Dropdown menu for Plotly Choropleth Map Plots - python

I am trying to create choropleth maps. Below is an example that works:
df = px.data.gapminder().query("year==2007")
fig = go.Figure(data=go.Choropleth(
locations=happy['iso'], # Spatial coordinates
z = happy['Happiness'].astype(float), # Data to be color-coded
colorbar_title = "Happiness Score",
))
fig.update_layout(
title_text = 'Life Expectancy in 2007'
)
fig.show()
However, I would like to create a dropdown menu that will change the plotted values between different variables (e.g., Life Expectancy, GDP, Population). I believe that this is possible but have not seen any tutorial online. Most of them just uses other kind of barcharts or scatterplots.
Here is what I have gotten so far:
# Initialize figure
fig = go.Figure()
# Add Traces
fig.add_trace(go.Figure(data=go.Choropleth(
locations=df['iso_alpha'], # Spatial coordinates
z = df['lifeExp'].astype(float), # Data to be color-coded
colorbar_title = "Life Expectancy")))
fig.add_trace(go.Figure(data=go.Choropleth(
locations=df['iso_alpha'], # Spatial coordinates
z = df['gdpPercap'].astype(float), # Data to be color-coded
colorbar_title = "GDP per capita")))
But I am not sure how to proceed from here. Do I need to update the layout of the figure via fig.update_layout or something?

There are two ways to solve this
Dash
# save this as app.py
import pandas as pd
import plotly.graph_objs as go
import plotly.express as px
import dash
import dash_core_components as dcc
import dash_html_components as html
# Data
df = px.data.gapminder().query("year==2007")
df = df.rename(columns=dict(pop="Population",
gdpPercap="GDP per Capita",
lifeExp="Life Expectancy"))
cols_dd = ["Population", "GDP per Capita", "Life Expectancy"]
app = dash.Dash()
app.layout = html.Div([
dcc.Dropdown(
id='demo-dropdown',
options=[{'label': k, 'value': k} for k in cols_dd],
value=cols_dd[0]
),
html.Hr(),
dcc.Graph(id='display-selected-values'),
])
#app.callback(
dash.dependencies.Output('display-selected-values', 'figure'),
[dash.dependencies.Input('demo-dropdown', 'value')])
def update_output(value):
fig = go.Figure()
fig.add_trace(go.Choropleth(
locations=df['iso_alpha'], # Spatial coordinates
z=df[value].astype(float), # Data to be color-coded
colorbar_title=value))
fig.update_layout(title=f"<b>{value}</b>", title_x=0.5)
return fig
if __name__ == '__main__':
app.run_server()
run this as python app.py and go to http://127.0.0.1:8050
Plotly
In this case we need to play with visibility of different traces and create buttons in a way they show one traces and hide all the others.
import pandas as pd
import numpy as np
import plotly.graph_objs as go
import plotly.express as px
# Data
df = px.data.gapminder().query("year==2007")
df = df.rename(columns=dict(pop="Population",
gdpPercap="GDP per Capita",
lifeExp="Life Expectancy"))
cols_dd = ["Population", "GDP per Capita", "Life Expectancy"]
# we need to add this to select which trace
# is going to be visible
visible = np.array(cols_dd)
# define traces and buttons at once
traces = []
buttons = []
for value in cols_dd:
traces.append(go.Choropleth(
locations=df['iso_alpha'], # Spatial coordinates
z=df[value].astype(float), # Data to be color-coded
colorbar_title=value,
visible= True if value==cols_dd[0] else False))
buttons.append(dict(label=value,
method="update",
args=[{"visible":list(visible==value)},
{"title":f"<b>{value}</b>"}]))
updatemenus = [{"active":0,
"buttons":buttons,
}]
# Show figure
fig = go.Figure(data=traces,
layout=dict(updatemenus=updatemenus))
# This is in order to get the first title displayed correctly
first_title = cols_dd[0]
fig.update_layout(title=f"<b>{first_title}</b>",title_x=0.5)
fig.show()

Related

Plotly: refresh data passed to px.line via dropdown from Database

