How to change plots of several datasets with Plotly button? - python

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:

Related

Hiding Duplicate Legend in Plotly

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.

Changing choropleth symbology with drop down # plotly

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

Plotly: Added title to colorbar but not able to see on plot

I have tried to add title to colorbar but not able to see on plot.
Code:
fig = go.Figure(go.Scatter(
x=df['Date'],
y = df["GC1"],
mode='markers',
# showlegend = True,
hovertext=df['MM_ln'],
hoverlabel=dict(namelength=0),
hovertemplate='%{hovertext}<br>Date: %{x} <br>MM_l: %{y}',
marker=dict(
size=df["GC1"]*0.01,
color=df["MM_l_cc"], #set color to MM_l_cc
colorscale='Viridis', # one of plotly colorscales
showscale=True,
)
))
# fig.layout.coloraxis.colorbar.title = 'Title'
fig.update_layout(
title='Positioning price concentration MM_l',
xaxis_title='Weekly observations',
yaxis_title='Gold price',
meta=dict(colorbar=dict(title="Title"))
)
# fig.layout.coloraxis.colorbar.title = 'another title'
fig.show()
Ouput:
Where is the mistake? How to solve this? Can anyone please suggest?
You can include it in go.Scatter() like so
import plotly.graph_objects as go
fig = go.Figure(data=go.Scatter(colorbar={"title": "Your title"},
z=[[1, 20, 30],
[20, 1, 60],
[30, 60, 1]]))
fig.show()
or you can include it in the layout update like so
fig.update_layout(
coloraxis_colorbar=dict(
title="Your Title",
),
)
I was able to see the title, after adding colorbar inside marker in my code as
marker=dict(
...
colorbar={"title": "Your title"},
)

Show the label for only a specific point in a Plotly graph?

For instance, with this example from the Plotly documentation
import plotly.express as px
df = px.data.gapminder().query("year==2007 and continent=='Americas'")
fig = px.scatter(df, x="gdpPercap", y="lifeExp", text="country", log_x=True, size_max=60)
fig.update_traces(textposition='top center')
fig.update_layout(
height=800,
title_text='GDP and Life Expectancy (Americas, 2007)'
)
fig.show()
I'm searching for a way to show only the label for a specified point, say, only 'Peru' in this case.
Any help appreciated, thank you!
You can always edit the text attribute for fig.data[0] like this:
fig.data[0].text = [e if e == 'Peru' else '' for e in fig.data[0].text]
And get:
The downside here is that this will remove country names from the hoverlabel for all other countries:
So I would rather subset the data for the country you would like to highlight and use fig.add_annotation() like this:
df2 = df[df['country'] == 'Peru']
fig.add_annotation(x=np.log10(df2['gdpPercap']).iloc[0],
y=df2["lifeExp"].iloc[0],
text = df2["country"].iloc[0],
showarrow = True,
ax = 10,
ay = -25
)
And get:
Complete code:
import plotly.express as px
import numpy as np
df = px.data.gapminder().query("year==2007 and continent=='Americas'")
fig = px.scatter(df, x="gdpPercap", y="lifeExp",
# text="country",
log_x=True, size_max=60)
fig.update_traces(textposition='top center')
fig.update_layout(
height=800,
title_text='GDP and Life Expectancy (Americas, 2007)'
)
df2 = df[df['country'] == 'Peru']
fig.add_annotation(x=np.log10(df2['gdpPercap']).iloc[0],
y=df2["lifeExp"].iloc[0],
text = df2["country"].iloc[0],
showarrow = True,
ax = 10,
ay = -25
)
# f = fig.full_figure_for_development(warn=False)
fig.show()

Plotly Dash: Render a Graph only if certain data in a Pandas DataFrame exists

I currently use Plotly Dash to create a webapp to visualize data.
The syntax involves using dcc.Graph to render an HTML Div as follows. Below the html.Div is the code to render the plot figure. The x and y axis values come from a Pandas DF.
Can anyone recommend a way to use an IF statement to check if a given column exists and then proceed to return the following code.
Plotly Dash gives an error when a 'fig' variable does not exist
html.Div([
html.Div([
html.H3('Chart'),
dcc.Graph(id='Chart',figure = chart_fig
)
sensor3_trace_day1 = Scatter(
y = sensor_3_day1['BG Calibration (mg/dl)'],
x = sensor_3_day1['Current (nA)'],
mode = 'markers',
name = 'Sensor 3 Day 1'
)
data = [sensor1_trace]
layout = Layout(showlegend=True, height = 600, width = 600, title='Day 1: BG Cal vs Current',xaxis={'title':'Current [nA]'},yaxis={'title':'BG Calibration (mg/dl)'})
chart_fig = dict(data=data, layout=layout)
iplot(chart_fig)
Another possible solution is to create a callback and show an empty plot, under certain conditions.
This example is very similar to the one by #lwileczek
def empty_plot(label_annotation):
'''
Returns an empty plot with a centered text.
'''
trace1 = go.Scatter(
x=[],
y=[]
)
data = [trace1]
layout = go.Layout(
showlegend=False,
xaxis=dict(
autorange=True,
showgrid=False,
zeroline=False,
showline=False,
ticks='',
showticklabels=False
),
yaxis=dict(
autorange=True,
showgrid=False,
zeroline=False,
showline=False,
ticks='',
showticklabels=False
),
annotations=[
dict(
x=0,
y=0,
xref='x',
yref='y',
text=label_annotation,
showarrow=True,
arrowhead=7,
ax=0,
ay=0
)
]
)
fig = go.Figure(data=data, layout=layout)
# END
return fig
# Layout
html.Div([
html.Div([
# Here it goes the dropdown menu
# ....
# The graph is defined below
html.H3('Chart'),
dcc.Graph(id='chart')
]),
])
# Callback
#app.callback(Output('chart','figure'),
[Input('dropdown','value')])
def update_fig(drop_val):
if drop_val in df.columns:
# fig = (...) Here it goes your figure
else:
fig = empty_plot('Nothing to display') # Here it goes the empty plot
return fig
What you can do is use two different #app.callbacks(). The first would return a figure and the second would return a "style" dictionary for the dcc.Graph() object. If the figure is empty you don't want to show the div. If you have a dropdown or a button that you use to update the information i.e. read in/ create the dataframe you can use that as input for your callbacks. For example:
html.Div([
html.Div([
html.H3('Chart'),
dcc.Graph(id='chart')
]),
])
#app.callback(Output('chart','figure'),
[Input('dropdown','value')])
def update_fig(drop_val):
if "col" in df.columns:
fig = {'data':data,'layout':layout}
else:
fig = {'data':[],'layout':layout}
return fig
#app.callback(Output('chart','style'),
[Input('dropdown','value')])
def update_style(drop_val):
if "col" in df.columns:
style = {'borderStyle':solid,'display':'inline-block'}
else:
style = {'display':'none'}
return style
In this case I have some imaginary dropdown that may flip between which df is being read in or something and then outputs the display and a figure each time. It must return a workable figure no matter what so make up
data = [{'x':[1,2,4], 'y':[4,5,6], 'type':'bar'}]
or something similar and just set display to "none" so it wont be rendered.

Categories