1

I am working on some plotly image processing for my work. I have been using matplotlib but need something more interactive, so I switched to dash and plotly. My goal is for people on my team to be able to draw a shape around certain parts of an image and return pixel values.

I am using this documentation and want a similar result: https://dash.plotly.com/annotations ; specifically "Draw a path to show the histogram of the ROI"

Code:

    import numpy as np
    import plotly.express as px
    
    from dash import Dash
    from dash.dependencies import Input, Output
    
    import dash_core_components as dcc
    import dash_html_components as html
    
    from skimage import data, draw #yes necessary
    from scipy import ndimage 
    
    import os, glob
    from skimage import io
    
    imagePath = os.path.join('.','examples')
    filename = glob.glob(os.path.join(imagePath,'IMG_0650_6.tif'))[0]
    moon = io.imread(filename)
    
    #imagePath = os.path.join('.','examples')
    #imageName = glob.glob(os.path.join(imagePath,'IMG_0650_6.tif'))[0]
    
    def path_to_indices(path):
        """From SVG path to numpy array of coordinates, each row being a (row, col) point
        """
        indices_str = [
            el.replace("M", "").replace("Z", "").split(",") for el in path.split("L")
        ]
        return np.rint(np.array(indices_str, dtype=float)).astype(np.int)
    
    def path_to_mask(path, shape):
        """From SVG path to a boolean array where all pixels enclosed by the path
        are True, and the other pixels are False.
        """
        cols, rows = path_to_indices(path).T
        rr, cc = draw.polygon(rows, cols)
        mask = np.zeros(shape, dtype=np.bool)
        mask[rr, cc] = True
        mask = ndimage.binary_fill_holes(mask)
        return mask

img = data.moon()

#print(img)
#print(type(img))

fig = px.imshow(img, binary_string=True)
fig.update_layout(dragmode="drawclosedpath")

fig_hist = px.histogram(img.ravel())

app = Dash(__name__)
app.layout = html.Div(
    [
        html.H3("Draw a path to show the histogram of the ROI"),
        html.Div(
            [dcc.Graph(id="graph-camera", figure=fig),],
            style={"width": "60%", "display": "inline-block", "padding": "0 0"},
        ),
        html.Div(
            [dcc.Graph(id="graph-histogram", figure=fig_hist),],
            style={"width": "40%", "display": "inline-block", "padding": "0 0"},
        ),
    ]
)

@app.callback(
    Output("graph-histogram", "figure"),
    Input("graph-camera", "relayoutData"),
    prevent_initial_call=True,
)
def on_new_annotation(relayout_data):
    if "shapes" in relayout_data:
        last_shape = relayout_data["shapes"][-1]
        mask = path_to_mask(last_shape["path"], img.shape)
        return px.histogram(img[mask])
    else:
        return dash.no_update

if __name__ == "__main__":
    app.run_server(debug=True)

This returns the following error:

Dash is running on http://127.0.0.1:8050/

  • Serving Flask app "main" (lazy loading)
  • Environment: production WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
  • Debug mode: on

Traceback:

Traceback (most recent call last):
  File "/Users/anthea/opt/anaconda3/lib/python3.9/site-packages/ipykernel_launcher.py", line 16, in <module>
    app.launch_new_instance()
  File "/Users/anthea/opt/anaconda3/lib/python3.9/site-packages/traitlets/config/application.py", line 845, in launch_instance
    app.initialize(argv)
  File "/Users/anthea/opt/anaconda3/lib/python3.9/site-packages/traitlets/config/application.py", line 88, in inner
    return method(app, *args, **kwargs)
  File "/Users/anthea/opt/anaconda3/lib/python3.9/site-packages/ipykernel/kernelapp.py", line 632, in initialize
    self.init_sockets()
  File "/Users/anthea/opt/anaconda3/lib/python3.9/site-packages/ipykernel/kernelapp.py", line 282, in init_sockets
    self.shell_port = self._bind_socket(self.shell_socket, self.shell_port)
  File "/Users/anthea/opt/anaconda3/lib/python3.9/site-packages/ipykernel/kernelapp.py", line 229, in _bind_socket
    return self._try_bind_socket(s, port)
  File "/Users/anthea/opt/anaconda3/lib/python3.9/site-packages/ipykernel/kernelapp.py", line 205, in _try_bind_socket
    s.bind("tcp://%s:%i" % (self.ip, port))
  File "/Users/anthea/opt/anaconda3/lib/python3.9/site-packages/zmq/sugar/socket.py", line 208, in bind
    super().bind(addr)
  File "zmq/backend/cython/socket.pyx", line 540, in zmq.backend.cython.socket.Socket.bind
  File "zmq/backend/cython/checkrc.pxd", line 28, in zmq.backend.cython.checkrc._check_rc
zmq.error.ZMQError: Address already in use

Solution Attempts:

I've consulted similar issues on here and tried reassigning 8050 to 1337, which was ineffective.

bad_coder
  • 11,289
  • 20
  • 44
  • 72
argo
  • 19
  • 1
  • 3
  • This question has great answers [here](https://stackoverflow.com/questions/51025893/flask-at-first-run-do-not-use-the-development-server-in-a-production-environmen). – Jakob Mar 28 '23 at 07:46

2 Answers2

2

I had the same problem and no amount of searching gave me an answer that solved my problem.

When I changed my code to this:

if __name__ == "__main__":
    app.run_server(debug=False)

It ran fine.

winkydink
  • 21
  • 1
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Apr 26 '22 at 18:45
  • 1
    Little bot, why is my answer less clear than the one above? Hmm? – winkydink Jun 08 '22 at 14:37
  • Setting `debug=False` doesn't solve the underlying problem. It only hides it. The warning indicates that the default Flask server is not intended for production, since it's not particular secure nor stable. What you want to use is a production server such as Gunicorn, Waitress or uWSGI as indicated in [this](https://stackoverflow.com/questions/51025893/flask-at-first-run-do-not-use-the-development-server-in-a-production-environmen) thread. – Jakob Mar 28 '23 at 07:51
0

when I had the same error I just tried to shutdown the other notebooks which are using the same Address 'http://127.0.0.1:8050/'

Other solution also worked for me, I changed the default port parameter

if __name__ == '__main__':  
    app.run_server(port=8051)