Python - Plotly - dynamic y-axis selection on a multiple axes plot - python

I have a dataframe of multiple columns, each containing a time series. I want to compare two time series plots at a time, for which I am plotting them overlayed with two y-axes as given in the example here: https://plot.ly/python/multiple-axes/#two-y-axes
My problems are:
I want plotly to let the user select only two traces at a time,
dynamically change and adjust the y-axis based on which trace is selected/un-selected
Building on the example given in the link above:
import plotly
import plotly.plotly as py
import plotly.graph_objs as go
trace1 = go.Scatter(x=[1, 2, 3],y=[40, 50, 60],name='yaxis data')
trace2 = go.Scatter(x=[2, 3, 4],y=[4, 5, 6],name='yaxis2 data',yaxis='y2')
trace3 = go.Scatter( x=[3, 4, 5],y=[400, 500, 600],name='yaxis3 data', yaxis='y2', visible = 'legendonly')
data = [trace1, trace2, trace3]
layout = go.Layout(
title='Double Y Axis Example',
yaxis=dict(
title='yaxis title'
),
yaxis2=dict(
title='yaxis2 title',
titlefont=dict(
color='rgb(148, 103, 189)'
),
tickfont=dict(
color='rgb(148, 103, 189)'
),
overlaying='y',
side='right'
)
)
fig = go.Figure(data=data, layout=layout)
plotly.offline.plot(fig)
So plotly should let the user choose only two traces at a time to be visible on the plot, and dynamically put the next selected trace on the available y-axis side.
For example if 'yaxis data' and 'yaxis2 data' are visible, the user has to unselect either of those before selecting 'yaxis3 data' from the legends. So if the user unselects 'yaxis data' which is on the left hand side of the plot, 'yaxis3 data's y-axis labels should go on the left hand side. IF the user had unselected 'yaxis2 data', the new data would go on the right hand side.
I want the yaxis= 'y' or 'y2' to be assigned through the interactive session. I dont know how to achieve that.

Related

Adjusting the plotly colorbar for each subplot according to their min and max

I wanted to find out how to have three different colorbars for my plotly 3 subplots and be able to adjust each of the three colorbars according to their min and max. (attached snapshot).
Does anyone know how to have each colorbar on the right side of each subplot?
Also, for some reasons, the plot sizes are not perfect and they dont appear with the subtitles specified in the code!
Lastly, I wonder if there is a way to synchronize the subplots together so that when we zoom in or out on each of the subplots, they all move together.
This is a sample of my code:
import pandas as pd
import plotly.graph_objects as go
from plotly.subplots import make_subplots
# load dataset
Real_df = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/volcano.csv")
Model_df = (df_1[np.random.default_rng(seed=42).permutation(df_1.columns.values)])
Error_df = pd.DataFrame(np.random.randint(0,5,size=(87, 61)), columns=df_2.columns)
# create figure
#fig = go.Figure()
# Add surface trace
fig = make_subplots(rows=1, cols=3,
specs=[[{'is_3d': True}, {'is_3d': True}, {'is_3d': True}]],
subplot_titles=['True', 'Model', 'Error Percentage'],
)
fig.add_trace(go.Surface(z=Real_df.values.tolist(), colorscale="jet"), 1, 1)
fig.add_trace(go.Surface(z=Model_df.values.tolist(), colorscale="jet"), 1, 2)
fig.add_trace(go.Surface(z=Error_df.values.tolist(), colorscale="jet"), 1, 3)
# Update plot sizing
fig.update_layout(
width=800,
height=900,
autosize=False,
margin=dict(t=0, b=0, l=0, r=0),
template="plotly_white",
)
# Update 3D scene options
fig.update_scenes(
aspectratio=dict(x=1, y=1, z=0.7),
aspectmode="manual"
)
fig.update_layout(1, 3, coloraxis={"cmin": 0, "cmax": 2})
fig.show()
To display a color bar for each subplot, the x-axis position must be set for each subplot. Also, for the subplot titles, the top margin is set to 0, which hides the text display area, so I set the top margin to 50. Finally, there does not seem to be a way to synchronize the zoom of the subplots at this time; the plotly community has mentioned synchronizing the camera viewpoint as an answer, but I am unsure if that is available in the current version.
import pandas as pd
import numpy as np
import plotly.graph_objects as go
from plotly.subplots import make_subplots
# load dataset
Real_df = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/volcano.csv")
Model_df = (Real_df[np.random.default_rng(seed=42).permutation(Real_df.columns.values)])
Error_df = pd.DataFrame(np.random.randint(0,5,size=(87, 61)), columns=Real_df.columns)
# Add surface trace
fig = make_subplots(rows=1, cols=3,
specs=[[{'is_3d': True}, {'is_3d': True}, {'is_3d': True}]],
subplot_titles=['True', 'Model', 'Error Percentage'],
)
fig.add_trace(go.Surface(z=Real_df.values.tolist(), colorscale="jet", colorbar_x=0.3), 1, 1)
fig.add_trace(go.Surface(z=Model_df.values.tolist(), colorscale="jet", colorbar_x=0.65), 1, 2)
fig.add_trace(go.Surface(z=Error_df.values.tolist(), colorscale="jet", colorbar_x=1.05, cmax=2, cmin=0), 1, 3)
# Update plot sizing
fig.update_layout(
width=2000,
height=900,
autosize=False,
margin=dict(t=50, b=0, l=0, r=0),
template="plotly_white",
)
# Update 3D scene options
fig.update_scenes(
aspectratio=dict(x=1, y=1, z=0.7),
aspectmode="manual"
)
fig.show()

