2

I already wrote below nested loops to generate 21 charts with success (one chart for each country, for example german gas austrian gas)

dfs is a dict with 21 countries names as keys and their respective gas storage dfs as values

for country in list(dfs_storage.keys()):
    df_country=dfs_storage[country]
    month = list(set(df_country['month']))
    fig = go.Figure()
    for year in set(df_country['year']):
        workingGasVolume_peryear=df_country.loc[df_country['year']==year,'workingGasVolume']
        gasInStorage_peryear=df_country.loc[df_country['year']==year,'gasInStorage']
        # Create and style traces
        fig.add_trace(go.Scatter(x=month, y=workingGasVolume_peryear, name=f'workingGasVolume{year}',
                                 line=dict(width=4,dash='dash')))
        fig.add_trace(go.Scatter(x=month, y=gasInStorage_peryear, name=f'gasInStorage{year}',
                                 line = dict(width=4)))

    # Edit the layout
    fig.update_layout(title=f'{country} workingGasVolume gasInStorage',
                       xaxis_title='Month',
                       yaxis_title='Gas Volume')

    offline.plot({'data':fig},filename=f'{country} gas storage.html',auto_open=False)

Now I am asked to put these 21 charts in one HTML file without changing each chart, they can appear vertically one after another for example

I tried the "subplots" with Plotly with below code and modified a few times but never have the desired chart, I got one single useless chart where I can't see any values.. Can anyone help me? Thanks

countries=[]
for country in list(dfs_storage.keys()):
    countries.append(country)
fig = make_subplots(
    rows=len(list(dfs_storage.keys())),cols=1,
    subplot_titles=(countries))

for country in countries:
    df_country=dfs_storage[country]
    month = list(set(df_country['month']))
    for year in set(df_country['year']):
        workingGasVolume_peryear=df_country.loc[df_country['year']==year,'workingGasVolume']
        gasInStorage_peryear=df_country.loc[df_country['year']==year,'gasInStorage']
        # Create and style traces
        fig.add_trace(go.Scatter(x=month, y=workingGasVolume_peryear, name=f'workingGasVolume{year}',
                                 line=dict(width=4,dash='dash')))
        fig.add_trace(go.Scatter(x=month, y=gasInStorage_peryear, name=f'gasInStorage{year}',
                                 line = dict(width=4)))

    # Edit the layout
# fig.update_layout(title='workingGasVolume gasInStorage',
#                    xaxis_title='Month',
#                    yaxis_title='Gas Volume')

offline.plot({'data':fig},filename='gas storage.html',auto_open=False) 

Edit 7th June: as per jayveesea's advice, I added the row and col argument under add_trace, the code is below but still has Traceback:

countries=[]
for country in list(dfs_storage.keys()):
    countries.append(country)
fig = make_subplots(
    rows=len(list(dfs_storage.keys())),cols=1,
    subplot_titles=(countries))

for i in range(len(countries)):
    country=countries[i]
    df_country=dfs_storage[country]
    month = list(set(df_country['month']))
    for year in set(df_country['year']):
        workingGasVolume_peryear=df_country.loc[df_country['year']==year,'workingGasVolume']
        gasInStorage_peryear=df_country.loc[df_country['year']==year,'gasInStorage']
        # Create and style traces
        fig.add_trace(go.Scatter(x=month, y=workingGasVolume_peryear, name=f'workingGasVolume{year}',row=i,col=1,
                                 line=dict(width=4,dash='dash')))
        fig.add_trace(go.Scatter(x=month, y=gasInStorage_peryear, name=f'gasInStorage{year}',row=i,col=1,
                                 line = dict(width=4)))

    # Edit the layout
# fig.update_layout(title='workingGasVolume gasInStorage',
#                    xaxis_title='Month',
#                    yaxis_title='Gas Volume')

offline.plot({'data':fig},filename='gas storage.html',auto_open=False)

print('the Plotly charts are saved in the same folder as the Python code')

Edit 8th June: This is the code I am running now, copied from @jayveesea's answer and only modified the name of the df

countries=[]
for country in list(dfs_storage.keys()):
    countries.append(country)
# STEP 1
fig = make_subplots(
    rows=len(countries), cols=1,
    subplot_titles=(countries))

for i, country in enumerate(countries): #enumerate here to get access to i
    years = df_country.year[df_country.country==country].unique()
    for yrs in years:
        focus = (df_country.country==country) & (df_country.year==yrs)
        month = df_country.month[focus]
        workingGasVolume_peryear = df_country.workingGasVolume[focus]
        gasInStorage_peryear = df_country.gasInStorage[focus]

        # STEP 2, notice position of arguments!
        fig.add_trace(go.Scatter(x=month, 
                                 y=workingGasVolume_peryear, 
                                 name=f'workingGasVolume{yrs}',
                                 line=dict(width=4,dash='dash')),
                      row=i+1, #index for the subplot, i+1 because plotly starts with 1
                      col=1)
        fig.add_trace(go.Scatter(x=month, 
                                 y=gasInStorage_peryear, 
                                 name=f'gasInStorage{yrs}',
                                 line = dict(width=4)),
                      row=i+1,
                      col=1)      
