21

Is it possible to show a simple matplotlib plot (the kind usually generated by plt.show()) in plotly's Dash framework? Or just plotly-like graphs with plotly's Scatters and Data traces?

Specifically I guess I need a different component than Graph (see below) and a way to return the simple plot in the update_figure function.

Example:

import dash
import dash_core_components as dcc
import dash_html_components as html
import numpy as np
import matplotlib.pyplot as plt

app = dash.Dash()

app.layout = html.Div(children=[
    html.H1(children='Hello Dash'),

    dcc.Slider(
        id='n_points',
        min=10,
        max=100,
        step=1,
        value=50,
    ),

    dcc.Graph(id='example') # or something other than Graph?...
])

@app.callback(
    dash.dependencies.Output('example', 'figure'),
    [dash.dependencies.Input('n_points', 'value')]
)

def update_figure(n_points):
    #create some matplotlib graph
    x = np.random.rand(n_points)
    y = np.random.rand(n_points)
    plt.scatter(x, y)
    # plt.show()
    return None # return what, I don't know exactly, `plt`?

if __name__ == '__main__':
    app.run_server(debug=True)
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Giora Simchoni
  • 3,487
  • 3
  • 34
  • 72
  • 1
    Idea: handle the matplotlib plot as a normal image and set it as a background image for a plotly graph – Nils Jun 24 '18 at 19:23
  • The answer to your question is given in this question - https://stackoverflow.com/questions/65960506/plotly-dash-plotting-networkx-in-python – Sky_7 Jun 21 '22 at 16:05

3 Answers3

18

Refer to https://plot.ly/matplotlib/modifying-a-matplotlib-figure/ . There is a mpl_to_plotly function in plotly.tools library that will return a plotly figure(which can then be returned to Graph's figure attribute) from matplotlib figure.

Edit: Just noticed you asked this a while back. Maybe the above is a new feature but its the cleanest way.

Andreus
  • 2,437
  • 14
  • 22
Haskar P
  • 420
  • 4
  • 9
15

If you don't want an interactive plot, you can return a static one (found from this help)


import io
import base64

...
    
app.layout = html.Div(children=[
    ...,

    html.Img(id='example') # img element
])

@app.callback(
    dash.dependencies.Output('example', 'src'), # src attribute
    [dash.dependencies.Input('n_points', 'value')]
)
def update_figure(n_points):
    #create some matplotlib graph
    x = np.random.rand(n_points)
    y = np.random.rand(n_points)
    buf = io.BytesIO() # in-memory files
    plt.scatter(x, y)
    plt.savefig(buf, format = "png")
    plt.close()
    data = base64.b64encode(buf.getbuffer()).decode("utf8") # encode to html elements
    buf.close()
    return "data:image/png;base64,{}".format(data)
simplyPTA
  • 343
  • 4
  • 11
  • When I took this approach, I was perpetually able to reaccess images. Thus, the RAM built during deployment until crashing. Can anyone advise? – rictuar Dec 16 '22 at 02:36
  • sr i forgot to close the stream : `buf.close()` just before `return` – simplyPTA Dec 19 '22 at 12:38
2
UserWarning: Starting a Matplotlib GUI outside of the main thread will likely fail

in my case it works, despite the warning message