I understand that if I want to set all of the subplot titles then I can do that when I declare the figure.
import pandas as pd
import plotly.graph_objs as go
from plotly.subplots import make_subplots
fig = make_subplots(
###
subplot_titles=['Plot 1', 'Plot 2', 'Plot 3', 'Plot 4', etc.]
)
However, I create each subplot graph within a loop, and I think it would be easiest to set each subplot's title during that process. In my case, I created a groupby object based on date, and then I loop through each group (date) dataframe. Each dataframe is used to create the subplot graph, and I'd like the title to be the date. I understand that I can figure this out before the loop and set the subplot_titles as normal, but it seems like it'd be a one-liner within the loop. If it matters, the traces I'm adding are choropleths. I'm not going to include a working dataset since my code works fine- I just want to know what line of code I need to add.
#Create groupby object, splitting data frame into separate data frames based on 'State'
death_counts_gbo = death_counts_by_week.groupby('End Week')
#Prepare subplots for choropleths
rows = 4
cols = 7
fig = make_subplots(
rows=rows, cols=cols,
specs = [[{'type': 'choropleth'} for c in np.arange(cols)] for r in np.arange(rows)],
)
#Graph each state's data
for i, (date, df) in enumerate(death_counts_gbo):
fig.add_trace(go.Choropleth(
locations=df['State Abbr'], # Spatial coordinates
z = df['COVID-19 Deaths per 100k'].astype(float), # Data to be color-coded
locationmode = 'USA-states', # set of locations match entries in `locations`
colorscale = 'Reds',
zmin = 0,
zmax = 30,
colorbar_title = "Deaths per 100k",
text = date.strftime('%m-%d-%Y')
), row=i//7+1, col=i%7+1)
### This is where I'd like to set the subplot's title to 'date' ###
# Set title of entire figure
# Set each subplot map for the USA map instead of default world map
# Set each subplot map's lake color to light blue
fig.update_layout(
title_text = 'COVID-19 Deaths per 100k at week ending',
**{'geo' + str(i) + '_scope': 'usa' for i in [''] + np.arange(2,len(death_counts_gbo)+1).tolist()},
**{'geo' + str(i) + '_lakecolor': 'lightblue' for i in [''] + np.arange(2,len(death_counts_gbo)+1).tolist()},
)
fig.show()
EDIT: For my example, I can set the subplot titles during the figure declaration with the following kwarg:
subplot_titles = [date.strftime('%m-%d-%Y') for date in list(death_counts_gbo.groups.keys())]
However, for my own edification and if I have a future case where the determination of the subtitle is more involved, I would still like to know how to set it during the loop / after the figure declaration.
EDIT2: Thanks to @rpanai I have a solution, though it required a change in my make_subplots
declaration, in addition to a one-liner in the loop. He informed me that subtitles are annotations stored in fig.layout.annotations
and that, while a list of subtitles may be provided to it, calculating the appropriate x
and y
coordinates might be a hassle. I worked around this issue by creating temporary subtitles and forcing make_subplots
to calculate the x
and y
coordinates. I then updated the text in the loop.
The updated make_subplots
figure declaration (subplot_titles added):
fig = make_subplots(
rows=rows, cols=cols,
specs = [[{'type': 'choropleth'} for c in np.arange(cols)] for r in np.arange(rows)],
subplot_titles = ['temp_subtitle' for date in np.arange(len(death_counts_gbo))]
)
One-liner (first line of the for-loop):
fig.layout.annotations[i]['text'] = date.strftime('%m-%d-%Y')
subplots module. Here is an example of creating a figure that includes two scatter traces which are side-by-side since there are 2 columns and 1 row in the subplot layout. from plotly.subplots import make_subplots import plotly.graph_objects as go fig = make_subplots(rows=1, cols=2) fig.
Adding Traces To Subplots If a figure was created using plotly. subplots. make_subplots() , then supplying the row and col arguments to add_trace() can be used to add a trace to a particular subplot. In [12]: from plotly.subplots import make_subplots fig = make_subplots(rows=1, cols=2) fig.
You mentioned that you'd like to be able to edit the titles (that are annotations) after you'be built your figures as well. And if you already have some title in place, and would like to change them, you can use fig.for_each_annotation()
in combination with a dict like this:
names = {'Plot 1':'2016', 'Plot 2':'2017', 'Plot 3':'2018', 'Plot 4':'2019'}
fig.for_each_annotation(lambda a: a.update(text = names[a.text]))
Which will turn this:
into this:
You can also easily combine existing titles with an addition of your choice with:
fig.for_each_annotation(lambda a: a.update(text = a.text + ': ' + names[a.text]))
from plotly.subplots import make_subplots
import plotly.graph_objects as go
fig = make_subplots(
rows=2, cols=2,
subplot_titles=("Plot 1", "Plot 2", "Plot 3", "Plot 4"))
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.add_trace(go.Scatter(x=[300, 400, 500], y=[600, 700, 800]),
row=2, col=1)
fig.add_trace(go.Scatter(x=[4000, 5000, 6000], y=[7000, 8000, 9000]),
row=2, col=2)
fig.update_layout(height=500, width=700,
title_text="Multiple Subplots with Titles")
names = {'Plot 1':'2016', 'Plot 2':'2017', 'Plot 3':'2018', 'Plot 4':'2019'}
# fig.for_each_annotation(lambda a: a.update(text = names[a.text]))
fig.for_each_annotation(lambda a: a.update(text = a.text + ': ' + names[a.text]))
fig.show()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With