Hi I am quite new to plotly and trying to create a choropleth covid map with different symbology with a button selector. problem I have is I can’t achieve different symbology.
Thanks in advance!
Here’s what I have so far:
df= pd.read_csv (covid.csv)
data=dict(type=‘choropleth’,
locations = df[‘Name’],
locationmode = ‘country names’,
z = df[‘Total’] # I believe here is my problem if I do z=[‘total’, ‘1M_pop’] I lost data
marker_line_color = ‘black’,
marker_line_width = 0.5,
)
layout=dict(title_text = ‘Cases today by country’,
title_x = 0.5,
geo=dict(
showframe = True,
showcoastlines = True,
projection_type = ‘mercator’
)
)
map=go.Figure( data=[data], layout =layout)
#buttons test
fig[“layout”]
fig[“layout”].pop(“updatemenus”)
fig.update_geos(fitbounds=“locations”, visible=True)
button1 = dict(method = “restyle”,
args = [{‘z’: [ df[“Total”] ] }, [“colorscale”, “Greens”]],
label = “Total Cases”)
button2 = dict(method = “restyle”,
args = [{‘z’: [ df[“1M_pop”] ]},[“colorscale”, “reds”]],
label = “Cases per 1M”)
fig.update_layout(width=1000,
coloraxis_colorbar_thickness=23,
updatemenus=[dict(y=1.1,
x=0.275,
xanchor=‘right’,
yanchor=‘bottom’,
active=0,
buttons=[button1, button2])
])
plot(fig, filename=‘covid.html’)```
[plotly][1]
[1]: https://i.stack.imgur.com/BV3gh.png
have plugged in OWID data to make it re-producable. Additionally you quotes and double-quotes were unusable so had to change to standard quote
I could get changes in z to work in updatemenus. Getting colorscale to work was not working
switched techniques, generate two similar traces then use updatemenus to control visibility
import requests, io
import pandas as pd
import plotly.graph_objects as go
# df= pd.read_csv (covid.csv)
df = pd.read_csv(
io.StringIO(
requests.get(
"https://raw.githubusercontent.com/owid/covid-19-data/master/public/data/latest/owid-covid-latest.csv"
).text
)
)
df = df.rename(
columns={
"location": "Name",
"total_cases": "Total",
"total_cases_per_million": "1M_pop",
}
)
data = dict(
type="choropleth",
locations=df["Name"],
colorscale="reds",
locationmode="country names",
z=df[
"Total"
], # I believe here is my problem if I do z=['total', '1M_pop'] I lost data
marker_line_color="black",
marker_line_width=0.5,
)
layout = dict(
title_text="Cases today by country",
title_x=0.5,
geo=dict(showframe=True, showcoastlines=True, projection_type="mercator"),
)
fig = go.Figure(
data=[
data,
{**data, **{"z": df["1M_pop"], "colorscale": "blues", "visible": False}},
],
layout=layout,
)
# buttons test
fig["layout"]
fig["layout"].pop("updatemenus")
fig.update_geos(fitbounds="locations", visible=True)
button1 = dict(
method="update",
args=[{"visible": [True, False]}],
label="Total Cases",
)
button2 = dict(
method="update",
args=[{"visible": [False, True]}],
label="Cases per 1M",
)
fig.update_layout(
width=1000,
coloraxis_colorbar_thickness=23,
updatemenus=[
dict(
y=1.1,
x=0.275,
xanchor="right",
yanchor="bottom",
active=0,
buttons=[button1, button2],
)
],
)
fig
Related
I'm new in using plotly and I'm trying to make a 2 different graph and show them individually through button; however, when I make it, the legends duplicated, resulting to a bad visualization of the data. Here's the code that I'm running right now:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import plotly as ply
import plotly.express as px
import plotly.graph_objects as go
url = "https://raw.githubusercontent.com/m23chaffee/DS100-Repository/main/Aluminum%20Alloy%20Data%20Set.csv"
alloy = pd.read_csv('https://raw.githubusercontent.com/m23chaffee/DS100-Repository/main/Aluminum%20Alloy%20Data%20Set.csv')
del alloy['temper']
alloy = alloy.rename(columns={'aluminum_alloy':'Alloy Number',
'modulus_elastic': 'Elastic Modulus',
'modulus_shear': 'Shear Modulus',
'strength_yield': 'Yield Strength',
'strength_tensile': 'Tensile Strength'
})
bar1 = px.bar(alloy,
x = "Alloy Number",
y = ["Elastic Modulus", "Shear Modulus","Yield Strength","Tensile Strength"],
barmode = 'group',
width = 1100,
height =500,
orientation = 'v',
color_discrete_sequence = px.colors.qualitative.Pastel,
labels={"value": "Data Values"},
template = 'seaborn').update_traces(legendgroup="group").update_layout(showlegend=False)
line1 = px.line(alloy,
x = "Alloy Number",
y = ["Elastic Modulus", "Shear Modulus","Yield Strength","Tensile Strength"],
width = 1100,
height =500,
orientation = 'v',
color_discrete_sequence = px.colors.qualitative.Pastel,
labels={"value": "Data Values"},
template = 'seaborn').update_traces(legendgroup="group", visible = 'legendonly').update_layout(showlegend=False)
# Add buttom
fig.update_layout(
updatemenus=[
dict(
type = "buttons",
direction = "left",
buttons=list([
dict(
args=['type', 'bar'],
label="Bar Graph",
method="restyle",
),
dict(
args=["type", "line"],
label="Line Graph",
method="restyle"
)
]),
pad={"r": 10, "t": 10},
showactive=True,
x=0.11,
xanchor="left",
y=1.1,
yanchor="middle"
),
]
)
fig.show()
and the result of the image would look like this:
Result of the code above
Attempted Solution
I tried to hide it using traces and in the documentation but it seems it didn't work out for me. I also found a similar stackoverflow post 8 years ago, tried it, and it didn't make any changes in my graph.
I want to change the dropdown button with an input box so I can search for the item by starting to type the name and then select. So far I have a drop down box where you can select either one item or all of them at the same time. However, I want the user to be able to start typing the name of the item and then click and select the item they want to display their graph.
As I am new to plotly, any suggestion is very welcome and appreciated :)
Here is what the plot looks like so far:
My code:
def interactive_multi_plot(actual, forecast_1, forecast_2, title, addAll = True):
fig = go.Figure()
for column in forecast_1.columns.to_list():
fig.add_trace(
go.Scatter(
x = forecast_1.index,
y = forecast_1[column],
name = "Forecast_SI"
)
)
button_all = dict(label = 'All',
method = 'update',
args = [{'visible': forecast_1.columns.isin(forecast_1.columns),
'title': 'All',
'showlegend':True}])
for column in forecast_2.columns.to_list():
fig.add_trace(
go.Scatter(
x = forecast_2.index,
y = forecast_2[column],
name = "Forecast_LSTM"
)
)
button_all = dict(label = 'All',
method = 'update',
args = [{'visible': forecast_2.columns.isin(forecast_2.columns),
'title': 'All',
'showlegend':True}])
for column in actual.columns.to_list():
fig.add_trace(
go.Scatter(
x = actual.index,
y = actual[column],
name = "True values"
)
)
button_all = dict(label = 'All',
method = 'update',
args = [{'visible': actual.columns.isin(actual.columns),
'title': 'All',
'showlegend':True}])
fig.layout.plot_bgcolor = '#010028'
fig.layout.paper_bgcolor = '#010028'
def create_layout_button(column):
return dict(label = column,
method = 'update',
args = [{'visible': actual.columns.isin([column]),
'title': column,
'showlegend': True}])
fig.update_layout(
updatemenus=[go.layout.Updatemenu(
active = 0,
buttons = ([button_all] * addAll) + list(actual.columns.map(lambda column: create_layout_button(column)))
)
]
)
# Update remaining layout properties
fig.update_layout(
title_text=title,
height=800,
font = dict(color='#fff', size=12)
)
fig.show()
This is the error I receive:
small changes to interactive_multi_plot().
for all three add_trace() add meta = column for each of the scatter creations
change to return fig instead of fig.show()
simulate some data and call interactive_multi_plot(). I have assumed all three data frames have the same columns
S = 100
C = 10
actual = pd.DataFrame(
{
c: np.sort(np.random.uniform(0, 600, S))
for c in [
f"{a}{b}-{c}"
for a, b, c in zip(
np.random.randint(100, 200, C),
np.random.choice(list("ABCDEF"), C),
np.random.randint(300, 400, C),
)
]
}
)
f1 = actual.assign(**{c:actual[c]*1.1 for c in actual.columns})
f2 = actual.assign(**{c:actual[c]*1.2 for c in actual.columns})
fig = interactive_multi_plot(actual, f1, f2, "Orders")
solution
use dash this does support interactive drop downs
simple case of show figure and define a callback on item selected from dash drop down
it could be considered that updatemenus is now redundant. I have not considered sync of updatemenus back to dash drop down
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
from jupyter_dash import JupyterDash
# Build App
app = JupyterDash(__name__)
app.layout = html.Div(
[
dcc.Dropdown(
id="lines",
options=[{"label": c, "value": c} for c in ["All"] + actual.columns.tolist()],
value="All",
),
dcc.Graph(id="interactive-multiplot", figure=fig),
]
)
#app.callback(
Output("interactive-multiplot", "figure"),
Input("lines", "value"),
State("interactive-multiplot", "figure"),
)
def updateGraphCB(line, fig):
# filter traces...
fig = go.Figure(fig).update_traces(visible=False).update_traces(visible=True, selector={"meta":line} if line!="All" else {})
# syn button to dash drop down
fig = fig.update_layout(updatemenus=[{"active":0 if line=="All" else actual.columns.get_loc(line)+1}])
return fig
app.run_server(mode="inline")
Using Python/Plotly, I'm trying to create a figure that has a map and a slider to choose the year. Depeding on the year that is selected in the slider, the map should render different results.
Evertyhing is working fine with exception for one thing - I cannot set the initial load state of the map to be the same as the initial step as defined in
sliders = [dict(active=0, pad={"t": 1}, steps=steps)]
When the first render is done, and the slider has not yet been used, the data displayed seems to be accordingly to the last state of the data_slider list, ie. it shows the last values that were loaded in the list (I'm not totally sure about this conclusion).
Is there a way to set the first data display accordingly to the step that is pre-defined? Or in alternative, a way to force the first load to be something like data_slider[0].
Below is the code I'm using.
import pandas as pd
import os
import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objects as go
import numpy as np
import random
ds = 'https://archive.org/download/globalterrorismdb_0718dist/globalterrorismdb_0718dist.csv'
# ds = os.getcwd() + '\globalterrorismdb_0718dist.csv'
fields = ['eventid', 'iyear', 'country', 'country_txt', 'region_txt', 'city', 'latitude', 'longitude', 'nkill']
df = pd.read_csv(ds, encoding='ISO-8859-1', usecols=fields)
df = df.loc[df['iyear'] >= 2000]
df['nkill'].fillna(0, inplace=True)
df = df.groupby(['country_txt', 'iyear'])['nkill'].sum().reset_index()
df = df.loc[df['nkill'] > 0]
data_slider = []
for year in df.iyear.unique():
df_year = df[(df['iyear'] == year)]
data_year = dict(
type='choropleth',
name='',
colorscale='amp',
locations=df_year['country_txt'],
z=df_year['nkill'],
zmax=15000,
zmin=0,
locationmode='country names',
colorbar=dict(
len=0.5,
thickness=10,
title=dict(
text='Number of fatalities',
font=dict(
family='Arial',
size=14,
),
side='right'
),
tickfont=dict(
family='Arial',
size=12),
)
)
data_slider.append(data_year)
steps = []
for i in range(len(data_slider)):
step = dict(
method='restyle',
args=['visible', [False] * len(data_slider)],
label=(format(i + 2000))
)
step['args'][1][i] = True
steps.append(step)
sliders = [dict(active=0, pad={"t": 1}, steps=steps)]
layout = dict(
geo=dict(
scope='world',
showcountries=True,
projection=dict(
type='equirectangular'
),
showland=True,
landcolor='rgb(255, 255, 255)',
showlakes=False,
showrivers=False,
showocean=True,
oceancolor='white',
),
sliders=sliders
)
fig = go.Figure(data=data_slider, layout=layout)
fig.update_layout(
font=dict(family='Arial', size=12),
autosize=False,
width=1250,
height=750,
margin=dict(
l=25,
r=0,
b=100,
t=50,
pad=0,
)
)
app = dash.Dash(__name__)
server = app.server
app.layout = html.Div(children=[
# html.H1(children='Test2'),
# html.Div(children='''
# Example of html Container
# '''),
dcc.Graph(
id='fig',
figure=fig
)
])
if __name__ == '__main__':
app.run_server(debug=True)
The problem here is not on sliders but on the traces you are defining in data_slider. You need to play with the visible parameter in order to have the first plot properly rendered. The following trick should work.
data_slider = []
for i, year in enumerate(df.iyear.unique()):
df_year = df[(df['iyear'] == year)]
data_year = dict(
type='choropleth',
name='',
colorscale='amp',
locations=df_year['country_txt'],
z=df_year['nkill'],
zmax=15000,
zmin=0,
locationmode='country names',
visible= True if i==0 else False,
colorbar=dict(
len=0.5,
thickness=10,
title=dict(
text='Number of fatalities',
font=dict(
family='Arial',
size=14,
),
side='right'
),
tickfont=dict(
family='Arial',
size=12),
)
)
data_slider.append(data_year)
Extra
Given that you are generating all the plots outside the app you could actually avoid to use dash.
I have three separated datasets of stocks/indexes. I can plot them one by one with PlotLy. But I want to create a button or dropdown menu that will allow me to switch the datasets from it.
Every dataset looks like this:
open high low close volume
Date
2015-08-06 5146.63 5149.93 5035.41 5056.44 2290950000
2006-08-16 2127.06 2149.54 2120.11 2149.54 2474760000
1995-06-19 909.90 922.09 909.84 922.09 407000000
2009-10-19 2162.41 2180.11 2150.42 2176.32 1970440000
1997-05-23 1377.73 1389.75 1377.73 1389.72 539440000
Below is my code. But I don't know where to put the three datasets that will substitute "df". I was thinking of something like a list of datasets maybe but I am not used to working with python. I would appreciate some help.
I want the button or the drop-down menu to change between df = [msft_data, spy_500, nasdaq]
def plot_interactive_stock_data(title):
fig = go.Figure()
fig_high = go.Scatter(x=df.index, y=df['high'], name="high ($)",
line_color='deepskyblue')
fig_low = go.Scatter(x=df.index, y=df['low'], name="low ($)",
line_color='green')
fig_open = go.Scatter(x=df.index, y=df['open'], name="open ($)",
line_color='maroon')
fig_close - go.Scatter(x=df.index, y=df['close'], name="close ($)",
line_color='orange')
fig_volume = go.Scatter(x=df.index, y=df['volume'], name="volume",
line_color='brown')
fig.update_layout(title_text='{}'.format(title),
xaxis_rangeslider_visible=True)
data = [fig_high, fig_low, fig_open, fig_close, fig_volume]
updatemenus = list([
dict(active = -1,
buttons = list([
dict(label = 'Microsoft',
method = 'update',
args = {'visible': [True, False, False]}),
dict(label = 'S&P 500',
method = 'update',
args = {'visible': [False, True, False]}),
dict(label = 'Nasdaq',
method = 'update',
args = {'visible': [False, False, True]})
]),
)
])
layout = dict(title=title, showlegend = False,
updatemenus = updatemenus)
fig = dict(data=data, layout=layout)
plotly.offline.plot(fig, auto_open=False, show_link=False)
I have found an answer which is not perfect but still, the code does what I wanted it to do. I have used information from plotly and from stackoverflow. Switching between datasets is very slow though. So I would appreciate it if somebody can show me a better solution.
Below is the code for the plot function:
def plot_data(df):
fig = go.Figure()
fig.add_trace(go.Scatter(
x=df.index,
y=df['open'],
name="Open",
line_color='blueviolet',
opacity=0.8))
fig.add_trace(go.Scatter(
x=df.index,
y=df['high'],
name="High",
line_color='green',
opacity=0.8))
fig.add_trace(go.Scatter(
x=df.index,
y=df['low'],
name="Low",
line_color='red',
opacity=0.8))
fig.add_trace(go.Scatter(
x=df.index,
y=df['close'],
name="Close",
line_color='darkkhaki',
opacity=0.8))
fig.add_trace(go.Scatter(
x=df.index,
y=df['volume'],
name="Volume",
line_color='darkgoldenrod',
opacity=0.8))
fig.add_trace(go.Scatter(
x=df.index,
y=df['dividends'],
name="Dividends",
line_color='brown',
opacity=0.8))
fig.add_trace(go.Scatter(
x=df.index,
y=df['stock_splits'],
name="Stock splits",
line_color='brown',
opacity=0.8))
fig.update_layout(title_text='Explore data',
xaxis_rangeslider_visible=True)
fig.show()
This is the code for the drop-down menu:
#interact(control=widgets.Dropdown(
options=["msft_data",
"spy_500",
"nasdaq"
],
description='Datasets'))
def plot_df(control):
plt.figure(figsize = (14,8), linewidth=3, frameon = False)
data = eval(control)
plot_data(data)
You can see the image of my work too:
I'm new in Plotly. I'm trying to draw a choropleth map with this tool. I have my data in a database and I'm trying to show some of them in a map.
First, I launch my das application : app = dash.Dash()
Once I'm connected to the database, I execute the following code:
#Load dataframes
df = pd.read_sql('SELECT * FROM Companies_Public', con=db_connection)
#Choropleth map
app.layaout = html.Div([
dcc.Graph(
id = 'Map',
figure={
'data': [ dict(
type = 'choropleth',
locations = df['ISOCountry'],
z = sum(df['FinalPointsPerDemography']),
text = df['CountryName'],
colorscale = [[0,"rgb(5, 10, 172)"],[0.35,"rgb(40, 60, 190)"],[0.5,"rgb(70, 100, 245)"],\
[0.6,"rgb(90, 120, 245)"],[0.7,"rgb(106, 137, 247)"],[1,"rgb(220, 220, 220)"]],
autocolorscale = False,
reversescale = True,
marker = dict(
line = dict (
color = 'rgb(180,180,180)',
width = 0.5
) ),
colorbar = dict(
autotick = False,
tickprefix = '$',
title = 'Points<br>'),
) ],
'layout': go.Layout(
title = 'Points by Company per Demography',
geo = dict(
showframe = False,
showcoastlines = False,
projection = dict(
type = 'Mercator'
)
)
)
}
)
])
# Add the server clause:
if __name__ == '__main__':
app.run_server()
I get the next message in the console:
dash.exceptions.NoLayoutException: The layout was None at the time that run_server was called. Make sure to set the layout attribute of your application before running the server.
The following figure shows the structure of df:
df structure