I want to use the plotly express lineplot to create a simple interactive plot that refreshes its data when choosing a new item in a dropdown box.
I have created a simple function prepare_dashboard_data which loads data from a database and does some filtering. The dashboard is showing the data from the initial dataload but I am completely lost on how to create a callback to the px.line function, such that the plot is updated with new data loaded from the database.
I have taken inspiration from this post where plotly.graph_objs are used. But i quite like the functionality of the default lineplot.
And in the example a preloaded dataframe is simply filtered based on the dropdown choice. This is not what I want.
I have some limited knowledge with ipython widgets and the observer pattern, but I am completely lost in this case. Here is a rough sceme of my current code:
import plotly.graph_objs as go
import plotly.express as px
def prepare_dashboard_data(serverconfig, shopname = "myshop"):
# Data is loaded form a db
# Transformed filtered by shopname and so on ...
# This returns a datframe with has an timestamp as an index and many items as columns
return df
# Prepare Dropdown menues
shopnames = df.columns # This just gives a list of available shopnames.
# plotly start
fig = go.Figure()
fig = px.line(prepare_dashboard_data(serverconfig=conf, shopname = "myshop"),width=1600, height=800)
# menu setup
updatemenu= []
# buttons for menu 1, shopnames
buttons=[]
# should i create traces for each shopnames alread here:
for webshop_name in shopnames :
buttons.append(dict(method='update',
label=webshop_name,
visible=True,
args=[#{I guess here goes the magic?}
]
)
)
# some adjustments to the updatemenus
updatemenu=[]
your_menu=dict()
updatemenu.append(your_menu)
updatemenu[0]['buttons']=buttons
updatemenu[0]['direction']='down'
updatemenu[0]['showactive']=True
fig.update_layout(
autosize=False,
width=1800,
height=800,
margin=dict(
l=50,
r=50,
b=100,
t=100,
pad=4
),
updatemenus=updatemenu,
paper_bgcolor="LightSteelBlue",
)
fig.show()
Any help would be really appreciated. I have tried to make sense of the documentation but i think i would need a pointer. Currently i generate my plots in a Vscode/jupyter notebook, not as a standalone app .
You should use plotly-Dash to solve this. Here is an example you can tune to fit the structure of your dataframe.
from dash import Dash, dcc, html, Input, Output
import pandas as pd
import plotly.express as px
app = Dash(__name__)
app.layout = html.Div([
dcc.Dropdown(['a','b','c'], 'a', id='dropdown'),
dcc.Graph(id='graph')
])
df = pd.DataFrame(
{'a': [1,2,3,4,5],
'b': [-1,-2,-3,-4,-5],
'c': [2,4,6,8,10]
}
)
#app.callback(
Output(component_id='graph', component_property='figure'),
Input(component_id='dropdown', component_property='value')
)
def update_output(column):
fig = px.line(df, x=column)
return fig
if __name__ == '__main__':
app.run_server(debug=True)

Is it possible to filter the dash datatable with the first row always unfiltered

I need to plot a 3D scatter and data table in Dash.
My intention is to be able to use the data table to filter the scatter plot. The first row of my data is the target. Is it possible for the filter to always keep the first row?
For example, I tried using the solar.csv to build a mockup:
from dash import Dash, dash_table
import pandas as pd
from dash.dependencies import Input, Output
import plotly.express as px
from dash import Dash, dash_table, html, dcc
df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/solar.csv')
app = Dash(__name__)
app.layout = dash_table.DataTable(
df.to_dict('records'),
[{"name": i, "id": i} for i in df.columns],
filter_action='native'
)
app.layout = html.Div([
dash_table.DataTable(
id='datatable-interactivity',
data = df.to_dict('records'),
columns = [{"name": i, "id": i} for i in df.columns],
filter_action='native'
),
html.Div(id='scatter-container')
])
#app.callback(
Output(component_id='scatter-container', component_property='children'),
Input(component_id='datatable-interactivity', component_property="derived_virtual_data")
)
def update_scatter(all_rows_data):
dff = pd.DataFrame(all_rows_data)
fig = px.scatter(dff, x='Number of Solar Plants', y = 'Generation (GWh)')
return dcc.Graph(figure=fig)
if __name__ == '__main__':
app.run_server(debug=True)
Assume the first row (California) is my target, is it possible to show both California and Arizona when I type "Arizona" in the filter field and hence show both California and Arizona in the scatter plot?
There may be many approaches, but one way to always display fixed rows is to create an additional graph on the graph created by the filtered data frame. go's graph object is used to add markers. And, I matched the hover data to the original graph.
def update_scatter(all_rows_data):
dff = df if all_rows_data is None else pd.DataFrame(all_rows_data)
fig = px.scatter(dff, x='Number of Solar Plants', y='Generation (GWh)')
fig.add_trace(go.Scatter(x=[df.loc[0, 'Number of Solar Plants']],
y=[df.loc[0,'Generation (GWh)']],
mode='markers',
marker=dict(color='#636efa'),
showlegend=False,
hovertemplate='Number of Solar Plants=%{x}<br>Generation (GWh)%{y}'
))
return dcc.Graph(figure=fig)

Plotly: How to change axes variables interactively for a 3D scatter plot?

