简体   繁体   中英

Figure is not being saved in plotly-dash out of a function. How do I fix this?

I have a function that takes a matplotlib plot and turns it into a plotly plot using tls.matplotlib_to_pyplot. In the end I named it plotly_fig. Now I'm trying to add sliders to a dash webapp. But when I compile it, I get an error saying plotly_fig is not defined. The following is some sample code that recreates the error.

import dash
import dash_core_components as dcc
import dash_html_components as html
import numpy as np
from numpy.linalg import matrix_power
import matplotlib.pyplot as plt
import plotly.tools as tls
from mpl_toolkits.mplot3d import Axes3D
from dash.dependencies import Input, Output
app = dash.Dash()
#begin with the knobs
app.layout = html.Div([
   dcc.Graph(
       id = 'graph',
       figure = plotly_fig),

   html.Label('Config L'), ## this is the knob for the length
   dcc.Slider(
       id = 'l',
       min = 5,
       max = 10,
       marks = {i: 'Label ={}'.format(i) if i == 1 else str(i) for i in range(5,10)},
       value = L,
   ),

   html.Label('Config n'), ##knob for the n-gon
   dcc.Slider(
       id = 'n',
       min = 0,
       max = 10,
       marks = {i: 'Label ={}'.format(i) if i == 1 else str(i) for i in range(1,10)},
       value = n,
   ),

   html.Label('Config N'),  ##knob for the number of n-gons outside initial
   dcc.Slider(
       id = 'N',
       min = 0,
       max = 10,
       marks = {i: 'Label ={}'.format(i) if i == 1 else str(i) for i in range(1,10)},
       value = N,
   ),

   html.Label('Config r'),  ##knob for r only works on integers for now
   dcc.Slider(
       id = 'r',
       min = 0,
       max = 2,
       marks = {i: 'Label ={}'.format(i) if i == 1 else str(i) for i in    range(1,2)},
       value = r,
   ),

   html.Label('Config d'), ##knoc for the depth of the dip
   dcc.Slider(
       id = 'd',
       min = 0,
       max = 2,
       marks = {i: 'Label ={}'.format(i) if i == 1 else str(i) for i in range(1,2)},
       value = d,
)
],
style = {'columnCount': 1})
@app.callback(
   dash.dependencies.Output('graph', 'figure'),
   [dash.dependencies.Input('l', 'value'),
   dash.dependencies.Input('n', 'value'),
   dash.dependencies.Input('N', 'value'),
   dash.dependencies.Input('r', 'value'),
   dash.dependencies.Input('d', 'value')])

def output(L,n,N,r,d):
    x = np.linspace(np.pi, L*n*N*r*d*np.pi, 1000)
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.plot(x, sinx)
    plotly_fig = tls.mpl_to_plotly(mpl_fig)
    return{plotly_fig}
if __name__=='__main__':
    app.run_server(debug = True)

What am I doing wrong?

The problem is that the variable plotly_fig is not even declared when you are trying to use it in the Graph's figure field. It is just declared locally in the callback.

It is not required to set the figure property of the Graph explicitly, It will be automatically mapped during the callback, so you can directly do it like this,

#your code here

app = dash.Dash()
#begin with the knobs
app.layout = html.Div([
   dcc.Graph(
       id = 'graph'),  # ==> here you can remove the figure as it will be automatically set during the callback.

    #your code here
],

style = {'columnCount': 1})

@app.callback(
   dash.dependencies.Output('graph', 'figure'), #here figure represents the field
   [dash.dependencies.Input('l', 'value'),
   dash.dependencies.Input('n', 'value'),
   dash.dependencies.Input('N', 'value'),
   dash.dependencies.Input('r', 'value'),
   dash.dependencies.Input('d', 'value')])

def output(L,n,N,r,d):
    #your code here
    plotly_fig = tls.mpl_to_plotly(mpl_fig)
    return{plotly_fig}

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

In the above snippet case, the value property of the Slider is the input of the app and the output of the app is the figure property of the Graph. Whenever the value of the Slider changes, Dash calls the callback function output with the new input values. The function filters the dataframe with this new value, constructs a figure object, and returns it to the Dash application.

Meanwhile, if you want a default value to be set even before the callback function is called you can declare plotly_fig as a global variable like this,

#your code here
plotly_fig = None # declare the default figure here

app = dash.Dash()
#begin with the knobs
app.layout = html.Div([
   dcc.Graph(
       id = 'graph', figure = plotly_fig),

    #your code here
],

style = {'columnCount': 1})

@app.callback(
   dash.dependencies.Output('graph', 'figure'),
   [dash.dependencies.Input('l', 'value'),
   dash.dependencies.Input('n', 'value'),
   dash.dependencies.Input('N', 'value'),
   dash.dependencies.Input('r', 'value'),
   dash.dependencies.Input('d', 'value')])

def output(L,n,N,r,d):
    #your code here
    plotly_fig = tls.mpl_to_plotly(mpl_fig)
    return{plotly_fig}

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

For more information refer the official documentation page which has a similar example,

https://dash.plot.ly/getting-started-part-2

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM