I'm trying to export the dynamic dash plot to html. here is my code, when I click download as html after the plot appear, I was only able to download an empty plot, it came back nothing.
What went wrong? thank you
from dash import Dash, dcc, html,Input, Output, callback,dash_table
import plotly.express as px
from base64 import b64encode
import io
app = Dash(__name__)
buffer = io.StringIO()
df=tem1 # tem1 is my own dataset
html_bytes = buffer.getvalue().encode()
encoded = b64encode(html_bytes).decode()
app.layout = html.Div([
html.H4('Test Graph'),
dcc.Graph(id="graph"),
dcc.Checklist(
id="checklist",
options=['A','B','C'],
value=['A','B','C'],
inline=True),
html.A(
html.Button("Download as HTML"),
id="download",
href="data:text/html;base64," + encoded,
download="plotly_graph.html"
)
])
#app.callback(
Output("graph", "figure"),
Input("checklist", "value"))
def update_line_chart(Programs):
mask = df.Program.isin(Programs)
fig = px.line(df[mask],
x="Month", y="Mood", color='Group',text='Module')
return fig
#app.callback(
Output('download','n_clicks'),
[Input('graph','figure')])
def download_html(n):
return n.write_html(buffer)
app.run_server(debug=False,port=8051)
I referred to this post, but it couldn't solve my problem.
Your referred code is my question and I think you should fix it as below:
Add dcc.Download
Save fig to html first
Use dcc.send_file to download html file
I don't have your df so please refer below code:
from dash import Dash, dcc, html,Input, Output, callback,dash_table
import plotly.express as px
from base64 import b64encode
import io
app = Dash(__name__)
df = px.data.gapminder()
app.layout = html.Div([
html.H4('Test Graph'),
dcc.Graph(id="graph",figure=fig),
dcc.Checklist(
id="checklist",
options=['A','B','C'],
value=['A','B','C'],
inline=True),
html.A(
html.Button("Download as HTML"),
id="download"
),
dcc.Download(id='download_1')
])
#app.callback(
Output("graph", "figure"),
Input("checklist", "value"))
def update_line_chart(Programs):
fig = px.scatter(df.query("year==2007"), x="gdpPercap", y="lifeExp",
size="pop", color="continent",
hover_name="country", log_x=True, size_max=60)
fig.write_html("plotly_graph.html")
return fig
#app.callback(
Output('download_1','data'),
Input('download','n_clicks'),prevent_initial_call=True)
def download_html(n):
return dcc.send_file("plotly_graph.html")
app.run_server(debug=False,port=8051)
Hope this help
Related
I want to update my DataFrame that feeds my graphs in realtime. In all the tutorials I have found, the DataFrame is created before creating the app layout. I want to take the input from the input component with the username_input ID and use that in the get_dataFrame function to create my initial DataFrame which will create the figure which will be used in the graph component.
app = Dash(__name__)
df = get_dataFrame(username_input)
fig = px.line(df, x='end', y="user",color="class")
app.layout = html.Div(children=[
dcc.Input(
id="username_input",
placeholder="username",
type='text'
),
dcc.Graph(
id='example-graph',
figure=fig
),
])
I don't fully understand how to structure the code so that this is possible. In essence I want a user input first and then after the user input all the dash data updates to reflect the new input. Any ideas?
Move your dataframe and figure creation into your callback, then return a new figure after the user's input comes in. Working example:
from dash import Dash, dcc, html, Input, Output, no_update
import pandas as pd
import plotly.express as px
import numpy as np
app = Dash(__name__)
def get_dataFrame(username_input):
data = np.random.rand(10) * len(username_input)
return pd.DataFrame({"end": [*range(10)], "user": data, "class": ["red"] * 10})
fig = px.line()
app.layout = html.Div(
children=[
dcc.Input(id="username_input", placeholder="username", type="text"),
dcc.Graph(id="example-graph", figure=fig),
]
)
#app.callback(
Output("example-graph", "figure"), Input("username_input", "value"),
)
def func(username_input: str):
if username_input:
df = get_dataFrame(username_input)
fig = px.line(df, x="end", y="user", color="class")
return fig
return no_update
if __name__ == "__main__":
app.run(debug=True)
I'm trying to set my Dash app to automatically pull the latest data from a .csv file used in the data frame with dcc.Interval. The error code isn't providing a detailed explanation and also doesn't always appear. I've tried this with both a button and a set 6 sec interval, but the result seems to be the same. The Dash app runs fine at first and refreshes fine a few times, then error starts occurring:
Callback error updating graph.figure
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import plotly.express as px
import plotly.graph_objects as go
import pandas as pd
app = dash.Dash(__name__)
server = app.server
df = pd.read_csv('example.csv', encoding="WINDOWS-1252")
app.layout = html.Div([
dcc.Graph(id='graph'),
dcc.Interval(
id='interval-component',
interval=1*6000,
n_intervals=0
)
])
#app.callback(
Output('graph','figure'),
[Input('interval-component', 'n_intervals')]
)
def update_df(n):
updated_df = pd.read_csv('example.csv', encoding="WINDOWS-1252")
fig = px.scatter(updated_df, x='Date', y='Deviation', height=800)
fig.update_layout(
yaxis_tickformat = '.0%',
)
fig.update_xaxes(
rangeslider_visible=True,
rangeselector=dict(
)
)
return fig
if __name__ == '__main__':
app.run_server(debug=True)
I think your issue must have something to do with your file specifically, because the following code based exactly off as you provide (with the exception of generation of random matching-df timeseries data), works perfectly updating with an interval of every 6 seconds:
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import plotly.express as px
import plotly.graph_objects as go
import pandas as pd
import numpy as np
np.random.seed(2019)
def get_random_deviation_ts_df(N=100):
rng = pd.date_range("2019-01-01", freq="D", periods=N)
df = pd.DataFrame(np.random.rand(N, 1), columns=["Deviation"], index=rng)
df["Date"] = df.index
return df
app = dash.Dash(__name__)
server = app.server
# df = pd.read_csv('example.csv', encoding="WINDOWS-1252")
app.layout = html.Div(
[
dcc.Graph(id="graph"),
dcc.Interval(
id="interval-component", interval=1 * 6000, n_intervals=0
),
]
)
#app.callback(
Output("graph", "figure"), [Input("interval-component", "n_intervals")]
)
def update_df(n):
updated_df = (
get_random_deviation_ts_df()
) # pd.read_csv('example.csv', encoding="WINDOWS-1252")
fig = px.scatter(updated_df, x="Date", y="Deviation", height=800)
fig.update_layout(yaxis_tickformat=".0%",)
fig.update_xaxes(rangeslider_visible=True, rangeselector=dict())
return fig
if __name__ == "__main__":
app.run_server(debug=True)
I recently wrote a dash program
it is refreshing number of records and refreshes or redraws the fig
the problem is when I do filter over 1 or multiple legends it won't show any of the points
but when you hover over invisible points it shows the data of the point
my code:
from threading import Event
import dash
from dash import dcc, Input, Output
from dash import html
from dash.dcc.Interval import Interval
import plotly.express as px
import pandas as pd
import sqlalchemy
app = dash.Dash(__name__)
# assume you have a "long-form" data frame
# see https://plotly.com/python/px-arguments/ for more options
connection = sqlalchemy.create_engine('mysql+pymysql://*:*#localhost:*')
df = pd.read_sql_table('rawdata_clean', connection)
fig = px.scatter(df, x="Size", y="Price", color="Neighbourhood_Per")
index = df.index
app.layout = html.Div(children=[
html.H1(id='Numberofrecords', children= len(index)),
dcc.Interval(id='up-Numberofrecords', interval=3000, n_intervals=0),
html.Div(children='''
Dash: A web application framework for Python.
'''),
dcc.Graph(
id='grph',
animate=True
),
dcc.Interval(id='up-graph', interval=3000, n_intervals=0)
])
#app.callback(Output('grph', 'figure'),
Input('up-graph', 'n_intervals'))
def update_graph (n):
df = pd.read_sql_table('rawdata_clean', connection)
fig = px.scatter(df, x="Size", y="Price", color="Neighbourhood_Per")
return fig
#app.callback(Output('Numberofrecords', 'children'),
Input('up-Numberofrecords', 'n_intervals'))
def up_Numberofrecords (n):
df = pd.read_sql_table('rawdata_clean', connection)
index = df.index
print('up_Numberofrecords')
return len(index)
if __name__ == '__main__':
app.run_server(debug=True, port=9876)
is there any problems with this code?
i'm new to dash and plotly :D
the problem was :
animate=True
IDK what this code does but by deleting it, it get to work
i changed the following code from using ".png" to ".pkl". but this doesn't work
import plotly.express as px
import joblib
#generate example pkl
fig = px.scatter(x=range(10), y=range(10))
joblib.dump(fig, "img_dash/figure.pkl")
#%%
import dash
import dash_core_components as dcc
import dash_html_components as html
import flask
import glob
import os
image_directory = 'img_dash/'
list_of_images = [os.path.basename(x) for x in glob.glob('{}*.pkl'.format(image_directory))]
static_image_route = '/static/'
app = dash.Dash()
app.layout = html.Div([
dcc.Dropdown(
id='image-dropdown',
options=[{'label': i, 'value': i} for i in list_of_images],
value=list_of_images[0]
),
html.Img(id='image')
])
#app.callback(
dash.dependencies.Output('image', 'src'),
[dash.dependencies.Input('image-dropdown', 'value')])
def update_image_src(value):
return static_image_route + value
#app.server.route('{}<image_path>.pkl'.format(static_image_route))
def serve_image(image_path):
image_name = '{}.pkl'.format(image_path)
if image_name not in list_of_images:
raise Exception('"{}" is excluded from the allowed static files'.format(image_path))
return flask.send_from_directory(image_directory, image_name)
if __name__ == '__main__':
app.run_server(debug=False)
i expect to show the .pkl files in the dashboard with hover-function. may other formats also possible! i was not able to check this.
I recommend you to use a Graph component here instead of an Img component since you want to display these figures dynamically.
Since each pkl file already stores a Figure you can just dynamically load these files using joblib in your callback based on the dropdown value.
Example based on your code:
# Example figures for demo purposes
fig1 = px.scatter(x=range(10), y=range(10))
fig2 = px.scatter(x=range(15), y=range(15))
fig3 = px.scatter(x=range(20), y=range(20))
joblib.dump(fig1, "img_dash/figure1.pkl")
joblib.dump(fig2, "img_dash/figure2.pkl")
joblib.dump(fig3, "img_dash/figure3.pkl")
# ...
image_directory = "img_dash/"
list_of_images = [
os.path.basename(x) for x in glob.glob("{}*.pkl".format(image_directory))
]
app = dash.Dash()
app.layout = html.Div(
[
dcc.Dropdown(
id="image-dropdown",
options=[{"label": i, "value": i} for i in list_of_images],
value=list_of_images[0],
),
dcc.Graph(id="graph"),
]
)
#app.callback(
dash.dependencies.Output("graph", "figure"),
[dash.dependencies.Input("image-dropdown", "value")],
)
def update_graph(file):
return joblib.load(os.path.join(image_directory, file))
if __name__ == "__main__":
app.run_server(debug=False)
Is it possible to have a text field at the bottom of a graph in dash that displays the text for the point they are on (showing hover data as plain text). So the text box will be able to make changes when users hover over a certain point. I have defined a dcc.Graph component and the app layout but am not sure how to define the callback function for the hoverdata.
I have used the below code to define dcc.Graph and app.layout
fig = go.Figure(data=plot_data, layout=plot_layout)
app.layout = html.Div([
dcc.Graph(figure=fig),
html.Div([
dcc.Markdown(id='mpg-metrics')
],style={'width':'20%','display':'inline-block'})
])
Any help with the callback will be great. thanks in advance
Yes, that's very possible! Since you haven't provided a complete description of your setup, I've put together a minimal example that draws on elements from dash.plotly.com/interactive-graphing and https://community.plotly.com/: Use Hover Trace As Input for Callback that among other things describes the use of hover data in callbacks. The code snippet below will produce the following app for JupyterDash. If you'd like to run a standard dash app, just rewrite it following these steps.
The solution I've put together should do exactly what you're aiming for. Every time you hover over a point on one of the lines in the figure in the dcc.Graph component, a set of details about the trace is displayed in the html.Pre component under it, such as x and y values. Try it out and let me know how it works out for you!
App 1:
If you'd like to retrieve only certain elements of the output, you can subset the output like this:
json.dumps({'Date:':hoverData['points'][0]['x'],
'Value:':hoverData['points'][0]['y']}, indent = 2)
App 2:
Complete code for JupyterDash, App1
import json
from textwrap import dedent as d
import pandas as pd
import plotly.graph_objects as go
import numpy as np
import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.express as px
from dash.dependencies import Input, Output
from jupyter_dash import JupyterDash
# app info
app = JupyterDash(__name__)
styles = {
'pre': {
'border': 'thin lightgrey solid',
'overflowX': 'scroll'
}
}
# data and basic figure
x = np.arange(20)+10
fig = go.Figure(data=go.Scatter(x=x, y=x**2, mode = 'lines+markers'))
fig.add_traces(go.Scatter(x=x, y=x**2.2, mode = 'lines+markers'))
app.layout = html.Div([
dcc.Graph(
id='basic-interactions',
figure=fig,
),
html.Div(className='row', children=[
html.Div([
dcc.Markdown(d("""
Click on points in the graph.
""")),
html.Pre(id='hover-data', style=styles['pre']),
], className='three columns'),
])
])
#app.callback(
Output('hover-data', 'children'),
[Input('basic-interactions', 'hoverData')])
def display_hover_data(hoverData):
return json.dumps(hoverData, indent=2)
app.run_server(mode='external', port = 8070, dev_tools_ui=True,
dev_tools_hot_reload =True, threaded=True)
Complete code for JupyterDash, App2
import json
from textwrap import dedent as d
import pandas as pd
import plotly.graph_objects as go
import numpy as np
import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.express as px
from dash.dependencies import Input, Output
from jupyter_dash import JupyterDash
# app info
app = JupyterDash(__name__)
styles = {
'pre': {
'border': 'thin lightgrey solid',
'overflowX': 'scroll'
}
}
# data and basic figure
y = np.arange(100)+10
x = pd.date_range(start='1/1/2021', periods=len(y))
fig = go.Figure(data=go.Scatter(x=x, y=y**2, mode = 'lines+markers'))
fig.add_traces(go.Scatter(x=x, y=y**2.2, mode = 'lines+markers'))
app.layout = html.Div([
dcc.Graph(
id='basic-interactions',
figure=fig,
),
html.Div(className='row', children=[
html.Div([
dcc.Markdown(d("""
Click on points in the graph.
""")),
html.Pre(id='hover-data', style=styles['pre']),
], className='three columns'),
])
])
#app.callback(
Output('hover-data', 'children'),
[Input('basic-interactions', 'hoverData')])
def display_hover_data(hoverData):
try:
return json.dumps({'Date:':hoverData['points'][0]['x'],
'Value:':hoverData['points'][0]['y']}, indent = 2)
except:
return None
app.run_server(mode='external', port = 8070, dev_tools_ui=True,
dev_tools_hot_reload =True, threaded=True)