Displaying an image with dcc.Graph in Plotly-Dash - python

I am trying to display an image with with dcc.Graph component in Plotly-Dash so I get its nice toolbars and built-in UI. However I am getting a bunch of errors. This is what my procedure is:
Upload JPG image.
Load image using np.array(Image.open(..)).
Convert to figure with px.imshow().
Pass this through dcc.Graph component and try to display it on page.
Below is my code:
import datetime
import dash
from dash.dependencies import Input, Output, State
from dash import dcc
from dash import html
import numpy as np
from PIL import Image
import plotly.express as px
app = dash.Dash(__name__)
app.layout = html.Div([
html.Div(
children=[
dcc.Upload(
id='upload-image',
children=html.Div([
'Drag and Drop or ',
html.A('Select Files')
]),
# Allow multiple files to be uploaded
multiple=True)]),
html.Div(
children=[
html.Div(id='output-image-upload'),
])
])
def parse_contents(contents, filename, date):
img = np.array(Image.open(contents))
fig = px.imshow(img)
return html.Div([
html.H5(filename),
html.H6(datetime.datetime.fromtimestamp(date)),
dcc.Graph(figure=fig)
])
#app.callback(Output('output-image-upload', 'children'),
Input('upload-image', 'contents'),
State('upload-image', 'filename'),
State('upload-image', 'last_modified'))
def update_output(list_of_contents, list_of_names, list_of_dates):
if list_of_contents is not None:
children = [
parse_contents(c, n, d) for c, n, d in
zip(list_of_contents, list_of_names, list_of_dates)]
return children
if __name__ == '__main__':
app.run_server(debug=True)
I get these errors below:
Callback error updating output-image-upload.children
Traceback (most recent call last):
File "C:\Users\...\test.py", line 48, in update_output
children = [
File "C:\Users\...\test.py", line 49, in <listcomp>
parse_contents(c, n, d) for c, n, d in
File "C:\Users\...\test.py", line 34, in parse_contents
img = np.array(Image.open(contents))
File "C:\Users\...\AppData\Local\Programs\Python\Python38\Lib\site-packages\PIL\Image.py", line 2904, in open
fp = builtins.open(filename, "rb")
FileNotFoundError: [Errno 2] No such file or directory: 'data:image/jpeg;base64,/9j/2wBDAAYEBQY...

As explained in this answer you need to remove data:image/png;base64, from the image string. If you update your parse_contents function as follows your app should work:
def parse_contents(contents, filename, date):
# Remove 'data:image/png;base64' from the image string,
# see https://stackoverflow.com/a/26079673/11989081
data = contents.replace('data:image/png;base64,', '')
img = Image.open(io.BytesIO(base64.b64decode(data)))
# Convert the image string to numpy array and create a
# Plotly figure, see https://plotly.com/python/imshow/
fig = px.imshow(np.array(img))
# Hide the axes and the tooltips
fig.update_layout(
plot_bgcolor='white',
paper_bgcolor='white',
margin=dict(t=20, b=0, l=0, r=0),
xaxis=dict(
showgrid=False,
showticklabels=False,
linewidth=0
),
yaxis=dict(
showgrid=False,
showticklabels=False,
linewidth=0
),
hovermode=False
)
return html.Div([
html.H5(filename),
html.H6(datetime.datetime.fromtimestamp(date)),
dcc.Graph(
figure=fig,
config={'displayModeBar': True} # Always display the modebar
)
])
Full code:
import io
import base64
import datetime
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
import numpy as np
import plotly.express as px
from PIL import Image
app = dash.Dash(__name__)
app.layout = html.Div([
html.Div(
children=[
dcc.Upload(
id='upload-image',
children=html.Div(['Drag and Drop or ', html.A('Select Files')]),
multiple=True
)
]
),
html.Div(
children=[
html.Div(id='output-image-upload'),
]
)
])
def parse_contents(contents, filename, date):
# Remove 'data:image/png;base64' from the image string,
# see https://stackoverflow.com/a/26079673/11989081
data = contents.replace('data:image/png;base64,', '')
img = Image.open(io.BytesIO(base64.b64decode(data)))
# Convert the image string to numpy array and create a
# Plotly figure, see https://plotly.com/python/imshow/
fig = px.imshow(np.array(img))
# Hide the axes and the tooltips
fig.update_layout(
plot_bgcolor='white',
paper_bgcolor='white',
margin=dict(t=20, b=0, l=0, r=0),
xaxis=dict(
showgrid=False,
showticklabels=False,
linewidth=0
),
yaxis=dict(
showgrid=False,
showticklabels=False,
linewidth=0
),
hovermode=False
)
return html.Div([
html.H5(filename),
html.H6(datetime.datetime.fromtimestamp(date)),
dcc.Graph(
figure=fig,
config={'displayModeBar': True} # Always display the modebar
)
])
#app.callback(
Output('output-image-upload', 'children'),
[Input('upload-image', 'contents')],
[State('upload-image', 'filename'),
State('upload-image', 'last_modified')])
def update_output(list_of_contents, list_of_names, list_of_dates):
if list_of_contents is not None:
children = [
parse_contents(c, n, d) for c, n, d in
zip(list_of_contents, list_of_names, list_of_dates)
]
return children
if __name__ == '__main__':
app.run_server(debug=True, host='127.0.0.1')