fig.show()

Yet I still have Traceback message

Traceback (most recent call last):

  File "<ipython-input-27-513826172e49>", line 43, in <module>
    line=dict(width=4,dash='dash')),

TypeError: 'dict' object is not callable
12
  • 1
    Do you mind to share a sample of your data? Commented Jun 5, 2020 at 20:03
  • I don't see any subplot reference to row and col, like fig.add_trace(go.Scatter(x=[1, 2, 3], y=[4, 5, 6]),row=1, col=1). See here. Commented Jun 6, 2020 at 16:15
  • @rpanai thanks, I just edited my post, you can see one of the df for Austrian data, I converted it to a dict to be able to paste here. Is this what you asked? Commented Jun 6, 2020 at 16:16
  • yes but when you fig.add_trace you need to tell it which row and col... its jayveesea, btw :) Commented Jun 6, 2020 at 16:52
  • 1
    Hi @jayveesea just give you some feedback, I still don't know why I can't run your code but I have corrected my code above dated 7th June by putting the 2 parameters row and column out of go.scatter, as you mentioned earlier. now this version of code works and I have 1 HTML, now I am working to try to fix the legend as there are 21 x 7 legends all stuck together on top part of the html instead of near each subplot. Thanks for your help Commented Jun 10, 2020 at 16:06

1 Answer 1

2

To use subplots in plotly you need to:

  1. use make_subplots to initialize the layout specifying the row and column
  2. then use row and col as arguments to fig.add_trace. NOTE: subplots row and columns start at 1 (not zero)

In your case, step2 is where you are getting stuck. Initially this part was missing (first post), but now in your update it's added in as an argument to go.Scatter. Carefully look over the examples here as the differences are just commas and parentheses and their placement.

To clarify, this:

fig.add_trace(go.Scatter(x=month, 
                         y=workingGasVolume_peryear, 
                         name=f'workingGasVolume{year}',
                         row=i,
                         col=1,
                         line=dict(width=4,dash='dash')))

should be:

fig.add_trace(go.Scatter(x=month, 
                         y=workingGasVolume_peryear, 
                         name=f'workingGasVolume{year}',
                         line=dict(width=4,dash='dash')),
              row=i+1,
              col=1)

I'm having difficulty with your code and data, which could be on my end as I do not use dictionaries like this, but here is a working example with your data in a csv and the use of pandas. Also, I changed one of the years to a different country so that there would be another plot.

import pandas as pd
import plotly.graph_objects as go  
from plotly.subplots import make_subplots

df = pd.read_csv('someData.csv')
countries = df.country.unique()

# STEP 1
fig = make_subplots(
    rows=len(countries), cols=1,
    subplot_titles=(countries))

for i, country in enumerate(countries): #enumerate here to get access to i
    years = df.year[df.country==country].unique()
    for yrs in years:
        focus = (df.country==country) & (df.year==yrs)
        month = df.month[focus]
        workingGasVolume_peryear = df.workingGasVolume[focus]
        gasInStorage_peryear = df.gasInStorage[focus]

        # STEP 2, notice position of arguments!
        fig.add_trace(go.Scatter(x=month, 
                                 y=workingGasVolume_peryear, 
                                 name=f'workingGasVolume{yrs}',
                                 line=dict(width=4,dash='dash')
                                ),
                      row=i+1, #index for the subplot, i+1 because plotly starts with 1
                      col=1)
        fig.add_trace(go.Scatter(x=month, 
                                 y=gasInStorage_peryear, 
                                 name=f'gasInStorage{yrs}',
                                 line = dict(width=4)),
                      row=i+1,
                      col=1)      
fig.show()

enter image description here

Sign up to request clarification or add additional context in comments.

6 Comments

Thanks a lot for your help @jayveesea, I was using this as example as I need the titles plotly.com/python/subplots/#multiple-subplots-with-titles I just edited my post: I pasted 2 dfs from the dictionary dfs_storage
sorry, not clear if you still have further questions... I tried the new data and it also works.
Thanks,@jayveesea, 1>I tried your code but it gives me tracebacks consecutively, I modified and deactivated some line but Tracebacks continue. 1.1>f'workingGasVolume{y}' should be f'workingGasVolume{yrs}' right? 1.2>then: line=dict(width=4,dash='dash') TypeError: 'dict' object is not callable, so I deleted this line, 1.3>then: col=1) ^ SyntaxError: unexpected EOF while parsing 2.> I don't get what was wrong in my latest version of code which iterates "for i in range(len(countries)):", I double-checked all the commas, indentations and parentheses and don't see why my code doesn't work
For #1.1, yes should be yrs, I'll correct my answer. For #1.2 and #1.3 it seems like my code was not copied correctly. For #2, your latest revision does not have the syntax correct for subplots. row=i,col=1 need to be arguments to fig.add_trace and you need row=i+1
added further clarification above
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.