Plotly ipwidgets with two Scattermapbox traces does not update the markers

i'm trying to make a simple widget that displays two points on a map together with a dropdown which allows you to select the case. On selecting a different case, different points are displayed on the map.
I initialise the map with the first case and on changing the value of the dropdown i update the data of the traces. The initial state works fine, but when i select a different case, the markes are not updated but the tooltip is updated and displayed in the right position.
Initial state
After changing the dropdown
the data i'm using looks like this
How do i force the traces to update the markers as well? I already tried updating the mode and marker properties of the Scattermapbox, that did not work.
I tried in a Jupyter notebook and in a Databricks notebook
Here is my example code:
from ipywidgets import widgets
import pandas as pd
import plotly.graph_objects as go
data = pd.DataFrame({"lat1":[46,48,47],"lon1":[13,11,13],"lat2":[45,47,46],"lon2":[12,10,12],"name":["aaa","bbb","ccc"],"info":[111,222,333]})
dropdown = widgets.Dropdown(
description='Case: ',
value=data['name'][0],
options=data['name'].unique().tolist()
)
one = go.Scattermapbox(
lat=[data['lat1'][0]],
lon=[data['lon1'][0]],
mode='markers+text',
marker=go.scattermapbox.Marker(
size=14
),
text=data[['name'][0]],
name = "one"
)
two = go.Scattermapbox(
lat=[data['lat2'][0]],
lon=[data['lon2'][0]],
mode='markers+text',
marker=go.scattermapbox.Marker(
size=14
),
text=data[['name','info'][0]],
name="two"
)
g = go.FigureWidget(data=[one, two],
layout=go.Layout(
title=dict(
text='Two traces'
),
mapbox = {
'center': {'lon': 13, 'lat': 46 },
'style': "stamen-terrain",
'zoom': 6},
width=1600,
height=900
))
def response(change):
temp_df = data[data['name']==dropdown.value]
with g.batch_update():
g.data[0].lat=temp_df['lat1']
g.data[0].lon=temp_df['lon1']
g.data[1].lat=temp_df['lat2']
g.data[1].lon=temp_df['lon2']
g.data[0].text=temp_df[['name']]
g.data[1].text=temp_df[['name','info']]
g.mode[0]='markers+text'
g.mode[1]='markers+text'
dropdown.observe(response, names="value")
widgets.VBox([dropdown,g])

Scroll between multiple subplots

i have a question regarding subplots.
i’m creating plots using this command:
figure = make_subplots(
rows=4,
cols=1,
shared_xaxes=True,
subplot_titles=("title1", "title2", "title3", "title4"),
vertical_spacing=0.1,
column_titles=[
f'title'
]
)
# then creating multiple candlestick graphs like this for each row:
figure.add_trace(
go.Candlestick(
x=inner_data.index,
open=inner_data['open'],
high=inner_data['high'],
low=inner_data['low'],
close=inner_data['close'],
name=f"{ticker} - INNER GRAPH"
),
row=row,
col=1
)
figure.show()
but because i have too many rows, the plots are shrinking a lot, and i cannot see anything.
is there a way to keep the size big, and create a scroll option in the page that opens up? i have not found it anywhere in the documentation…
thanks in advance,
Yaniv
A candlestick graph has been created using four stock prices. The display area can be changed by setting the graph height. The unit is pixels. Also, the range slider is not shown as an element that makes the graph area narrower. If necessary, change it to True. Since column titles and sub-titles are covered, the column titles are not set, but are changed to the overall title.
import yfinance as yf
tickers = "AAPL TSLA GOOG NFLX"
df = yf.download(tickers, start="2021-07-01", end="2022-07-01", group_by='ticker')
df = df.stack(0).reset_index().rename(columns={'level_1':'Ticker'})
from plotly.subplots import make_subplots
import plotly.graph_objects as go
figure = make_subplots(
rows=4,
cols=1,
shared_xaxes=True,
subplot_titles=tickers.split(' '),
vertical_spacing=0.1,
# column_titles=[
# f'title'
# ]
)
for row,ticker in enumerate(tickers.split(' ')):
inner_data = df[df['Ticker'] == ticker]
figure.add_trace(
go.Candlestick(
x=inner_data.index,
open=inner_data['Open'],
high=inner_data['High'],
low=inner_data['Low'],
close=inner_data['Close'],
name=f"{ticker} - INNER GRAPH"
), row=row+1, col=1
)
figure.update_layout(title='title',
autosize=True,
height=800,
)
figure.update_xaxes(rangeslider=dict(visible=False))
figure.show()

