3

Are there guidelines on how to set up secondary Y-axes in python for plotly? I am assinging axis style through an iterative loop, as follows:

all_plots = ['plot1','plot2'...'plot20']
fig = tools.make_subplots(rows=nrow, cols=ncol, shared_xaxes=False, shared_yaxes=False, subplot_titles=all_plots)
for i in all_plots:
    fig['layout']['yaxis'+str(j)].update()

How does the assignment of y axes work?

If my subplot included, say, 4 rows and 5 columns for a total of 20 subplots, do I have to assume that plotly needs to receive odd and even numbers, meaning: yaxis1 and yaxis2 for plot1

....

yaxis39 and yaxis40 for plot20

Andreuccio
  • 1,053
  • 2
  • 18
  • 32

3 Answers3

2

It is possible, to do this, but its not particularly intuitive. Take this example where I create a plot 2x2 subplots, and add a secondary y axis to the plot in position 2,2.

When you create a subplots, they are assigned y axes: "y1","y2","y3","y4" on the left side of each subplot. To a secondary y axes, you need to use fig['layout'].updateto create new axes "y5", "y6", "y7", "y8" which correspond to "y1","y2","y3","y4". So the bottom right subplot would have axes y4(right) and y8(left). In the example below, I only create a secondary y axis for the last plot, but expanding it to more/all the subplots is pretty straightforward.

It is important to note, that creating the secondary axes, and assigning it in trace5 doesn't automatically place it on the proper axes. You still have to manually assign it with fig['data'][4].update(yaxis='y'+str(8)) to plot it relative to the left axis.

fig = tools.make_subplots(rows=2, cols=2,subplot_titles=('Air Temperature', 'Photon Flux Density',
                                                         'Ground Temps','Water Table & Precip'))


fig['layout']['xaxis1'].update( range=[174, 256])
fig['layout']['xaxis3'].update(title='Day of Year', range=[174, 256])
fig['layout']['yaxis1'].update(title='Degrees C',range=[-5,30])
fig['layout']['yaxis2'].update(title='mmol m<sup>-2</sup> m<sup>-d</sup>', range=[0, 35])
fig['layout']['yaxis3'].update(title='Ground Temps', range=[0, 11])
fig['layout']['yaxis4'].update(title='depth cm', range=[-20, 0])
fig['layout']['yaxis8'].update(title='rainfall cm', range=[0, 1.6])
fig['layout'].update(showlegend=False, title='Climate Conditions')



# In this example, I am only doing it for the last subplot, but if you wanted to do if for all, 
# Just change to range(1,5)

for k in range(4,5):  
    fig['layout'].update({'yaxis{}'.format(k+4): dict(anchor='x'+str(k),
                                                          overlaying='y'+str(k),
                                                          side='right',
                                                         )
                            })

trace1 = go.Scatter(
        y=Daily['AirTC_Avg'],
        x=Daily.index,
        marker = dict(
        size = 10,
        color = 'rgba(160, 0, 0, .8)',),
        error_y=dict(
            type='data',
            array=Daily_Max['AirTC_Avg']-Daily_Min['AirTC_Avg'],
            visible=True,
        color = 'rgba(100, 0, 0, .5)',
        ),
    name = 'Air Temp'
    )

trace2 = go.Bar(
        y=Daily['PPFD']/1000,
        x=Daily.index,
        name='Photon Flux',
        marker=dict(
            color='rgb(180, 180, 0)'
        ),

    yaxis='y2',
)

trace3 = go.Scatter(
        y=Daily['Temp_2_5_1'],
        x=Daily.index,
        name='Soil Temp',
        marker=dict(
            color='rgb(180, 0, 0)'
        ),

    yaxis='y3',
)


trace4 = go.Scatter(
        y=Daily['Table_1']*100,
        x=Daily.index,
        name='Water Table',
        marker=dict(
            color='rgb(0, 0, 180)'
        ),

    yaxis='y4',
)

trace5 = go.Bar(
        y=Daily['Rain']/10,
        x=Daily.index,
        name='Rain',
        marker=dict(
            color='rgb(0, 100, 180)'
        ),

    yaxis='y8',
)

fig.append_trace(trace1, 1, 1)
fig.append_trace(trace2, 1, 2)
fig.append_trace(trace3, 2, 1)
fig.append_trace(trace4, 2, 2)
fig.append_trace(trace5, 2, 2)


## This part is important!!! you have to manually assing the data to the axis even 
# though you do it when defining trace 5
fig['data'][4].update(yaxis='y'+str(8))
plot(fig, filename='FI_Climate')
June Skeeter
  • 1,142
  • 2
  • 13
  • 27
1

Not an exact answer but I thought it might help...

I like to use pandas and cufflinks. Here is an example of how to plot two sets of data from one dataframe (df) on a graph using a secondary y axis. The data from each axis is displayed in different formats in this example (scatter and bar). The data is arranged into columns beforehand.

import pandas as pd
import cufflinks as cf
from plotly.offline import download_plotlyjs, init_notebook_mode,plot,iplot    

fig1 = df.iplot(kind='scatter', mode='lines+markers', x=['col1', 'col2'],
                y=['col3', 'col4',],
                asFigure=True)
fig2 = df.iplot(kind='bar', x=['col1', 'col2'],
                  y=['col3', 'col4', ],
                  secondary_y=['col5','col6'],asFigure=True)
fig2['data'].extend(fig1['data'])
sparrow
  • 10,794
  • 12
  • 54
  • 74
  • 3
    thanks for that, that's really useful. Unfortunately that does not answer my main question on how to produce subplots with two y axes each – Andreuccio Nov 15 '16 at 14:42
0

The naming convention is y, y2, y3... y40, and you make the reference to the axis in the trace dict.

So your traces should be like...

trace0 = dict(
    x = xvals,
    y = yvals,
    yaxis = 'y'
)
trace1 = dict(
     x = x2vals,
     y = y2vals,
     yaxis = 'y2'
)
....
trace40 = dict(
     x = x40vals,
     y = y40vals,
     yaxis = 'y40'
)
Sam
  • 4,000
  • 20
  • 27
  • I am not sure my question was clear. If I do what you recommend, I get one y-axis for each subplot, and my two defined y axes (one ranging [0,5], the other [0,20] are alternated between subsequent subplots, rather than appear at the same time for each plot https://plot.ly/~andrea.botti/627.embed – Andreuccio Nov 07 '16 at 18:44