Related

Multiple functions in Plotly Dash app call back?

I'm creating a fitness chart using Plotly Dash that allows a user to enter a weight, which saves the data to an excel file, and then the user can refresh the screen to update the graph. I've been able to do them seperately by only having one function under the app.callback section. How can I have both functions? I can make the graph OR I can collect the input and refresh, but not both. Here's a sample of the data I'm using.
And here's the MVP code I'm trying to use.
import openpyxl
import dash
from dash import html, dcc, Input, Output, State
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
app = dash.Dash(__name__)
app.layout = html.Div([
dcc.Input(id='weight', placeholder='Enter Your Weight', type='text'),
html.Button(id='submit-button', type='submit', children='Submit'),
html.A(html.Button('Refresh'), href='/'),
dcc.Graph(
id='chart')
])
#app.callback(Output('chart', 'figure'),
[Input('submit-button', 'n_clicks')],
[State('weight', 'value')],
)
def display_time_series(n_clicks, input_value):
xlsx = pd.read_excel('Weight Tracker.xlsx')
df = xlsx
fig = px.line(df, x="DATE", y="ACTUAL WEIGHT")
fig.add_trace(
go.Scatter(x=df['DATE'], y=df['HIGH ESTIMATE'], name="HIGH ESTIMATE", line=dict(color="green", dash="dash")),
secondary_y=False,
)
fig.add_trace(
go.Scatter(x=df['DATE'], y=df['LOW ESTIMATE'], name="LOW ESTIMATE", line=dict(color="red", dash="dash")),
secondary_y=False,
)
if n_clicks is not None:
wb = openpyxl.load_workbook('Weight Tracker.xlsx')
sheet = wb.active
# Finds the last open row in Column B or the 'Actual Weight' Column
last_empty_entry = max((b.row for b in sheet['B'] if b.value is not None)) + 1
c1 = sheet.cell(row=last_empty_entry, column=2)
c1.value = int(input_value)
wb.save("Weight Tracker.xlsx")
print("Excel has been saved.")
return fig
if __name__ == '__main__':
app.run_server(debug=True)
Here's the error I'm getting and the graph doesn't display and the input button doesn't do anything.
Cannot read properties of null (reading 'data')
at f.value (http://127.0.0.1:8050/_dash-component-suites/dash/dcc/async-graph.js:1:4493)
at f.value (http://127.0.0.1:8050/_dash-component-suites/dash/dcc/async-graph.js:1:9778)
at callComponentWillReceiveProps (http://127.0.0.1:8050/_dash-component-suites/dash/deps/react-dom#16.v2_3_1m1648990364.14.0.js:13111:16)
at updateClassInstance (http://127.0.0.1:8050/_dash-component-suites/dash/deps/react-dom#16.v2_3_1m1648990364.14.0.js:13313:9)
at updateClassComponent (http://127.0.0.1:8050/_dash-component-suites/dash/deps/react-dom#16.v2_3_1m1648990364.14.0.js:17242:22)
at beginWork (http://127.0.0.1:8050/_dash-component-suites/dash/deps/react-dom#16.v2_3_1m1648990364.14.0.js:18755:18)
at HTMLUnknownElement.callCallback (http://127.0.0.1:8050/_dash-component-suites/dash/deps/react-dom#16.v2_3_1m1648990364.14.0.js:182:16)
at Object.invokeGuardedCallbackDev (http://127.0.0.1:8050/_dash-component-suites/dash/deps/react-dom#16.v2_3_1m1648990364.14.0.js:231:18)
at invokeGuardedCallback (http://127.0.0.1:8050/_dash-component-suites/dash/deps/react-dom#16.v2_3_1m1648990364.14.0.js:286:33)
at beginWork$1 (http://127.0.0.1:8050/_dash-component-suites/dash/deps/react-dom#16.v2_3_1m1648990364.14.0.js:23338:9)
The main issue you're having is the callback is being called at initial start of program, so to fix this pass in prevent_initial_callbacks=True into dash app instance.
Then you need 2 separate inputs for each button and don't use an anchor for Refresh button it won't work.
import dash
from dash import html, dcc, Input, Output, State
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
import datetime as dt
app = dash.Dash(__name__, prevent_initial_callbacks=True)
app.layout = html.Div([
dcc.Input(id='weight', placeholder='Enter Your Weight', type='text'),
html.Button(id='submit-button', type='submit', children='Submit'),
html.Button('Refresh', id='refresh'),
dcc.Graph(id='chart'),
html.P(children='dummy', id='dummy', hidden=True)
])
#app.callback(Output('chart', 'figure'),
[Input('refresh', 'n_clicks')],
prevent_initial_callback=True,
)
def display_time_series(n_clicks):
if n_clicks is not None:
xlsx = pd.read_excel('Weight Tracker.xlsx')
df = xlsx
fig = px.line(df, x="DATE", y="ACTUAL WEIGHT")
fig.add_trace(
go.Scatter(x=df['DATE'], y=df['HIGH ESTIMATE'], name="HIGH ESTIMATE", line=dict(color="green", dash="dash")),
secondary_y=False,
)
fig.add_trace(
go.Scatter(x=df['DATE'], y=df['LOW ESTIMATE'], name="LOW ESTIMATE", line=dict(color="red", dash="dash")),
secondary_y=False,
)
return fig
#app.callback(Output('dummy', 'children'),
[Input('submit-button', 'n_clicks')],
[State('weight', 'value')],
prevent_initial_callback=True
)
def save_new_entry(n_clicks, input_value):
if n_clicks is not None:
wb = openpyxl.load_workbook('Weight Tracker.xlsx')
sheet = wb.active
# Finds the last open row in Column B or the 'Actual Weight' Column
last_empty_entry = max((b.row for b in sheet['B'] if b.value is not None)) + 1
c0 = sheet.cell(row=last_empty_entry, column=1)
c0.value = dt.datetime.now()
c1 = sheet.cell(row=last_empty_entry, column=2)
c1.value = int(input_value)
wb.save("Weight Tracker.xlsx")
print("Excel has been saved.")
if __name__ == '__main__':
app.run_server(debug=True)

How to capture the data of the drawn shapes by the mouse in Dash

So I have this simple python dash application in which I've laid out a graph and a button.
My goal is this: when I press the button, I want to retrieve the shapes that have been drawn.
import plotly.graph_objects as go
import dash
from dash import html, dcc, Input, Output, State
app = dash.Dash(__name__)
fig = go.Figure()
app.layout = html.Div([
dcc.Graph(id = "graph-pic", className="graph-pic", figure=fig, config={'modeBarButtonsToAdd':['drawrect', 'eraseshape']}),
html.Button("Shape count", id = "shape-count-button")
])
fig.add_shape(editable=True, x0=-1, x1=0, y0=2, y1=3, xref='x', yref='y')
#app.callback(
Output("graph-pic", "figure"),
Input("shape-count-button", "n_clicks")
)
def on_shape_count_button_pressed(n_clicks):
trigger_id = dash.callback_context.triggered_id
if trigger_id == "shape-count-button":
print("Shape count: " + str(len(fig.layout.shapes)))
print(fig.layout.shapes)
return dash.no_update
if __name__ == "__main__":
app.run_server()
When I press the button, it only prints the first shape that I've added through code... and NOT the ones that I've drawn on the graph with the draw rectangle tool.
Output:
Shape count: 1
(layout.Shape({
'editable': True, 'x0': -1, 'x1': 0, 'xref': 'x', 'y0': 2, 'y1': 3, 'yref': 'y'
}),)
Any hint would be appreciated!
You should use relayout_data to detect all the drawn shapes on the graph, and then you can parse the desired data as you would:
import dash
import json
import plotly.graph_objects as go
from dash import html, dcc, Input, Output, State
app = dash.Dash(__name__)
fig = go.Figure()
app.layout = html.Div([
dcc.Graph(id = "graph-pic", className="graph-pic", figure=fig, config={'modeBarButtonsToAdd':['drawrect', 'eraseshape']}),
html.Button("Shape count", id = "shape-count-button"),
html.Div(id="text")
])
fig.add_shape(editable=True, x0=-1, x1=0, y0=2, y1=3, xref='x', yref='y')
#app.callback(
Output("text", "children"),
Input("shape-count-button", "n_clicks"),
Input("graph-pic", "relayoutData"),
)
def on_shape_count_button_pressed(n_clicks, relayout_data):
trigger_id = dash.callback_context.triggered_id
if trigger_id == "shape-count-button":
text_lst = "Shape count: " + str(len(fig.layout.shapes))
text_lst += str(fig.layout.shapes)
if "shapes" in relayout_data:
text_lst += json.dumps(relayout_data["shapes"], indent=2)
return text_lst
return dash.no_update
if __name__ == "__main__":
app.run_server()
Output

How to update data from mySql for plotly dash

I’m trying to make a live updates from mySql database but graphs did not update with new data but Stop and Re-run script. I tried to find solutions or simple code but I couldn’t find it.
Below is my code:
import pandas as pd
import numpy as np
import plotly.express as px
import dash
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Input, Output
import dash_bootstrap_components as dbc
import plotly.graph_objects as go
from io import BytesIO
from wordcloud import WordCloud
import base64
import dash.dependencies as dd
import mysql.connector
db = mysql.connector.connect(
host="localhost",
user="root",
password="",
database="indeed_data_dump"
)
cur = db.cursor()
cur.execute("SELECT * FROM jobs")
data = pd.DataFrame(cur.fetchall())
db.close()
data.rename(columns = {1:'Url',2:'Job Link',3:'Title',4:'Company',5:'Rating',6:'Location',
7:'Posted',8:'Job Description',9:'Min Salary',10:'Max Salary'}, inplace = True)
data.to_dict()
data = data[data['Max Salary'].notnull()]
jobs_2 = data[['Title','Company','Rating','Location','Max Salary']]
jobs_2['Max Salary'] = jobs_2['Max Salary'].str.replace(',','')
jobs_2['Type'] = jobs_2['Max Salary'].str[-5:]
jobs_2['Type'] = jobs_2['Type'].str.replace(' ','')
jobs_2['Max Salary'] = jobs_2['Max Salary'].str.extract('(\d+)')
jobs_2 = jobs_2.dropna(subset=['Max Salary'])
jobs_2['Max Salary'] = jobs_2['Max Salary'].astype(int)
jobs_2['Max Salary'] = np.where((jobs_2['Type'] == "year"),(jobs_2['Max Salary']/12).round(decimals=0),jobs_2['Max Salary'])
jobs_2['Max Salary'] = np.where((jobs_2['Type'] == "week"),(jobs_2['Max Salary']*4).round(decimals=0),jobs_2['Max Salary'])
app = dash.Dash(__name__,external_stylesheets=[dbc.themes.LUX])
app.layout = html.Div([
dbc.Row([
dbc.Col([
dbc.Card([
dbc.CardBody([html.H5('Average salary on each location',className='text-center'), #marks=mark_values
dcc.Graph(id='sal_location',figure={},style={'height':500,'width':'auto'}),
])
])
],width={'size':12,"offset":0,'order':1},style={'padding-left' : 25,'padding-right' : 25}),
]),
html.Hr(),
dbc.Row([
dbc.Col([
dbc.Card([
dbc.CardBody([html.H5('Top 10 Job',className='text-center'), #marks=mark_values
dcc.Graph(id='sal_top10',figure={},style={'height':600,'width':'auto'}),
])
])
],width={'size':6,"offset":0,'order':1},style={'padding-left' : 25}),
dbc.Col([
dbc.Card([
dbc.CardBody([html.H5('Average salary on star',className='text-center'), #marks=mark_values
dcc.Graph(id='sal_star',figure={},style={'height':600,'width':'auto'}),
])
])
],width={'size':6,"offset":0,'order':1},style={'padding-right' : 25}),
]),
html.Hr(),
dbc.Row([
dbc.Col([html.H5('Drop Down',className='text-center'),
dcc.Dropdown(id='location_cd_2',placeholder="Please select location",
options=[{'label':x,'value':x} for x in data.sort_values('Location')['Location'].unique()],
value='Select',
multi=False,
disabled=False,
clearable=True,
searchable=True),
],width={'size':6,"offset":0,'order':1},style={'padding-left' : 25}),
]),
html.Hr(),
dbc.Row([
dbc.Col([
dbc.Card([
dbc.CardBody([html.H5('Job on each location',className='text-center'), #marks=mark_values
dcc.Graph(id='job_location_2',figure={},style={'height':600,'width':'auto'}),
])
])
],width={'size':12,"offset":0,'order':1},style={'padding-left' : 25,'padding-right' : 25}),
]),
dbc.Row([
dbc.Col([
dbc.Card([
dbc.CardBody([html.H5('Word Cloud',className='text-center'),
html.Img(id="image_wc"),
])
])
],width={'size':12,"offset":0,'order':1},style={'padding-left' : 25,'padding-right' : 25},className='text-center'),
]),
dcc.Interval(id='update', n_intervals = 0, interval=1000*5)
])
#app.callback(
Output('sal_location', 'figure'),
[Input('update', 'n_intervals')])
def update_graph(jobs_location):
global jobs
jobs = jobs_2.copy()
jobs_location = pd.pivot_table(jobs,values=['Max Salary',],index=['Location'],aggfunc=np.mean)
jobs_location = jobs_location.reset_index()
# Fig 1
fig_1 = go.Figure(data=[
go.Bar(x=jobs_location['Location'],
y=jobs_location['Max Salary'].round(decimals=2),
width=0.45,
text = jobs_location['Max Salary'].round(decimals=2),
textposition='inside',
marker_color='indianred')])
fig_1.update_layout(barmode='stack')
fig_1.update_traces(texttemplate='%{text:,}')
fig_1.update_layout(plot_bgcolor='rgba(0,0,0,0)')
fig_1.update_yaxes(showline=False,showgrid=False,dtick=5000,exponentformat="none",separatethousands=True)
return fig_1
#app.callback(
Output('sal_top10', 'figure'),
[Input('update', 'n_intervals')])
def update_graph_2(top_10):
global job_cloud
jobs['Rating'].fillna(0,inplace=True)
jobs_title = pd.pivot_table(jobs,values=['Max Salary',],index=['Title'],aggfunc=np.mean)
jobs_title = jobs_title.reset_index()
top_10 = jobs_title.sort_values(['Max Salary'], ascending=[False]).head(10)
top_10 = top_10.sort_values(['Max Salary'], ascending=[True])
job_cloud = jobs.groupby(["Title"])["Title"].count().reset_index(name="count")
# Fig 3
fig_3 = px.bar(top_10, x="Max Salary", y="Title", orientation='h')
fig_3.update_traces(marker_color='#E8788C')
fig_3.update_layout(plot_bgcolor='white',xaxis_title='',yaxis_title='')
fig_3.update_yaxes(showline=False,showgrid=False,exponentformat="none",separatethousands=True)
fig_3.update_xaxes(showline=False,showgrid=False,exponentformat="none",separatethousands=True)
return fig_3
#app.callback(
Output('sal_star', 'figure'),
[Input('update', 'n_intervals')])
def update_graph_3(jobs_rating):
jobs_rating = pd.pivot_table(jobs,values=['Max Salary',],index=['Rating'],aggfunc=np.mean)
jobs_rating = jobs_rating.reset_index()
fig_2 = go.Figure(data=[
go.Bar(x=jobs_rating['Rating'],
y=jobs_rating['Max Salary'].round(decimals=2),
width=0.45,
text = jobs_rating['Max Salary'].round(decimals=2),
textposition='inside',
marker_color='lightsalmon')])
fig_2.update_layout(barmode='stack')
fig_2.update_traces(texttemplate='%{text:,}')
fig_2.update_layout(plot_bgcolor='rgba(0,0,0,0)')
fig_2.update_yaxes(showline=False,showgrid=False,dtick=5000,exponentformat="none",separatethousands=True)
fig_2.update_xaxes(type='category')
return fig_2
#app.callback(Output('job_location_2', 'figure'),
[Input('location_cd_2', 'value'),
Input('update', 'n_intervals')])
def build_graph(location_code,dff_2):
if not location_code or 'Select' in location_code:
dff_2 = pd.pivot_table(jobs,values=['Max Salary',],index=['Location','Title'],aggfunc=np.mean).reset_index()
dff_2 = dff_2[(dff_2['Location']=='Kuala Lumpur')]
else:
dff_2 = pd.pivot_table(jobs,values=['Max Salary',],index=['Location','Title'],aggfunc=np.mean).reset_index()
dff_2 = dff_2[(dff_2['Location'] == location_code)]
fig_4 = go.Figure(data=[
go.Bar(x=dff_2['Title'],
y=dff_2['Max Salary'].round(decimals=2),
width=0.45,
text = dff_2['Max Salary'].round(decimals=2),
textposition='inside',
marker_color='lightsalmon')])
fig_4.update_layout(barmode='stack')
fig_4.update_traces(texttemplate='%{text:,}')
fig_4.update_layout(plot_bgcolor='rgba(0,0,0,0)')
fig_4.update_yaxes(showline=False,showgrid=False,dtick=20000,exponentformat="none",separatethousands=True)
fig_4.update_xaxes(type='category')
return fig_4
def plot_wordcloud(data):
d = {a: x for a, x in data.values}
wc = WordCloud(background_color='white', width=1080, height=360)
wc.fit_words(d)
return wc.to_image()
#app.callback(dd.Output('image_wc', 'src'), [dd.Input('image_wc', 'id')])
def make_image(b):
img = BytesIO()
plot_wordcloud(data=job_cloud).save(img, format='PNG')
return 'data:image/png;base64,{}'.format(base64.b64encode(img.getvalue()).decode())
if __name__ == "__main__":
app.run_server(debug=False,port=1215)
This code worked good with csv files but didn't update data from mySql.
What should I change for my code or could you give me a sample code? Thank you.

Graph is not being returned by Plotly Dash Callback

I'm doing some GIS analysis and got a bit flustered.
I need to create a interactive plotly dash app, where you have two multi dropdown dash core components that update values on a px.scatter_mapbox map. The DataFrame has the following "Filters"/Fields I need in the dropdowns: Race/Ethnicity and City. I'm stuck at this point:
Click on the Race Drop down (Multi) (works)
City Options are appropriately filled (works)
Map won't update-- just returns what you see below.
Here is my code:
import dash.dependencies
import plotly.express as px
import pandas as pd
from jupyter_dash import JupyterDash
import dash_core_components as dcc
from dash import html
from dash.dependencies import Input, Output
import plotly.graph_objects as go
px.set_mapbox_access_token(mapbox_access_token)
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = JupyterDash(__name__, external_stylesheets=external_stylesheets)
re_indicators = df["RE"].unique()
city_indicators = df["CITY"].unique()
app.layout = html.Div([
html.Div(children=[
html.Label('Race & Ethnicity'),
dcc.Dropdown( id = "re",
options=[{'label': i, 'value': i} for i in re_indicators],
value = ["White"],
multi = True
),
html.Label('City'),
dcc.Dropdown( id = "city",
options=[],
value = [],
multi = True
),
html.Div([
dcc.Graph(
id='my_map',
figure = {})
])
])])
#app.callback(
dash.dependencies.Output('city', 'options'),
dash.dependencies.Input('re', 'value')
)
def re_picker(choose_re):
if len(choose_re) > 0:
dff = df[df.RE.isin(choose_re)]
return [{'label': i, 'value': i} for i in (dff.CITY.unique())]
#app.callback(
dash.dependencies.Output('city', 'value'),
dash.dependencies.Input('city', 'options')
)
def set_city_value(available_options):
return [x['value'] for x in available_options]
#app.callback(
dash.dependencies.Output('my_map', 'figure'),
[dash.dependencies.Input('re', 'value'),
dash.dependencies.Input('city', 'value')]
)
def update_figure(selected_re, selected_city):
if len(selected_re) == 0:
return print("nope")
else:
df_filtered = dff[(dff['CITY'] == selected_city)]
fig = px.scatter_mapbox(df_filtered,
lat="Latitude",
lon="Longitude",
zoom=1)
return fig
# Run app and display result inline in the notebook
if __name__ == '__main__':
app.run_server(host = "127.0.0.1", port = "8888", mode= "inline", debug = False)
Ouput Photo
you have not provided any data, have generated some sample data
there are a number issues with your code. All actually generate obvious exceptions
scoping, dff is note scoped across all callbacks however you are assuming it is. Fixes are to only have df as global scope
list equality makes no sense. use isin()
better practice is to use raise dash.exceptions.PreventUpdate if conditions for callback are not met
solution
import dash.dependencies
import plotly.express as px
import pandas as pd
from jupyter_dash import JupyterDash
import dash_core_components as dcc
from dash import html
from dash.dependencies import Input, Output
import plotly.graph_objects as go
# px.set_mapbox_access_token(mapbox_access_token)
external_stylesheets = ["https://codepen.io/chriddyp/pen/bWLwgP.css"]
app = JupyterDash(__name__, external_stylesheets=external_stylesheets)
re_indicators = df["RE"].unique()
city_indicators = df["CITY"].unique()
app.layout = html.Div(
[
html.Div(
children=[
html.Label("Race & Ethnicity"),
dcc.Dropdown(
id="re",
options=[{"label": i, "value": i} for i in re_indicators],
value=["White"],
multi=True,
),
html.Label("City"),
dcc.Dropdown(id="city", options=[], value=[], multi=True),
html.Div([dcc.Graph(id="my_map", figure={})]),
]
)
]
)
#app.callback(
dash.dependencies.Output("city", "options"), dash.dependencies.Input("re", "value")
)
def re_picker(choose_re):
if len(choose_re) > 0:
dff = df[df.RE.isin(choose_re)]
else:
raise dash.exceptions.PreventUpdate
return [{"label": i, "value": i} for i in (dff.CITY.unique())]
#app.callback(
dash.dependencies.Output("city", "value"),
dash.dependencies.Input("city", "options"),
)
def set_city_value(available_options):
return [x["value"] for x in available_options]
#app.callback(
dash.dependencies.Output("my_map", "figure"),
[dash.dependencies.Input("re", "value"), dash.dependencies.Input("city", "value")],
)
def update_figure(selected_re, selected_city):
if not selected_re or not selected_city or len(selected_re)==0 or len(selected_city)==0:
raise dash.exceptions.PreventUpdate
# df_filtered = dff[(dff['CITY'] == selected_city)] # this is out of scope!!!
df_filtered = df.loc[df["CITY"].isin(selected_city) & df["RE"].isin(selected_re)]
fig = px.scatter_mapbox(df_filtered, lat="Latitude", lon="Longitude", zoom=1).update_layout(mapbox={"style":"carto-positron"})
return fig
# Run app and display result inline in the notebook
if __name__ == "__main__":
app.run_server(host="127.0.0.1", port="8888", mode="inline", debug=False)
data
import io
import pandas as pd
df = pd.read_csv(io.StringIO("""RE,Longitude,Latitude,CITY
Black,-120.99774156574261,37.559165406261,Stanislaus
Pacific,-120.65111562736087,38.446389516422855,Amador
Pacific,-119.81550247702623,36.07536100517565,Kings
Black,-121.95120685287338,37.92342159137978,Contra Costa
Native,-118.26100262413676,34.197992401614535,Los Angeles
Asian,-120.7249673888429,41.58984787469562,Modoc
White,-121.95120685287338,37.92342159137978,Contra Costa
Hispanic,-123.9578138104391,41.74495737627584,Del Norte
Black,-122.39220680431815,39.59840477506362,Glenn
Pacific,-122.04052155027398,40.7637665910163,Shasta
Black,-120.71766862423333,37.19185694553567,Merced
Native,-121.69484223375345,39.03452277403378,Sutter
Black,-115.9938588669452,33.743676039870444,Riverside
Black,-119.90551726806129,37.58152187924647,Mariposa
Pacific,-117.41078970333236,36.51112681410214,Inyo
Black,-119.76264585146096,37.218035870388235,Madera
Pacific,-123.43155392039253,39.433623844726505,Mendocino
Black,-121.34428014540734,38.4493728777556,Sacramento
White,-120.7249673888429,41.58984787469562,Modoc
Pacific,-119.64932124370894,36.758179506828185,Fresno
White,-119.81550247702623,36.07536100517565,Kings
Native,-121.91788591709779,37.65054956250571,Alameda
Asian,-121.07499558470187,36.6057059207284,San Benito
Native,-120.52464692805631,38.778737966889466,El Dorado
Pacific,-120.55413218695809,38.204606401638536,Calaveras
Hispanic,-116.17845588321354,34.84143467938159,San Bernardino
Black,-122.23388486629841,40.12573617303074,Tehama
White,-121.90162044594241,38.68664649354098,Yolo
Native,-120.45219691432906,35.38741552944272,San Luis Obispo
Pacific,-119.82065303166894,38.59725063024503,Alpine"""))