Is there a way to add a button that filters data set in plotly

I'm pretty new using plotly in python. I managed to plot a box chart with my dataframe in plotly like this:
box chart
The box plot shows the entire department's performance. I wish to add a few buttons that filter or narrow down the result. For example:
Team 1 button - filter on JH, DT, MB, SC
Team 2 button - filter on NP, DH, MZ, SB
Team 3 button - filter on KT, BL, SM,LW
and so on
I read through the plotly Figure reference (https://plotly.com/python/reference/layout/updatemenus/#layout-updatemenus-items-updatemenu-buttons-items-button-args)
and managed to add the buttons with args=["Claim_Handler"] where ["Claim_Handler"] is the column name in my dataframe. However the button does not perform any action when I click on it.
Where did I do wrong?
Here is the code for the graph:
fig2 = px.box(DF2, x='Claim_Handler', y='Days_to_close',hover_data=["Claim#"])
fig2.update_layout(
title='Average days to close for Claims Closed in last 5 years',
xaxis = dict(
rangeslider = dict(
visible=True,
thickness=0.05
)
),
yaxis = dict(
),
barmode='stack',
paper_bgcolor='#FFFFFF',
showlegend=True
)
fig2.update_layout(
updatemenus=[
dict(
type = "buttons",
direction = "left",
buttons=list([
dict(
args=["Claim_Handler"],
label="DH",
method="update"
),
dict(
args=["Claim_Handler"],
label="DT",
method="update"
)
])
),]
)
fig2.show(renderer="iframe")

Show name of a trace on scatterpolar chart all the time without needing to hover over it

I am trying to figure out if there is a way to have the name of a Python plotly scatterpolar trace to always be visible, rather than having to hover over each trace on the graph. This is what I have so far in terms of code.
import plotly.graph_objects as go
categories = ['Passing', 'Dribbling', 'Shooting', 'Defense', 'Fitness']
fig = go.Figure()
fig.add_traces(go.Scatterpolar(
r=[6.33, 3.71, 0, 5.45, 5],
theta=categories,
fill='toself',
name='Team Average'
))
fig.add_traces(go.Scatterpolar(
r=[9.38, 2.86, 0, 5.0, 5.6],
theta=categories,
fill='toself',
name='Player Average'
))
fig.update_layout(
polar=dict(
radialaxis=dict(
visible=False,
range=[0,10]
)
),
showlegend=False
)
fig.show()
And this is what the current scatterpolar chart looks like when I run it. As you can see, it does not show the names of each of the traces, and only appears when I hover over each trace.
With a go.Scatterpolar chart, text annotations are difficult because you will need to specify the cartesian x- and y-coordinates for the text annotations. Polar coordinates for text annotations inside the chart are not yet available, at least according to the linked Plotly forum post. While you could convert the polar coordinates of each point to x- and y-coordinates, and then add text at each of these locations, this seems like a heavy handed solution unless it's really necessary.
One compromise would be to use px.line_polar to draw the chart, and use the text argument to specify what text gets added for each point. Unfortunately you can only choose one field from your data (in your case, you can choose to display the value that you are passing to parameter r, or the category that you are passing to parameter theta).
To make px.line_polar look like go.Scatterpolar, you will want to add filling between the lines. In addition, to add the second px.line_polar chart on top of the first one, you'll need to create a new figure, then add that figure's data as a trace. You will also need to manually specify the color of the second px.line_polar chart.
import plotly.express as px
import plotly.graph_objects as go
categories = ['Passing', 'Dribbling', 'Shooting', 'Defense', 'Fitness']
fig = go.Figure()
fig = px.line_polar(
{'Team Average':[6.33, 3.71, 0, 5.45, 5], 'direction':categories},
r="Team Average",
theta="direction",
start_angle=360,
line_close=True,
text="Team Average",
)
fig2 = px.line_polar(
{'Player Average':[9.38, 2.86, 0, 5.0, 5.6], 'direction':categories},
r="Player Average",
color_discrete_sequence=["salmon"]*5,
theta="direction",
start_angle=360,
line_close=True,
text="Player Average",
)
## add fig2 to fig
fig.add_trace(fig2.data[0])
fig.update_traces(textposition='top center', fill='toself')
fig.update_layout(
polar=dict(
radialaxis=dict(
visible=False,
range=[0,10]
)
),
showlegend=False
)
fig.show()

Categories