I'm plotting a multidimensional table in scatter plots to test relationships between columns of a unique data frame.
I would like to know if there is any way that I can change in the browser the variable in each ax in an interactive way, without needing to plot another grid.
I don't know if this is a redundant question, but I've already did some research without any success.
fig = px.scatter_3d(data, x="V1", y="V2", z= 'V3', hover_data=['Z'])
fig.show()
Thank you in advance.
The complete code snippet below will give you a Dash-app in JupyterLab that looks like this:
Here you can change which columns to display from the plotly dataset px.data.stocks(). If this approach is something you can use, I'd be happy to explain the details. ANd if JupyterLab is not your thing, just follow the three steps needed to rewrite it to a standard Dash app as described in the post Plotly: How to rewrite a standard dash app to launch it in JupyterLab?
Complete code_
import plotly as py
import pandas as pd
from plotly import tools
import plotly.express as px
import plotly.graph_objects as go
import dash
import dash_core_components as dcc
import dash_html_components as html
from jupyter_dash import JupyterDash
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output
app = JupyterDash(external_stylesheets=[dbc.themes.SLATE])
colors = px.colors.qualitative.Plotly
# colors = ['blue', 'green', 'red', 'black', 'yellow']
symbols = ['circle', 'circle-open', 'square', 'square-open', 'diamond', 'diamond-open', 'cross', 'x']
df = px.data.stocks().set_index('date')
columns = df.columns
# Set up well organized controls in a dbc.Card()
controls = dbc.Card([dbc.FormGroup([dbc.Label("x-axis"),
dcc.Dropdown(id='dd_x',
options= [{'label': k, 'value': k} for k in columns],
value=columns[0],
),
],),
dbc.FormGroup([dbc.Label("y-axis"),
dcc.Dropdown(id='dd_y',
options= [{'label': k, 'value': k} for k in columns],
value=columns[1],
),
],),
dbc.FormGroup([dbc.Label("z-axis"),
dcc.Dropdown(id='dd_z',
options= [{'label': k, 'value': k} for k in columns],
value=columns[2],
),
],)
],
body=True,
style = {'font-size': 'large'}
)
# Set up the app layout using dbc.Container(), dbc.Row(), and dbc.Col()
app.layout = dbc.Container([html.H1("Make a column selection for each axis"),
html.Hr(),
dbc.Row([dbc.Col([controls],xs = 4),
dbc.Col([dbc.Row([dbc.Col(dcc.Graph(id="market_graph")),])]),
]),
html.Br(),
],
fluid=True,
)
# 3D figure with callbacks for color, symbol and size
#app.callback(
Output("market_graph", "figure"),
[
Input("dd_x", "value"),
Input("dd_y", "value"),
Input("dd_z", "value"),
],
)
def history_graph(x, y, z):
# df = px.data.iris()
fig = px.scatter_3d(df, x=df[x], y=df[y], z=df[z])
fig.data[0].update(marker_color=colors[4])
fig.data[0].update(marker_symbol=symbols[6])
fig.data[0].update(marker_size=8)
fig.update_layout(uirevision='constant')
fig.update_layout(template = 'plotly_dark')
fig.update_layout(margin=dict(l=10, r=10, b=10, t=10))
return fig
app.run_server(mode='inline', port = 8007)

Plotly: How to make a plotly dropdown menu for figures with wholly different data and layouts?