How to Adjust the size of graphs in Dash with Python?

The objective is to maximise the pie chart view at each place card. As can be seen in the figure below, the pie chart is small and not properly fit the window of each place card.
OP1 shed some workaround, but I am unable to reproduce it correctly.
Appreciate if someone can shed some light on how to address this problem.
The code to reproduce the above figure is:
import dash
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Input, Output
import dash_bootstrap_components as dbc
import plotly.graph_objs as go
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
app.config.suppress_callback_exceptions = True
labels = [['monkeys', 'elephants'],
['birds', 'dinosaurs'],
['unicorns', 'giraffes']]
values = [[50, 40],
[100, 10],
[100, 20]]
data = []
for label, value in zip(labels, values):
data.append(html.Div([dcc.Graph(figure={'data': [go.Pie(labels=label,
values=value,
hoverinfo='label+value+percent', textinfo='value'
)]})
], className='col-sm-4'))
labels_second = [['Human', 'Animal']]
values_second = [[40, 60]]
data_second = []
for label, value in zip(labels_second, values_second):
data_second.append(html.Div([dcc.Graph(figure={'data': [go.Pie(labels=label,
values=value,
hoverinfo='label+value+percent', textinfo='value'
)]})
], className='col-sm-4'))
def color_font():
selected_color = 'yellow'
style = {'textAlign': 'center', 'background': selected_color}
return style
def second_row():
return html.Div(className='four columns div-user-controls',
children=[
html.H2('Second Row', style=color_font()),
html.P('Display data Left')])
def multiple_rows():
return html.Div(className='rowxxx',
children=[
second_row(),
second_row(),
# my_tab(),
# html.Div(id='tabs-example-content')
])
def pie_chart_side_by_side():
return html.Div(data, className='row')
def pie_chart_single():
return html.Div(data_second, className='row')
def multiple_columns():
"""
Testing multiple column
"""
return dbc.Row(
[
dbc.Col(multiple_rows(), width=1),
dbc.Col(pie_chart_single()),
dbc.Col(pie_chart_side_by_side()),
], no_gutters=True, # Disable spacing between column
)
app.layout = html.Div(
children=[
multiple_columns(),
]
)
# Callback for
#app.callback(Output('tabs-example-content', 'children'),
[Input('tabs-example', 'value')])
def render_content(tab):
if tab == 'tab-1':
return html.Div([
html.H3('Tab content 1')
])
elif tab == 'tab-2':
return html.Div([
html.H3('Tab content 2')
])
elif tab == 'tab-3':
return html.Div([
html.H3('Tab content 3')
])
# Run the app
if __name__ == '__main__':
app.run_server(debug=True)
The parameter style is responsible to adjust the plot size.
For example,
style={"height": "50%", "width": "40%"}
The style can be incorporated as below,
html.Div(html.Div([dcc.Graph(figure = {'data': [go.Pie(labels=['Human', 'Animal', 'Alien'],
values=[40, 59.1, 0.9],
title='Trend',
showlegend=False,
hoverinfo='label+value+percent', textinfo='value')]}
)
], style={"height": "60%", "width": "80%"}))
Which produce something like the attachement below;

Categories

Resources