Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I set each plotly subplot title during graph creation loop?

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')
like image 858
wex52 Avatar asked Aug 02 '20 19:08

wex52


People also ask

What is subplot in Plotly?

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.

What is Add_trace in Plotly?

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.


1 Answers

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:

enter image description here

into this:

enter image description here

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]))

Plot 3

enter image description here

Complete code:

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()
like image 162
vestland Avatar answered Oct 05 '22 23:10

vestland