Related
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
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")
I am pretty new to dash and I have tried to read as much as I can to understand what the issue might be. In a nutshell I have a single datepicker which is an input to the DataTable and Graph callback. The graph callback is working fine so it is just the DataTable which is causing problems. I also tried the single input to multiple output callback but didnt work. My code is as below:
app = JupyterDash()
folder = os.getcwd()
portfolio_returns_table = pd.read_csv(Path(folder, 'portfolioreturns_maria.csv',parse_dates=[0]))
portfolio_returns_table = portfolio_returns_table.set_index('Unnamed: 0')
name_portfolioID_table = pd.read_csv(Path(folder, 'name_portfolioID.csv'))
#Calculate portfolio cumulative returns
df_cumret = (portfolio_returns_table+1).cumprod().round(5)
df_cumret.index = pd.to_datetime(df_cumret.index)
app.layout = html.Div(html.Div([dcc.DatePickerSingle(
id='my-date-picker-single',
min_date_allowed=dt.date(df_cumret.index.min()),
max_date_allowed=dt.date(df_cumret.index.max()),
initial_visible_month=dt.date(df_cumret.index.max()),
date = dt.date(df_cumret.index.max())
,display_format = 'Y-MM-DD',clearable = True),
html.Div(id='output-container-date-picker-single'),
html.Div(dash_table.DataTable(id = 'data_table',
data = {},
fixed_rows={'headers': True},
style_cell = {'textAlign': 'left'},
style_table={'height': 400})),
html.Div(dcc.Graph('my_graph'))
]))
#app.callback([Output('data_table','data'),Output('data_table','columns')],
[Input('my-date-picker-
single','date')])
def update_leader_table(date):
#Get data for the selected date and transpose
df_T = df_cumret.loc[[date]].T
#Sort the table to reveal the top leaders
df_Top = df_T.sort_values(df_T.columns[0], ascending=False)[:10]
#Convert the index to an interger
df_Top.index = df_Top.index.astype(int)
#Generate the leaderboard to given date
df_leader = pd.merge(df_Top,name_portfolioID_table,
left_index=True,right_index=True, how = 'left')
#Create the col rank
df_leader['Rank'] = range(1,len(df_leader)+1)
df_leader.columns = ['Cum Return', 'Investor','Rank']
df_leader.reset_index(drop = True, inplace = True)
data = df_leader.to_dict('records')
columns= [{'id': c, 'name': c, "selectable": True} for c in
df_leader.columns]
return (data,columns)
#callback to link calendar to graph
#app.callback(Output('my_graph','figure'),[Input('my-date-picker-single','date')])
def update_graph(date):
#date filter
df_T = df_cumret.loc[:date].T
#Sort the table to reveal the top leaders & filter for leaderboard
df_Top = df_T.sort_values(df_T.columns[-1], ascending=False)[:10]
#Transpose to have date as index
df_top_graph = df_Top.T
#set the columns as an Int
df_top_graph.columns = df_top_graph.columns.astype(int)
#Rename columns
df_top_graph.rename(columns=dict(zip(name_portfolioID_table.index,
name_portfolioID_table.name)),
inplace=True)
#Generate graph
fig = px.line(df_top_graph, x = df_top_graph.index, y =
df_top_graph.columns, title='ETF LEADERBOARD PERFORMANCE: '+date, labels=
{'Unnamed: 0':'Date','value':'Cumulative Returns'})
fig.update_layout(hovermode = 'x unified')
fig.update_traces(hovertemplate='Return: %{y} <br>Date: %{x}')
fig.update_layout(legend_title_text = 'Investor')
return fig
if __name__ == '__main__':
app.run_server(mode = 'inline',debug=True, port = 65398)
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
I'm trying to create a plotly graph with a Scatter and Graph elements. It all goes nicely, but one issue - the two Y axis don't align around 0.
I have tried playing with different attributes, such as 'mirror' and tick0, I also tried following the examples on plotly's site, but it's mostly multiple y-axis with the same graph type.
What can I do to fix this?
import utils
import pandas as pd
import plotly.plotly as py
import plotly.graph_objs as go
import plotly
pd_data ['dt'] = ... dates
pd_data['price'] = ... prices
pd_data['car'] = ... cars
price = go.Scatter(
x = pd_data['dt'],
y = pd_data['price'],
mode = 'lines',
name = 'Price',
xaxis = 'x',
yaxis='y1',
marker = dict(
color = utils.prep_color_string('orange'),
),
line = dict(
width = utils.line_width,
),
)
car = go.Bar(
x = pd_data['dt'],
y = pd_data['car'],
#mode = 'lines',
name = 'Cars',
xaxis = 'x',
yaxis='y2',
marker = dict(
color = utils.prep_color_string('light_green'),
),
#line = dict(
# width = utils.line_width,
#),
)
data = [price, car]
layout = dict(
title = 'Price/Car',
geo = dict(
showframe = True,
showcoastlines = True,
projection = dict(
type = 'Mercator'
)
),
yaxis=dict(
title = 'Price',
tickprefix = "$",
overlaying='y2',
anchor = 'x'
),
yaxis2=dict(
title = 'Car',
dtick = 1,
#tickprefix = "",
side = 'right',
anchor = 'x',
),
)
fig = dict( data=data, layout=layout)
div = plotly.offline.plot( fig, validate=False, output_type = 'file',filename='graph.html' ,auto_open = False)
I have been struggling with this as well. Exact same problem, but I am using R. The way I figured around it was to use the rangemode="tozero" for both the yaxis and yaxis2 layouts.
I think in your case, it would look like this:
layout = dict(
title = 'Price/Car',
geo = dict(
showframe = True,
showcoastlines = True,
projection = dict(
type = 'Mercator'
)
),
yaxis=dict(
title = 'Price',
tickprefix = "$",
overlaying='y2',
anchor = 'x',
rangemode='tozero'
),
yaxis2=dict(
title = 'Car',
dtick = 1,
#tickprefix = "",
side = 'right',
anchor = 'x',
rangemode = 'tozero'
),
)
Let me know if that works for you.