Based on this code directly from plotly's tut page:
https://plot.ly/python/dropdowns/
Now, what if I want to change not just the chart type but rather the data source and its chart type?
Is it possible?
EDIT:
I've played with this settings:
data1 = go.Surface(z=df.values.tolist(), colorscale='Viridis')
data2 = go.Heatmap(z=df.values.tolist())
buttons=list([
dict(
args=[data1],
label='3D Surface',
method='restyle'
),
dict(
args=[data2],
label='Heatmap',
method='restyle'
)
])
However, the graphs are shown, but overlayed. And when I click any item in the dropdown menu, the graph is completely gone.
I've found a solution myself, that is actually based on the tut:
import plotly
import plotly.graph_objs as go
from datetime import datetime
import pandas_datareader as web
df = web.DataReader("aapl", 'google',
datetime(2015, 1, 1),
datetime(2016, 7, 1))
trace_high = go.Bar( x=df.index,
y=df.High,
name='High')
trace_low = go.Scatter(x=df.index,
y=df.Low,
name='Low',
line=dict(color='#F06A6A'))
data = [trace_high, trace_low]
updatemenus = list([
dict(active=-1,
buttons=list([
dict(label = 'High',
method = 'update',
args = [{'visible': [True, False]},
{'title': 'Yahoo High'}]),
dict(label = 'Low',
method = 'update',
args = [{'visible': [False, True]},
{'title': 'Yahoo Low'}])
]),
)
])
layout = dict(title='Yahoo', showlegend=False,
updatemenus=updatemenus)
fig = dict(data=data, layout=layout)
plotly.offline.plot(fig, auto_open=False, show_link=False)
Related
I have this dataset below and this code that outputs this chart
Column A
Tools
Category
role
figure
Occurences After
idx
0
PostgreSQL
DatabaseHaveWorkedWith
Developer, front-end
38.044286
4
False
1
MySQL
DatabaseHaveWorkedWith
Developer, front-end
45.883489
2
False
0
MongoDB
DatabaseWantToWorkWith
Developer, front-end
39.018110
1
True
1
PostgreSQL
DatabaseWantToWorkWith
Developer, front-end
48.236203
3
False
0
MySQL
DatabaseHaveWorkedWith
Developer, back-end
26.096002
1
True
1
PostgreSQL
DatabaseHaveWorkedWith
Developer, back-end
33.771734
2
False
0
Redis
DatabaseWantToWorkWith
Developer, back-end
28.495408
1
True
1
PostgreSQL
DatabaseWantToWorkWith
Developer, back-end
40.314136
1
True
from itertools import cycle
import plotly.express as px
fig = go.Figure()
palette = cycle(px.colors.qualitative.Alphabet)
colors = {c:next(palette) for c in daata['Tools'].values}
#Build dropdown Labels
labels = daata['role'].unique()
for i, row in daata.iterrows():
fig.add_trace(
go.Bar(x=[[row['role']],[row["Category"]]],
y=[row["figure"]],
name=row["Tools"],
text=str(round(row["figure"],2))+'%', showlegend=row['idx'],marker_color=colors[row["Tools"]],
legendgroup=row["Tools"]# Fix legend
))
fig.update_layout({
'barmode': 'group',
'xaxis': {
'tickangle': -45,
},
'yaxis': {
'title_text': "figures",
},
})
fig.show()
The above code outputs this chart
However, I want to also add a dropdown filter for the roles (i.e the chart can be filtered by 'Developer, back-end', 'Developer, front-end' and 'All'
I have tried adding button labels, all what have tried kept filtering the chart wrongly
With dash you can add Dropdown and then use value to return fig. Please check below code:
from dash import Dash, dcc, html, dash_table, Input, Output, callback
import plotly.express as px
import dash_bootstrap_components as dbc
import pandas as pd
from itertools import cycle
palette = cycle(px.colors.qualitative.Alphabet)
colors = {c:next(palette) for c in daata['Tools'].values}
#Build dropdown Labels
labels = daata['role'].unique()
app = Dash(__name__, external_stylesheets=[dbc.themes.LUX])
app.layout = html.Div([
dcc.Dropdown(id='dropdown',
options=[
{'label': x, 'value': x} for x in df['role'].unique()],
value=[],
multi=True,
disabled=False,
clearable=True,
searchable=True),
dcc.Graph(id='graph',figure={})
])
#app.callback(Output('graph','figure'),
Input('dropdown','value'))
def update_graph(role):
if role == []:
dff= daata.copy()
fig = go.Figure()
for i, row in dff.iterrows():
fig.add_trace(
go.Bar(x=[[row['role']],[row["Category"]]],
y=[row["figure"]],
name=row["Tools"],
text=str(round(row["figure"],2))+'%', showlegend=row['idx'],marker_color=colors[row["Tools"]],
legendgroup=row["Tools"]# Fix legend
))
fig.update_layout({
'barmode': 'group',
'xaxis': {'tickangle': -45},
'yaxis': {'title_text': "figures",},
})
else:
dff= daata[daata['role'].isin(role)]
fig = go.Figure()
for i, row in dff.iterrows():
fig.add_trace(
go.Bar(x=[[row['role']],[row["Category"]]],
y=[row["figure"]],
name=row["Tools"],
text=str(round(row["figure"],2))+'%', showlegend=row['idx'],marker_color=colors[row["Tools"]],
legendgroup=row["Tools"]# Fix legend
))
fig.update_layout({
'barmode': 'group',
'xaxis': {'tickangle': -45},
'yaxis': {'title_text': "figures",},
})
return fig
if __name__ == "__main__":
app.run_server(debug=False)
Hope this help
i am trying to compare two lines in the same fig in plotly go, the goal is to let the user to select two entities (i.e. countries) from two dropdown menu in the chart
this is the chart with all entities active
when i select different country in the two dropdown:
i.e. dropdown1 = Italy, dropdown2= France
the chart shows just one line (the last selected from the dropdown, so it update)but it doesn't plot the two lines in the same figure
Plot with just one line
this is the dataframe:
dataframe head
this is the code i am working on:
fig1 = go.Figure()
for column in df.columns.to_list():
fig1.add_trace(
go.Scatter(
x = df.index,
y = df[column],
name = column
)
)
button_all = dict(label = 'All',
method = 'restyle',
args = [{'visible': df.columns.isin(df.columns),
'title': 'All',
'showlegend':True}])
button_none = dict(label = 'None',
method = 'update',
args = [{'visible': df.columns.isin(df.columns),
'title': 'All',
'showlegend':True}])
def create_layout_button(column):
return dict(label = column,
method = 'restyle',
args = [{'visible': df.columns.isin([column]),
'title': column,
'showlegend': True}])
def create_layout_buttonE(column):
return dict(label = column,
method = 'update',
args = [{'visible': df.columns.isin([column]),
'title': column,
'showlegend': True}])
addAll = True
# Update plot sizing
fig1.update_layout(
width=700,
height=500,
autosize=False,
margin=dict(t=120, b=0, l=0, r=0),
)
# Add dropdowns
button_layer_1_height = 1.08
fig1.update_layout(
updatemenus=[
dict(
buttons=([button_all] * addAll) + list(df.columns.map(lambda column: create_layout_button(column))),
direction="down",
pad={"r": 10, "t": 0},
showactive=True,
x=0.1,
xanchor="left",
y=button_layer_1_height,
yanchor="top"
),
dict(
buttons=([button_none] * addAll) + list(df.columns.map(lambda column: create_layout_buttonE(column))),
direction="down",
pad={"r": 10, "t": 0},
showactive=True,
x=0.37,
xanchor="left",
y=button_layer_1_height,
yanchor="top"
),
]
)
fig1.show()
synthesized dataframe in same structure as you defined
taken a different approach. Rather than creating all traces and controlling visibility in updatemenus. Create two traces and control name and contents of y in updatemenus
import pandas as pd
import numpy as np
import plotly.graph_objects as go
# get some countries
countries = (
pd.read_csv(
"https://raw.githubusercontent.com/owid/covid-19-data/master/public/data/vaccinations/locations.csv"
)
.loc[lambda d: d["iso_code"].str.len() == 3, "location"]
.sample(20)
.sort_values()
.values
)
# build data frame of same struct
df = pd.DataFrame(
np.random.randint(200, 1500, [22, len(countries)]),
columns=countries,
index=range(2000, 2022),
)
# create a figure with two place holder traces
fig = go.Figure(
[
go.Scatter(x=df.index, y=np.full(len(df), np.nan), meta=i, name=i)
for i in range(2)
]
)
# but data for y and name in when country is selected
fig.update_layout(
updatemenus=[
{
"x": b / 3,
"y": 1.4,
"active": None,
"buttons": [
{
"label": c,
"method": "restyle",
"args": [{"y": [df[c]], "name": c}, [b]],
}
for c in df.columns
],
}
for b in range(2)
]
)
I'm following a simple tutorial to build a stock price dashboard in Plotly Dash. When the app is running on localhost, every Component gets a border when hovered or clicked. See the GIF below.
Is this due to a setting somewhere? It's very annoying, and it seems to happen in most of the Dash apps I've been making.
The code for the app is here:
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
import plotly.graph_objs as go
import pandas_datareader.data as web
from datetime import datetime, timedelta
app = dash.Dash(title="Stock Dashboard")
app.layout = html.Div(
[
html.H1("Stock Ticker Dashboard"),
html.Div(
[
html.H4("Enter stock symbols:"),
dcc.Input(
id = 'stock_picker',
value = 'AAPL',
style = dict(
fontSize = 24,
width = '100%',
marginRight = '15px',
padding = '10px 5px',
borderRadius = '4px'
)
),
],
style = dict(
display = 'inline-block',
verticalAlign = 'middle',
marginRight = '20px',
width = '40%'
)
),
html.Div(
[
html.H4("Choose a date range:"),
dcc.DatePickerRange(
id = 'date_picker',
min_date_allowed = datetime(2010, 1, 1),
max_date_allowed = datetime.today(),
start_date = datetime.today() - timedelta(days=365),
end_date = datetime.today(),
),
],
style = dict(
display = 'inline-block',
verticalAlign = 'middle',
marginLeft = '20px'
)
),
html.Div(
[
html.Button(
id = 'submit_button',
n_clicks = 0,
children = "Submit",
style = dict(
fontSize = 24,
marginLeft = '30px'
)
)
],
style = dict(
display = 'inline-block',
verticalAlign = 'bottom'
)
),
html.Div(
[
dcc.Graph(
id = 'stock_graph',
figure = dict(
data = [{'x': [1,2], 'y': [3,1]}],
layout = go.Layout(
xaxis = dict(
title = dict(
text = "Date",
),
),
yaxis = dict(
title = dict(
text = "Closing Price / [$]",
)
)
)
),
style = dict(
height = '600px'
)
)
],
style = dict(
height = '600px'
)
)
],
style = dict()
)
#app.callback(
Output('stock_graph', 'figure'),
[Input('submit_button', 'n_clicks')],
[
State('stock_picker', 'value'),
State('date_picker', 'start_date'),
State('date_picker', 'end_date')
],
)
def update_graph(n_clicks, stock_ticker, start_date, end_date):
start = datetime.strptime(start_date[:10], '%Y-%M-%d')
end = datetime.strptime(end_date[:10], '%Y-%M-%d')
print(f"Getting stock prices for: {stock_ticker}, [{start} - {end}]")
df = web.DataReader(stock_ticker, 'yahoo', start, end)
fig = dict(
data = [go.Scatter(
x = df.index,
y = df['Close'],
mode = 'lines'
)],
layout = dict(
title = stock_ticker,
yaxis = dict(
title = 'Closing Price / [$]'
)
)
)
return fig
if __name__ == '__main__':
app.run_server()
Edited to add the version numbers for some of the modules (please let me know if I should include others):
pandas==1.1.1
pandas-datareader==0.9.0
dash-core-components==1.10.2
dash-html-components==1.0.3
dash-renderer==1.6.0
dash-table==4.9.0
Flask==1.1.2
Flask-Compress==1.5.0
I'm a dingus. It was from my React Developer Tools addon (Firefox 79.0). Not sure why that setting got turned on, but there you go. :facepalm:
Editing:
The following example from Plotly for reference:
import plotly.express as px
df = px.data.gapminder().query("continent == 'Europe' and year == 2007 and pop > 2.e6")
fig = px.bar(df, y='pop', x='country', text='pop')
fig.update_traces(texttemplate='%{text:.2s}', textposition='outside')
fig.update_layout(uniformtext_minsize=8, uniformtext_mode='hide')
fig.show()
How to remove the word 'pop'.
What I want to hide the y-axis title of'value'.
The following syntax doesn't work.
fig.update_yaxes(showticklabels=False)
Thanks.
Solution
You need to use visible=False inside fig.update_yaxes() or
fig.update_layout() as follows. For more details see the
documentation for plotly.graph_objects.Figure.
# Option-1: using fig.update_yaxes()
fig.update_yaxes(visible=False, showticklabels=False)
# Option-2: using fig.update_layout()
fig.update_layout(yaxis={'visible': False, 'showticklabels': False})
# Option-3: using fig.update_layout() + dict-flattening shorthand
fig.update_layout(yaxis_visible=False, yaxis_showticklabels=False)
Try doing the following to test this:
# Set the visibility ON
fig.update_yaxes(title='y', visible=True, showticklabels=False)
# Set the visibility OFF
fig.update_yaxes(title='y', visible=False, showticklabels=False)
A. How to create the figure directly with hidden-yaxis label and tickmarks
You can do this directly by using the layout keyword and
supplying a dict to go.Figure() constructor.
import plotly.graph_objects as go
fig = go.Figure(
data=[go.Bar(y=[2, 1, 3])],
layout_title_text="A Figure Displaying Itself",
layout = {'xaxis': {'title': 'x-label',
'visible': True,
'showticklabels': True},
'yaxis': {'title': 'y-label',
'visible': False,
'showticklabels': False}
}
)
fig
B. How to create the figure without the margin space around
Say, you suppressed the titles for both the axes. By default plotly
would still leave a default amount of space all around the figure:
this is known as the margin in Plotly's documention.
What if you want to reduce or even completely remove the margin?
This can be done using fig.update_layout(margin=dict(l = ..., r = ..., t = ..., b = ...)) as mentioned in the documentation:
https://plotly.com/python/reference/#layout-margin.
In the following example, I have reduced the left, right
and bottom margins to 10 px and set the top margin to 50 px.
import plotly.graph_objects as go
fig = go.Figure(
data=[go.Bar(y=[2, 1, 3])],
layout_title_text="A Figure with no axis-title and modified margins",
layout = {
'xaxis': {'title': 'x-label',
'visible': False,
'showticklabels': True},
'yaxis': {'title': 'y-label',
'visible': False,
'showticklabels': False},
# specify margins in px
'margin': dict(
l = 10, # left
r = 10, # right
t = 50, # top
b = 10, # bottom
),
},
)
fig
C. An Interesting Feature of Plotly: A hidden shorthand
It turns out that Plotly has a convenient shorthand notation
allowing dict-flattening available for input arguments such as this:
## ALL THREE METHODS BELOW ARE EQUIVALENT
# No dict-flattening
# layout = dict with yaxis as key
layout = {'yaxis': {'title': 'y-label',
'visible': False,
'showticklabels': False}
}
# Partial dict-flattening
# layout_yaxis = dict with key-names
# title, visible, showticklabels
layout_yaxis = {'title': 'y-label',
'visible': False,
'showticklabels': False}
# Complete dict-flattening
# layout_yaxis_key-name for each of the key-names
layout_yaxis_title = 'y-label'
layout_yaxis_visible = False
layout_yaxis_showticklabels = False
Now try running all three of the following and compare the outputs.
import plotly.graph_objects as go
# Method-1: Shortest (less detailed)
fig = go.Figure(
data=[go.Bar(y=[2, 1, 3])],
layout_title_text="A Figure Displaying Itself",
layout_yaxis_visible = False,
layout_xaxis_title = 'x-label'
)
fig.show()
# Method-2: A hibrid of dicts and underscore-separated-syntax
fig = go.Figure(
data=[go.Bar(y=[2, 1, 3])],
layout_title_text="A Figure Displaying Itself",
layout_xaxis_title = 'x-label',
layout_yaxis = {'title': 'y-label',
'visible': False,
'showticklabels': False}
)
fig.show()
# Method-3: A complete dict syntax
fig = go.Figure(
data=[go.Bar(y=[2, 1, 3])],
layout_title_text="A Figure Displaying Itself",
layout = {'xaxis': {'title': 'x-label',
'visible': True,
'showticklabels': True},
'yaxis': {'title': 'y-label',
'visible': False,
'showticklabels': False}
}
)
fig.show()
How to remove the word 'pop'?
Just pass yaxis_title=None to fig.update_layout to hide default title of Y axis (similarly for xaxis_title=None for X axis).
import plotly.express as px
df = px.data.gapminder().query("continent == 'Europe' and year == 2007 and pop > 2.e6")
fig = px.bar(df, y='pop', x='country', text='pop')
fig.update_traces(texttemplate='%{text:.2s}', textposition='outside')
fig.update_layout(uniformtext_minsize=8, uniformtext_mode='hide', yaxis_title=None)
fig.show()
I'm making a webapp using Python and Dash, this webapp includes a choropleth map of the world with data based on the selected year. I want to be able to change the year and with that also update the map to match that year. I prefer to do this with the Dash slider, although any other way I would appreciate as well.
I've tried updating other graphs such as line charts with the text input, and that worked, but when i changed it to a choropleth map it stopped updating. It now only creates the map but updates on it don't show up. I've put some print text in the update function and it confirmed that it is actually called when I change the input, but the graph just doesn't update.
The layout:with the dcc.input i want to update the html.Div 'my-div'
app.layout = html.Div( children=[
html.H1(
children='UN Sustainable Development goal: Poverty',
style={
'textAlign': 'center',
'color': colors
}
),
dcc.Input(id='my-id',value='30', type='text'),
html.Div(id='my-div')
,
daq.Slider(
id='my-daq-slider',
min=1,
max=sliderlength,
step=1,
),
html.Div(id='slider-output')
], style={
'textAlign': 'center'
})
The update part
#app.callback(
Output('my-div', 'children'),
[Input('my-id', 'value')])
def update_output_div(input_value):
return dcc.Graph(
id='my-div',
figure={'data': [go.Choropleth(
locations = df_pov['Country Code'],
z = df_pov.iloc[:,int(input_value)],
text = df_pov['Country Name'],
autocolorscale = True,
reversescale = False,
marker = go.choropleth.Marker(
line = go.choropleth.marker.Line(
color = 'rgb(180,180,180)',
width = 0.5
)),
colorbar = go.choropleth.ColorBar(
tickprefix = '%',
title = '% below 1.90$ '),
)],
'layout': go.Layout(
title = go.layout.Title(
text = list(df_pov)[int(input_value)]
),
geo = go.layout.Geo(
showframe = False,
showcoastlines = False,
projection = go.layout.geo.Projection(
type = 'equirectangular'
)
),
annotations = [go.layout.Annotation(
x = 0.55,
y = 0.1,
xref = 'paper',
yref = 'paper',
text = 'Source: Kaggle',
showarrow = False
)]
)
}
)
What i expected: for the choropleth to update when changing the text input, or slider input.
Actual: the map gets created once ( with the same function that should update it), but doesn't update.
Dash doesn't like new components being loaded in like this. Try initializing your graph by adding an empty graph to the layout like this:
html.Div(id='my-div', children=[
dcc.Graph(
id='my-graph-id',
figure=dict(
data=[],
layout={},
),
)
])
With the graph already on the page, you would have to change the callback so that it updates the figure prop of the Graph instead of the children of the div.
Also, you have multiple IDs that are the same. Dash doesn't like that. Make sure every ID is unique. If all of this still does not work, I may need to ask you to post some more details so I can help further. Good luck!