I am trying to make an interactive plot with a dropdown menu that selects from a series of wholly unrelated figures (i.e. plots that rely on different data structures and that have very different layouts). All of the dropdown menu examples I have seen are based on either a single set of data or multiple datasets but that use a relatively simple plot layout. This is not applicable to my case where I am trying to merge dozens of plots with very different layouts and underlying data. Below is a working example of the plots that I am trying to merge. The layouts are highly different across each plot:
import plotly.graph_objs as go
import plotly.express as px
import pandas as pd
# Prep some fake data for a bar graph
df1 = pd.DataFrame(dict(
bar_y = ['Bar1', 'Bar2'],
bar_x = [2,3],
bar_z = [1,2]
))
# Make bar graph
fig1 = px.bar(df1,
x="bar_x",
y='bar_y',
color='bar_z',
orientation='h',
)
# Add layout attributes
fig1.update_layout(
xaxis_title="<b> Bar graph title <b>",
yaxis_title="<b> Bar x axis <b>",
legend_title="<b> Bar y axis <b>",
xaxis = dict(
showgrid=True,
ticks="",
showline = False,
gridcolor = 'white'
)
)
# Prep some fake data for a line graph
df2 = pd.DataFrame(dict(
line_y = [3,2,1, 1,2,3],
line_x = [1,2,3,1,2,3],
line_group = ['line1','line1','line1','line2','line2','line2']
))
# Make an ugly line graph
fig2 = px.line(
df2,
x= 'line_x',
y= 'line_y',
color = 'line_group'
)
# Add a number of layout attributes that are distinct from those above
fig2.update_layout(
shapes=[dict(
type= 'line',
fillcolor = 'black',
line_width=2,
yref= 'y', y0= 0, y1= 0,
xref= 'x', x0= 1, x1= 3,
)],
xaxis_title="<b> Line graph title <b>",
yaxis_title="<b> Line x axis <b>",
legend_title="<b> Line y axis <b>",
template='simple_white',
hoverlabel=dict(bgcolor="white")
)
# Create a dropdown menu. Below is close to what I'd like to do, but the data statements are not working correctly and the shape in fig2 is causing problems...
fig3 = go.Figure()
fig3.update_layout(
updatemenus=[
dict(
active=0,
buttons=list([
dict(label="Bar Graph",
method="update",
args=[fig1.to_dict()['data'],
fig1.to_dict()['layout']]
),
dict(label="Line Graph",
method="update",
args=[fig2.to_dict()['data'],
fig2.to_dict()['layout']]
),
]))
]
)
It appears that I am almost able to correctly update the layout of each dropdown constituent plot based on the layout of each original graph. However, is it possible to update the data via this sort of method
as well?
I may be missing the point completely here. And it may also be overkill to unleash a Dash app in this case. But I would like to show you how the following setup can enable you to return completely different figure objects using a dcc.Dropdown(). The code snippet below will produce the following app:
If you now select fig2, you'll get this:
We can talk more about the details if this is something you can use. Also, the design with the very wide dropdown button is admittedly not the prettiest one, but I assume that design isn't the primary objective here.
Complete code:
import dash
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
import plotly.graph_objs as go
from dash.dependencies import Input, Output
import numpy as np
from plotly.subplots import make_subplots
import plotly.express as px
# Prep some fake data for a bar graph
df1 = pd.DataFrame(dict(
bar_y = ['Bar1', 'Bar2'],
bar_x = [2,3],
bar_z = [1,2]
))
# Make bar graph
fig1 = px.bar(df1,
x="bar_x",
y='bar_y',
color='bar_z',
orientation='h',
)
# Add layout attributes
fig1.update_layout(
xaxis_title="<b> Bar graph title <b>",
yaxis_title="<b> Bar x axis <b>",
legend_title="<b> Bar y axis <b>",
xaxis = dict(
showgrid=True,
ticks="",
showline = False,
gridcolor = 'white'
)
)
# Prep some fake data for a line graph
df2 = pd.DataFrame(dict(
line_y = [3,2,1, 1,2,3],
line_x = [1,2,3,1,2,3],
line_group = ['line1','line1','line1','line2','line2','line2']
))
# Make an ugly line graph
fig2 = px.line(
df2,
x= 'line_x',
y= 'line_y',
color = 'line_group'
)
# Add a number of layout attributes that are distinct from those above
fig2.update_layout(
shapes=[dict(
type= 'line',
fillcolor = 'black',
line_width=2,
yref= 'y', y0= 0, y1= 0,
xref= 'x', x0= 1, x1= 3,
)],
xaxis_title="<b> Line graph title <b>",
yaxis_title="<b> Line x axis <b>",
legend_title="<b> Line y axis <b>",
template='simple_white',
hoverlabel=dict(bgcolor="white")
)
# app = JupyterDash(__name__)
app = dash.Dash()
figs = ['fig1', 'fig2']
app.layout = html.Div([
html.Div([
dcc.Graph(id='plot'),
html.Div([
dcc.Dropdown(
id='variables',
options=[{'label': i, 'value': i} for i in figs],
value=figs[0]
)
])
])
])
#app.callback(
Output('plot', 'figure'),
[Input('variables', 'value')])
def update_graph(fig_name):
if fig_name == 'fig1':
# fig=go.Figure(go.Scatter(x=[1,2,3], y = [3,2,1]))
return fig1
if fig_name == 'fig2':
# fig=go.Figure(go.Bar(x=[1,2,3], y = [3,2,1]))
return fig2
# app.run_server(mode='external', debug=True)
app.run_server(debug=True,
use_reloader=False # Turn off reloader if inside Jupyter
)

Set up multiple subplots with moving averages using cufflinks and plotly offline

