code:
from plotly.offline import init_notebook_mode, iplot, iplot_mpl
def plot_train_test(train, test, date_split):
data = [Candlestick(x=train.index, open=train['open'], high=train['high'], low=train['low'], close=train['close'],name='train'),
Candlestick(x=test.index, open=test['open'], high=test['high'], low=test['low'], close=test['close'],name='test')
]
layout = {
'shapes': [
{'x0': date_split, 'x1': date_split, 'y0': 0, 'y1': 1, 'xref': 'x', 'yref': 'paper',
'line': {'color': 'rgb(0,0,0)', 'width': 1}}],
'annotations': [{'x': date_split, 'y': 1.0, 'xref': 'x', 'yref': 'paper', 'showarrow': False, 'xanchor': 'left','text': ' test data'},
{'x': date_split, 'y': 1.0, 'xref': 'x', 'yref': 'paper', 'showarrow': False, 'xanchor': 'right', 'text': 'train data '}] }
figure = Figure(data=data, layout=layout)
iplot(figure)
The above code is ok.But now I want to 'volume' in this candlestick chart
code:
from plotly.offline import init_notebook_mode, iplot, iplot_mpl
def plot_train_test(train, test, date_split):
data = [Candlestick(x=train.index, open=train['open'], high=train['high'], low=train['low'], close=train['close'],volume=train['volume'],name='train'),
Candlestick(x=test.index, open=test['open'], high=test['high'], low=test['low'],close=test['close'],volume=test['volume'],name='test')]
layout = {
'shapes': [
{'x0': date_split, 'x1': date_split, 'y0': 0, 'y1': 1, 'xref': 'x', 'yref': 'paper',
'line': {'color': 'rgb(0,0,0)', 'width': 1}}
],
'annotations': [
{'x': date_split, 'y': 1.0, 'xref': 'x', 'yref': 'paper', 'showarrow': False, 'xanchor': 'left',
'text': ' test data'},
{'x': date_split, 'y': 1.0, 'xref': 'x', 'yref': 'paper', 'showarrow': False, 'xanchor': 'right',
'text': 'train data '}
]
}
figure = Figure(data=data, layout=layout)
iplot(figure)
error:
ValueError: Invalid property specified for object of type
plotly.graph_objs.Candlestick: 'volume'
If you looking add smaller subplot of volume just below OHLC chart, you can use:
rows and cols to specify the grid for subplots.
shared_xaxes=True for same zoom and filtering
row_width=[0.2, 0.7] to change height ratio of charts. ie. smaller volume chart than OHLC
Plot:
import pandas as pd
import plotly.graph_objects as go
from plotly.subplots import make_subplots
# data
df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv')
# Create subplots and mention plot grid size
fig = make_subplots(rows=2, cols=1, shared_xaxes=True,
vertical_spacing=0.03, subplot_titles=('OHLC', 'Volume'),
row_width=[0.2, 0.7])
# Plot OHLC on 1st row
fig.add_trace(go.Candlestick(x=df["Date"], open=df["AAPL.Open"], high=df["AAPL.High"],
low=df["AAPL.Low"], close=df["AAPL.Close"], name="OHLC"),
row=1, col=1
)
# Bar trace for volumes on 2nd row without legend
fig.add_trace(go.Bar(x=df['Date'], y=df['AAPL.Volume'], showlegend=False), row=2, col=1)
# Do not show OHLC's rangeslider plot
fig.update(layout_xaxis_rangeslider_visible=False)
fig.show()
You haven't provided a complete code snippet with a data sample, so I'm going to have to suggest a solution that builds on an example here.
In any case, you're getting that error message simply because go.Candlestick does not have a Volume attribute. And it might not seem so at first, but you can easily set up go.Candlestick as an individual trace, and then include an individual go.Bar() trace for Volumes using:
fig = make_subplots(specs=[[{"secondary_y": True}]])
fig.add_traces(go.Candlestick(...), secondary_y=True)
fig.add_traces(go.Bar(...), secondary_y=False)
Plot:
Complete code:
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import pandas as pd
# data
df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv')
# Create figure with secondary y-axis
fig = make_subplots(specs=[[{"secondary_y": True}]])
# include candlestick with rangeselector
fig.add_trace(go.Candlestick(x=df['Date'],
open=df['AAPL.Open'], high=df['AAPL.High'],
low=df['AAPL.Low'], close=df['AAPL.Close']),
secondary_y=True)
# include a go.Bar trace for volumes
fig.add_trace(go.Bar(x=df['Date'], y=df['AAPL.Volume']),
secondary_y=False)
fig.layout.yaxis2.showgrid=False
fig.show()
Here is my improvement implementation based on the previous answer by Vestland, with some labelling and colouring improvements.
import plotly.graph_objects as go
from plotly.subplots import make_subplots
candlesticks = go.Candlestick(
x=candles.index,
open=candles['open'],
high=candles['high'],
low=candles['low'],
close=candles['close'],
showlegend=False
)
volume_bars = go.Bar(
x=candles.index,
y=candles['volume'],
showlegend=False,
marker={
"color": "rgba(128,128,128,0.5)",
}
)
fig = go.Figure(candlesticks)
fig = make_subplots(specs=[[{"secondary_y": True}]])
fig.add_trace(candlesticks, secondary_y=True)
fig.add_trace(volume_bars, secondary_y=False)
fig.update_layout(title="ETH/USDC pool after Uniswap v3 deployment", height=800)
fig.update_yaxes(title="Price $", secondary_y=True, showgrid=True)
fig.update_yaxes(title="Volume $", secondary_y=False, showgrid=False)
fig.show()
You can find the full source code in this open-source notebook.
If you want to add different colors for buy/sell isay 'green'/'red', you can use some libs (e.g. mplfinance) which do these automatically however the plots are non-interactive. To get interactive plot with plotly with separate colors for buy/sell colors, one needs to add trace for each data point. Here is code:
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import pandas as pd
# Create subplots and mention plot grid size
title=df.symbol.unique()[0]
fig = make_subplots(rows=2, cols=1, shared_xaxes=True,
vertical_spacing=0.02,
row_width=[0.25, 0.75])
# Plot OHLC on 1st row
fig.add_trace(go.Candlestick(x=df.index,
open=df['open'], high=df['high'],
low=df['low'], close=df['close'],showlegend=False),row=1, col=1,)
# Bar trace for volumes on 2nd row without legend
# fig.add_trace(go.Bar(x=df.index, y=df['volume'], showlegend=False), row=2, col=1)
df['color']=''
df['color']=['red' if (x>y) else t for x,y,t in zip(df['open'],df['close'],df['color'])]
df['color']=['green' if (x<y) else t for x,y,t in zip(df['open'],df['close'],df['color'])]
colors=df.color.tolist()
df['prev_color']=[colors[0]]+colors[:(len(colors)-1)]
df.loc[((df.open==df.close) & (df.color=='')),'color']=[z for x,y,z,t in zip(df['open'],df['close'],df['prev_color'],df['color']) if (x==y and t=='')]
colors=df.color.tolist()
df['prev_color']=[colors[0]]+colors[:(len(colors)-1)]
df.loc[((df.open==df.close) & (df.color=='')),'color']=[z for x,y,z,t in zip(df['open'],df['close'],df['prev_color'],df['color']) if (x==y and t=='')]
markers=['green','red']
for t in markers:
df_tmp=df.loc[~(df.color==t)] ## somehow the color it takes is opposite so take negation to
fig.add_trace(go.Bar(x=df_tmp.index, y=df_tmp['volume'], showlegend=False), row=2, col=1)
# Do not show OHLC's rangeslider plot
fig.update(layout_xaxis_rangeslider_visible=False)
fig.layout.yaxis2.showgrid=False
fig.update_layout(title_text=title,title_x=0.45)
fig.show()
My two cents on Plotting Volume in a different subplot with colors, it is just making #user6397960 response shorter without hacks to get the right color, just use marker_color. Think about it, what makes a candle green? The fact of having Close price above the Open price, and what about red candle? well, having a close price below the open price, so with this basics:
import plotly.graph_objects as go
from plotly.subplots import make_subplots
# Create a Figure with 2 subplots, one will contain the candles
# the other will contain the Volume bars
figure = make_subplots(rows=2, cols=1, shared_xaxes=True, row_heights=[0.7, 0.3])
# Plot the candles in the first subplot
figure.add_trace(go.Candlestick(x=df.index, open=df.open, high=df.high, low=df.low, close=df.close, name='price',
increasing_line_color='#26a69a', decreasing_line_color='#ef5350'),
row=1, col=1)
# From our Dataframe take only the rows where the Close > Open
# save it in different Dataframe, these should be green
green_volume_df = df[df['close'] > df['open']]
# Same for Close < Open, these are red candles/bars
red_volume_df = df[df['close'] < df['open']]
# Plot the red bars and green bars in the second subplot
figure.add_trace(go.Bar(x=red_volume_df.index, y=red_volume_df.volume, showlegend=False, marker_color='#ef5350'), row=2,
col=1)
figure.add_trace(go.Bar(x=green_volume_df.index, y=green_volume_df.volume, showlegend=False, marker_color='#26a69a'),
row=2, col=1)
# Hide the Range Slider
figure.update(layout_xaxis_rangeslider_visible=False)
figure.update_layout(title=f'BTC/USDT', yaxis_title=f'Price')
figure.update_yaxes(title_text=f'Volume', row=2, col=1)
figure.update_xaxes(title_text='Date', row=2)
References
https://plotly.com/python/subplots/
https://plotly.com/python/candlestick-charts/
Related
I had created the subplots in the seaborn. but not able to create same to same plots using plotly.
y1 = [-51.04464896560272, -50.891166658544364, -50.82896235500738,-47.93693115514636, -48.93693115514636, -50.2337317810911, -50.580211311328924, -49.63778008455918, -50.55143905012876, -47.18028476096273, -49.45950323726963, -52.759450409024325, -46.94239220924591, -49.34719404199133, -48.592737888881025, -50.39057938285388,-50.33666292445022,-49.689436282011854,-49.86872483079463, -49.47463251418676,-51.542982170986264, -50.650742675143576, -46.498494705109124, -69.232249295994,-65.83208484345344,-56.624359510655715, -64.65663405050996, -63.385051075806444, -61.4890501679952, -64.5215014815885]
y2 = [-49.22994660618851, -49.93693115514636,-47.48816812312157, -47.642008385846054, -49.24556971152835, -49.003594660143946, -49.92614593515235, -48.79589239042106, -49.90953636053393, -49.84547212502676, -48.83995760926475, -50.399185030856515, -47.98870212151289, -49.68206139796429, -48.82322978146867, -49.76209077328067, -48.3489893943433, -49.7807786904155, -51.025277583740525, -46.11152498485985, -17.51108674058229, -6.141613959880809, -107.74424733083552, 24.898229249313353, -27.273007692798586, -26.553484680185544, -38.6166124915005, -29.34043563361383, 31.648897538128374, 52.881233935942774]
t = [50.0,51.0,52.0,53.0,54.0,55.0,56.0,57.0,58.0,59.0,59.0,59.0,60.0,61.0, 59.0,63.0,64.0, 65.0, 66.0,67.0, 68.0,69.0, 70.0,71.0, 72.0, 73.0, 74.0, 75.0, 76.0, 77.0]
dd= ['0','50','79','80','88','95','0','50','79','80','88','95','0','50','79','80','88','95','88','95','79','80','50','79','95','0','50','88','88','95']
df = pd.DataFrame({'y1':y1,'y2':y2,'t':t,'dd':dd})
fig, axes = plt.subplots(2,1, sharex=True, figsize=(17,10))
sns.lineplot(ax=axes[0],hue='dd',x='t', y=y1, data=df, legend='full', ci=None)
sns.lineplot(ax=axes[1],hue='dd',x='t', y=y2, data=df, legend='full', ci=None)
plt.show();
I want same graph in plotly.
I tried
import plotly.graph_objects as go
fig = px.line(rmc, y='y1', x='t',color=df['dd'],title='plot')
fig = px.line(rmc, y='y2', x='t', title='plot', color=df['dd'])
fig.show();
thank you in advance!!
Based on the example I commented on, I created a code with an updated data frame. I have specified 6 colors from the plotly default color set so that each graph has a common line color. The second is hidden because it is automatically assigned a legend. I have also added subtitle and main title settings.
from plotly.subplots import make_subplots
import plotly.graph_objects as go
import plotly.express as px
colors = px.colors.qualitative.Plotly[:6]
print(colors)
fig = make_subplots(
rows=2, cols=1,
subplot_titles=("Ttitle 1", "Title 2"))
for d,c in zip(df['dd'].unique(), colors):
dff = df.query('dd == #d')
fig.add_trace(go.Scatter(x=dff['t'], y=dff['y1'], mode='lines', line_color=c, name=d), row=1, col=1)
fig.add_trace(go.Scatter(x=dff['t'], y=dff['y2'], mode='lines', line_color=c, name=d, showlegend=False), row=2, col=1)
fig.update_layout(title_text="Multiple Subplots with Titles")
fig.show()
Plotly express handles this beautifully with px.line if you include the facet_row argument to produce a trellis or facet plot. Both of which are practically just other terms for a subplot. If you're willing to perform a slight manipulation of your dataset so that y1 and y2 appear in the same column like this:
pd.melt(df, id_vars= ['t', 'dd'], value_vars = ['y1', 'y2'])
...then all you have to do in order to produce the plot below is:
px.line(df2, y='value', x='t', title='plot', color = 'dd', facet_row = 'variable')
Plot
Complete snippet
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import pandas as pd
y1 = [-51.04464896560272, -50.891166658544364, -50.82896235500738,-47.93693115514636, -48.93693115514636, -50.2337317810911, -50.580211311328924, -49.63778008455918, -50.55143905012876, -47.18028476096273, -49.45950323726963, -52.759450409024325, -46.94239220924591, -49.34719404199133, -48.592737888881025, -50.39057938285388,-50.33666292445022,-49.689436282011854,-49.86872483079463, -49.47463251418676,-51.542982170986264, -50.650742675143576, -46.498494705109124, -69.232249295994,-65.83208484345344,-56.624359510655715, -64.65663405050996, -63.385051075806444, -61.4890501679952, -64.5215014815885]
y2 = [-49.22994660618851, -49.93693115514636,-47.48816812312157, -47.642008385846054, -49.24556971152835, -49.003594660143946, -49.92614593515235, -48.79589239042106, -49.90953636053393, -49.84547212502676, -48.83995760926475, -50.399185030856515, -47.98870212151289, -49.68206139796429, -48.82322978146867, -49.76209077328067, -48.3489893943433, -49.7807786904155, -51.025277583740525, -46.11152498485985, -17.51108674058229, -6.141613959880809, -107.74424733083552, 24.898229249313353, -27.273007692798586, -26.553484680185544, -38.6166124915005, -29.34043563361383, 31.648897538128374, 52.881233935942774]
t = [50.0,51.0,52.0,53.0,54.0,55.0,56.0,57.0,58.0,59.0,59.0,59.0,60.0,61.0, 59.0,63.0,64.0, 65.0, 66.0,67.0, 68.0,69.0, 70.0,71.0, 72.0, 73.0, 74.0, 75.0, 76.0, 77.0]
dd= ['0','50','79','80','88','95','0','50','79','80','88','95','0','50','79','80','88','95','88','95','79','80','50','79','95','0','50','88','88','95']
df = pd.DataFrame({'y1':y1,'y2':y2,'t':t,'dd':dd})
df2 = pd.melt(df, id_vars= ['t', 'dd'], value_vars = ['y1', 'y2'])
fig = px.line(df2, y='value', x='t', title='Trellis / Facet plot', color = 'dd', facet_row = 'variable')
fig.show()
Below is the syntax used to get the pie chart and grouped bar chart using plotly express subplots
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
specs = [[{'type':'pie'}, {"type": "bar"}]]
fig = make_subplots(rows=1, cols=2, specs=specs, shared_yaxes = True,subplot_titles=['Pie Chart',
'Grouped Bar Chart'])
fig.add_trace(go.Pie(
labels = df_pie['index'],
values = df_pie['count'],
hole = 0.6,
marker_colors = ['#353837','#646665', '#8e9492', '#c9d1ce'],
), 1, 1)
fig.add_trace(go.Bar(
x = df_bar['Satisfaction'],
y = df_bar['count'],
base =df_bar['Gender'],
),1,2)
fig.update_layout(showlegend=False,
title=dict(text="Visualization",
font=dict(
family="Arial",
size=20,
color='#283747')
))
fig.show()
and below is the results I get based on the above code,
How can I get the pie chart look like this
and the bar chart look like this
by plotly express subplots.
You can achieve this by using textinfo for pie-chart. For bar graph, you will need to create the text you want to show on each bar and then use text to display it. Also, as you are looking for grouped bar plots, you will need to use create two traces and then combine then to the subplot - 1,2. Note that the textposition=auto will select the right way to display the text. In the case of bars, due to length, it has moved the text to be displayed vertically.
As the data was not provided, I created some basic data. Hope this is what you are looking for.
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
specs = [[{'type':'pie'}, {"type": "bar"}]]
fig = make_subplots(rows=1, cols=2, specs=specs, shared_yaxes = True, subplot_titles=['Pie Chart', 'Grouped Bar Chart'])
##My data creation##
df_pie=pd.DataFrame({'index':[1,2,3,4], 'count':[442,459,289,280]})
df_bar=pd.DataFrame({'Satisfaction': ['Excellent', 'Excellent', 'Good', 'Good', 'Poor', 'Poor', 'Neutral', 'Neutral'], 'count': [442, 459, 289, 280, 442, 459, 289, 280], 'Gender': ['Male', 'Female', 'Male', 'Female', 'Male', 'Female', 'Male', 'Female']})
fig.add_trace(go.Pie(
labels = df_pie['index'],
values = df_pie['count'],
hole = 0.6,
marker_colors = ['#353837','#646665', '#8e9492', '#c9d1ce'],
textinfo='percent+value', ## ADD - display both
), 1, 1)
## New column to get percentage of row across all Male/Females
df_bar['percentage'] = df_bar.groupby(['Gender'])['count'].transform(lambda z: round(z / z.sum() * 100))
## New column - text of count and percentage - how you need the annotation shown
df_bar['Text']=df_bar['count'].astype(str) + ',' + df_bar['percentage'].astype(str)+'%'
## Create individual traces for Male and Female
trace1 = go.Bar(
x=df_bar[df_bar.Gender == 'Male']['Satisfaction'],
y=df_bar[df_bar.Gender == 'Male']['count'],
name='Male',
text=df_bar[df_bar.Gender == 'Male']['Text'], ## Display text
textposition='auto',
)
trace2 = go.Bar(
x=df_bar[df_bar.Gender == 'Female']['Satisfaction'],
y=df_bar[df_bar.Gender == 'Female']['count'],
name='Female',
text=df_bar[df_bar.Gender == 'Male']['Text'], ## Display text
textposition='auto'
)
fig.append_trace(trace1, 1,2) ## Add as first set of bars in second subplot
fig.append_trace(trace2,1,2) ## Add as second set of bars in second subplot
##Removed your original code
#fig.add_trace(go.Bar(
# x = df_bar['Satisfaction'],
# y = df_bar['count'],
# base =df_bar['Gender'],
# ),1,2)
fig.update_layout(showlegend=False,
title=dict(text="Visualization",
font=dict(
family="Arial",
size=20,
color='#283747')
))
fig.show()
I am plotting an Indian map using plotly and geojson file. Now what I want to do is show static values on the Indian States. Currently those values are visible on hover, I want the values to be seen all the time.
This my code :
import pandas as pd
import plotly.graph_objects as go
df = data_state1
fig = go.Figure(data=go.Choropleth(
geojson="https://gist.githubusercontent.com/jbrobst/56c13bbbf9d97d187fea01ca62ea5112/raw/e388c4cae20aa53cb5090210a42ebb9b765c0a36/india_states.geojson",
featureidkey='properties.ST_NM',
locationmode='geojson-id',
locations=df['ST_NM'].str.title(), # To make lower case to CamelCase
z=df['odval']/df['count'],
text= df['ST_NM'].str.title(),
autocolorscale=False,
colorscale='Reds',
marker_line_color='darkgreen',
colorbar=dict(
title={'text': "Amount"},
thickness=35,
len=1.0,
bgcolor='rgba(255,255,255,0.6)',
xanchor='right',
x=0.0,
yanchor='bottom',
y=0.0
),
))
fig.update_geos(
visible=True,
projection=dict(
type='conic conformal',
parallels=[12.472944444, 35.172805555556],
rotation={'lat': 24, 'lon': 80}
),
lonaxis={'range': [68, 98]},
lataxis={'range': [6, 38]}
)
fig.update_layout(
title=dict(
text="Average Overdue Amount over Total cases ",
xanchor='center',
x=0.5,
yref='paper',
yanchor='bottom',
y=0.9,
pad={'b': 0}
),
margin={'r': 0, 't': 0, 'l': 0, 'b': 0},
height=850,
width=750
)
fig.show()
I also tried with geopandas, on that plot, i was able to plot map with colours on the basis of values, but did not find a way to show state names and values.
Code for geopandas is :
fig, ax = plt.subplots(1, figsize=(10, 10))
ax.axis('off')
ax.set_title('ODVal/Cases distribution',
fontdict={'fontsize': '15', 'fontweight' : '3'})
merged.plot(column='ratio_od_cases',cmap='Reds', linewidth=0.8, ax=ax, edgecolor='0', legend=True)
plt.text(,merged['State_Name'])
I think the easiest way to add text on the map is to use text mode in go.Scattergeo() and specify the latitude and longitude. From the geojson data used, geopandas is used to calculate the center of the state for the text display.
import pandas as pd
import numpy as np
import plotly.graph_objects as go
from urllib import request
import json
url = "https://gist.githubusercontent.com/jbrobst/56c13bbbf9d97d187fea01ca62ea5112/raw/e388c4cae20aa53cb5090210a42ebb9b765c0a36/india_states.geojson"
with request.urlopen(url) as f:
geo_india = json.load(f)
import geopandas as gpd
df = gpd.read_file(url)
df["lon"] = df["geometry"].centroid.x
df["lat"] = df["geometry"].centroid.y
df['value'] = np.random.randint(5,50,36)
fig = go.Figure(data=go.Choropleth(
geojson=geo_india,
featureidkey='properties.ST_NM',
#locationmode='geojson-id',
locations=df['ST_NM'].str.title(), # To make lower case to CamelCase
z=df['value'],
text= df['ST_NM'].str.title(),
autocolorscale=False,
colorscale='Reds',
marker_line_color='darkgreen',
colorbar=dict(
title={'text': "Amount"},
thickness=35,
len=1.0,
bgcolor='rgba(255,255,255,0.6)',
xanchor='right',
x=0.0,
yanchor='bottom',
y=0.0
),
))
fig.update_geos(
visible=True,
projection=dict(
type='conic conformal',
parallels=[12.472944444, 35.172805555556],
rotation={'lat': 24, 'lon': 80}
),
lonaxis={'range': [68, 98]},
lataxis={'range': [6, 38]}
)
fig.add_trace(go.Scattergeo(
lon=df['lon'],
lat=df['lat'],
mode='text',
#text=df['ST_NM'].str.title(),
text=['{}<br>{}'.format(k,v) for k,v in zip(df['ST_NM'].str.title(), df['value'])],
textfont={'color': 'Green'},
name='',
))
fig.update_layout(
title=dict(
text="Average Overdue Amount over Total cases ",
xanchor='center',
x=0.5,
yref='paper',
yanchor='bottom',
y=0.9,
pad={'b': 0}
),
margin={'r': 0, 't': 0, 'l': 0, 'b': 0},
height=850,
width=750
)
fig.show()
I am trying to get the line to display over the bar. It seems that whatever trace has secondary_y=True will be drawn on top of the one where secondary_y=False.
That's fine, but for this particular data set, the bar axis should be on the right, because otherwise this graph is confusing. The line is the one that is in the 1-3 range, and the bar is the one that is in the 0-35k range.
In other words, it should look just like this, but with y-axes switched. Is there some way to switch the axes, or control the order in which it draws the traces, so that I can force the line to be on top of the bars?
import pandas as pd
import plotly.graph_objects as go
from plotly.subplots import make_subplots
from plotly.offline import init_notebook_mode, plot
init_notebook_mode()
rdf = pd.read_csv('us_covid_data_latest.csv', dtype={'fips':str})
incidence = pd.pivot_table(rdf, values='cases', index = 'date', aggfunc=np.sum)
incidence['actual_inc'] = incidence['cases'].diff()
def tail_plot_plotly(tail):
fig = make_subplots(specs=[[{"secondary_y": True}]])
fig.add_trace(
go.Bar(
x= incidence['date'].tail(tail),
y= incidence['actual_inc'].tail(tail)
),
secondary_y = False
)
fig.add_trace(
go.Scatter(
x= incidence['date'].tail(tail),
y= incidence['R_t'].tail(tail)
),
secondary_y = True
)
plot(fig)
tail_plot_plotly(50)
It's not easy providing a complete solution without a sample of your dataset, but I still think I've figured it out. I'm in a bit of a hurry right now, so I'll make it short:
Bars are big numbers, lines are small numbers. Out of the box, a fig = make_subplots(specs=[[{"secondary_y": True}]]) would provide this:
Line trace on top = Good. Bar numbers to the left = Bad.
Changing the order of which yoy apply the different traces to the figure won't help. But you can freely specify on which side of the plot you'd like your primary and secondary y axis to appear like this:
fig.update_layout(dict(yaxis2={'anchor': 'x', 'overlaying': 'y', 'side': 'left'},
yaxis={'anchor': 'x', 'domain': [0.0, 1.0], 'side':'right'}))
Add that to the mix, and you'll get:
Line trace on top = Good. Bar numbers to the right = Good.
Complete code with a data sample:
# imports
import plotly.graph_objects as go
import numpy as np
from plotly.subplots import make_subplots
# set figure twith multiple y axes
fig = make_subplots(specs=[[{"secondary_y": True}]])
# blue line with numbers from 1 to 3
fig.add_trace(
go.Scatter(x=[0, 1, 2, 3, 4, 5],
y=[1.5, 1.0, 1.3, 2.7, 1.8, 2.9]),secondary_y=True)
# red bars with big numbers
fig.add_trace(
go.Bar(x=[0, 1, 2, 3, 4, 5],
y=[np.nan, np.nan, np.nan, 100000, 20000, 250000]))
# update layout to put axes and values in the desired positions
fig.update_layout(dict(yaxis2={'anchor': 'x', 'overlaying': 'y', 'side': 'left'},
yaxis={'anchor': 'x', 'domain': [0.0, 1.0], 'side':'right'}))
fig.show()
I am trying to associate a separate annotation object with each subplot in Plotly (Python), how can this be done?
What I tried
I am setting up the plot like this:
from plotly import tools
fig = tools.make_subplots(rows=2, cols=1)
fig.append_trace(traces[0], 1, 1)
fig.append_trace(traces[1], 2, 1)
where each trace is formed like this:
import plotly.graph_objs as go
traces[0] = go.Scatter(
x=[1,2,3,4],
y=[4,4,2,1],
mode='markers'
)
I know I can access the xaxis of each subplot separately via:
fig['layout']['xaxis1'].update(title='hello1')
fig['layout']['xaxis2'].update(title='hello2')
But how can I access the annotation of each subplot? I tried "annotations1" and "annotation1", with no luck. I also tried to access the layout of subplot 1 via "layout1" as in:
fig['layout1'][...].update(...)
This did not work either.
1) You could assign annotation to specific subplot through setting xref and yref with subplot axis id, such as x1 and y1 represents x axis and y axis of subplot1, as seen from example below and more on link
fig['layout'].update(
annotations=[
dict(
x=2, y=2, # annotation point
xref='x1',
yref='y1',
text='dict Text',
showarrow=True,
arrowhead=7,
ax=10,
ay=70
),
dict(
...
# if have multiple annotations
)
])
2) After you assigned it, you could get access to annotations through
fig['layout']['annotations']
which will return a list of dictionary items:
[{'xref': 'x2', 'arrowhead': 7, 'yref': 'y2', 'text': 'dict Text', 'ay': 40, 'ax': 10, 'y': -1.9491807521563174, 'x': 0.77334098360655923, 'showarrow': True}, {'xref': 'x2', 'arrowhead': 7, 'yref': 'y2', 'text': 'dict Text', 'ay': -40, 'ax': 10, 'y': -0.0041268527747384542, 'x': 1.1132422279202281, 'showarrow': True}]
Hope this could help ;)
it also works with update(),
if you adress the subplot as an element inside the annotations list.
from plotly.subplots import make_subplots
import plotly.graph_objects as go
# create figure with subplots
fig = make_subplots(rows=1, cols=2, subplot_titles = ['title1','title2'])
fig.add_trace(
go.Scatter(x=[1, 2, 3], y=[4, 5, 6]),
row=1, col=1
)
fig.add_trace(
go.Scatter(x=[20, 30, 40], y=[50, 60, 70]),
row=1, col=2
)
fig.update_layout(height=600, width=800, title_text="Subplots")
fig.show()
# to change subtitle, address subplot
fig['layout']['annotations'][0].update(text='your text here');
fig.show()