Im trying to select 4 different product prices from my dataframe and plot their moving average as a subplot (2,2) using plotly cufflinks. I would appreciate if anyone can guide on this.
I tried plotting the price as below.
I came across cufflinks technical analysis which allow me to plot moving average in a cleaner way, however, im not too sure how to apply it yet.
from plotly.offline import download_plotlyjs,init_notebook_mode,plot,iplot
from plotly import tools
import plotly.graph_objs as go
trace1= go.Scatter(name=',milk', x=df.Date, y=df['milk'])
trace2= go.Scatter(name='soap', x=df.Date, y=df['soap'])
trace3= go.Scatter(name='rice', x=df.Date, y=df['rice'])
trace4= go.Scatter(name='water', x=df.Date, y=df['water'])
fig = tools.make_subplots(rows=2, cols=2, subplot_titles=('milk', 'soap',
'rice', 'water'))
fig.append_trace(trace1, 1, 1)
fig.append_trace(trace2, 1, 2)
fig.append_trace(trace3, 2, 1)
fig.append_trace(trace4, 2, 2)
fig['layout'].update(height=1000, width=1800, title='supermarket')
plot(fig, filename='supermarket.html')
I would appreciate if someone could teach me how to use plotly cufflinks to plot four moving averages from the selected columns from a dataframe using plotly offline.
Insert the code section below in a Jupyter Notebook to produce the following plot using cufflinks and plotly offline:
Plot:
Code:
# imports
import plotly
from plotly import tools
import cufflinks as cf
from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot
import pandas as pd
import numpy as np
from IPython.core.display import display, HTML
import copy
import plotly.graph_objs as go
####### PART 1 - SETUP AND SAMPLE DATA #######
# setup
display(HTML("<style>.container { width:55% !important; } .widget-select > select {background-color: gainsboro;}</style>"))
init_notebook_mode(connected=True)
np.random.seed(123)
cf.set_config_file(theme='pearl')
# Random data using cufflinks
df = cf.datagen.lines().iloc[:,0:4]
df.columns = ['StockA', 'StockB', 'StockC', 'StockD']
####### PART 2 - FUNCTION FOR MOVING AVERAGES #######
# Function for moving averages
def movingAvg(df, win, keepSource):
"""Add moving averages for all columns in a dataframe.
Arguments:
df -- pandas dataframe
win -- length of movingAvg estimation window
keepSource -- True or False for keep or drop source data in output dataframe
"""
df_temp = df.copy()
# Manage existing column names
colNames = list(df_temp.columns.values).copy()
removeNames = colNames.copy()
i = 0
for col in colNames:
# Make new names for movingAvgs
movingAvgName = colNames[i] + '_MA' #+ str(win)
# Add movingAvgs
df_temp[movingAvgName] = df[col].rolling(window=win).mean()
i = i + 1
# Remove estimates with insufficient window length
df_temp = df_temp.iloc[win:]
# Remove or keep source data
if keepSource == False:
df_temp = df_temp.drop(removeNames,1)
return df_temp
# Add moving averages to df
windowLength = 10
df = movingAvg(df=df, win=windowLength, keepSource = True)
####### PART 3 -PLOTLY RULES #######
# Structure lines / traces for the plots
# trace 1
trace1 = go.Scatter(
x=df.index,
y=df['StockA'],
name='StockA'
)
trace1_ma = go.Scatter(
x=df.index,
y=df['StockA_MA'],
name='StockA_MA'
)
# trace 2
trace2 = go.Scatter(
x=df.index,
y=df['StockB'],
name='StockB'
)
trace2_ma = go.Scatter(
x=df.index,
y=df['StockB_MA'],
name='StockB_MA'
)
# trace 3
trace3 = go.Scatter(
x=df.index,
y=df['StockC'],
name='StockC'
)
trace3_ma = go.Scatter(
x=df.index,
y=df['StockC_MA'],
name='StockC_MA'
)
# trace 4
trace4 = go.Scatter(
x=df.index,
y=df['StockD'],
name='StockD'
)
trace4_ma = go.Scatter(
x=df.index,
y=df['StockD_MA'],
name='StockD_MA'
)
# Structure traces as datasets
data1 = [trace1, trace1_ma]
data2 = [trace2, trace2_ma]
data3 = [trace3, trace3_ma]
data4 = [trace4, trace4_ma]
# Build figures
fig1 = go.Figure(data=data1)
fig2 = go.Figure(data=data2)
fig3 = go.Figure(data=data3)
fig4 = go.Figure(data=data4)
# Subplots setup and layout
figs = cf.subplots([fig1, fig2, fig3, fig4],shape=(2,2))
figs['layout'].update(height=800, width=1200,
title='Stocks with moving averages = '+ str(windowLength))
iplot(figs)

Categories