Black Lives Matter. Please consider donating to Black Girls Code today.
Learn how to use COVID-19 data in open source Dash apps. Register for the Sept 23rd webinar with IQT!

Subplots with two y axes

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

anyone has any idea on how to do that??

Your plots have as left yaxes, assigned via tools.tls.make_subplots, the axes: yaxis1, yaxis2, … yaxis20.
The right yaxes will be denoted yaxis21, yaxis22, …, yaxis40. They are assigned by the following layout update:

for k in range(1,21):
      fig['layout'].update({'yaxis{}'.format(k+20): YAxis(anchor='x'+str(k),
                                                          overlaying='y'+str(k),
                                                          side='right',
                                                          title='my-title',
                                                         )
                            })

A very important point is to set the range for each yaxis!!!

2 Likes

Thank you very much empet. Finally some help on this!

empet, any idea why, following your advice and assigning the different traces to different axes, I get them all plotted against one (the left axis) - see https://plot.ly/~andrea.botti/627.embed

For each subplot, the green trace should refer to the right axis yaxis='y' + str(i+no_charts), whereas the other two traces refer to the left axis 'y' + str(i) where i is the loop counter and no_charts is the number of subplots (quite self-explanatory)

@andrea.botti I checked your code on the Plotly cloud: https://plot.ly/~andrea.botti/627/tm52-criteria-for-all-rooms-may-to-sep/#code, and I noticed that you have all traces in a plot referenced to 'xaxis'+str(k}, 'yaxis'+str(k}, k =1, …16.
For example the traces 46, 47, 48 are referenced to xaxis16, yaxis16. That is why for all three traces at hovering are displayed values with respect to the left yaxis16.

Not only the layout, but also each trace in fig['data'], referenced to the right yaxis should be updated to corresponding 'yaxis'+str(number).

After appending all traces to fig, you should update fig[‘data’][j], with j coorresponding to the traces that are referenced to the right yaxis of the corresponding plot. See the Python code for this example: https://plot.ly/~empet/13405/points-accumulated-by-s-halep-in-each-tournament/#code

Empet,
thanks very much for your reply!
I am confused now.
So is it the case that I should:
1 append the traces to the correct row and column (within the subplot table)
2 define the layout to include two y-axes(left and right)
3 update each trace within the data to impose those are plotted against the correct axis (I don’t understand why this step is required)

My traces were appended with the following code in the first place:

trace_He = Scatter(
	x=df52_all.index,
	y=df52_all['He_'+column],
	line = dict(
		color = ('rgba(138,191,63,1.0)'),
		width = 1,
  	),
	fill='tozeroy',
        fillcolor = ('rgba(138,191,63,0.25)'),
	name='He_'+column,
	text='He_'+column,
	xaxis='x'+str(i),
        yaxis='y'+str(i+no_charts),
        )
fig_tm52.append_trace(trace_He,row=row,col=col)


trace_We = Bar(
    x=df52_all.index,
    y=df52_all['We_'+column],
    marker=dict(color = ('rgba(220,129,34,1.0)')),
    name='We_'+column,
    text='We_'+column,
    xaxis='x'+str(i),
    yaxis='y'+str(i)
    )
fig_tm52.append_trace(trace_We,row=row,col=col)


trace_Ul = Bar(
    x=df52_all.index,
    y=df52_all['Ul_'+column],
    marker=dict(color = ('rgba(200,54,162,1.0)')),
    name='Ul_'+column,
    text='Ul_'+column,
    xaxis='x'+str(i),
    yaxis='y'+str(i)
    )
fig_tm52.append_trace(trace_Ul,row=row,col=col)

Why do I have to tell plotly a second time that trace_We and trace_Ul should plot on 'y'+str(i), while He on 'y'+str(i+no_charts) ?

@andrea.botti The result of your code isn’t correct, because no trace is referenced to an 'yaxis'+str(k} that has in layout side='right'. If you look at my example you’ll see that the first trace is referenced to x1, y1, while the second to x1, y2.

In your code all traces in the same plot are referenced to some xk, yk.

@empet Yes, that is understood (and thank you for help clarifying that). We agree there is an error in the end code, but not really sure what I am doing wrong.

Could it be because I am appending traces first, and then defining the layout?

Thanks

@andrea.botti

Could it be because I am appending traces first, and then defining the layout?

No, that order doesn’t matter. Something went wrong with this assignment: yaxis='y'+str(i+no_charts) because in the code on Plotly cloud isn’t displayed the sum i+no_charts, but only yaxis=y+str(i).

You know, I have included a print('y'+str(i+no_charts)) to check that the loop actually generates the values y17y32 (as I no_charts=16) and that prints just fine. This is driving me mad!

@andrea.botti This test isn’t relevant. Just check:

print  fig['data'][k] 

where k is a trace number for which you have yaxis='y'+str(i+no_charts) . If it prints only yaxis=‘y’+str(i), then try to make the sum i+no_charts before the definition of that trace, assign it to some j, and
set in the trace definition yaxis='y'+str(j).

@empet the command:
print(fig_tm52['data'][i]) (k is not defined anywhere in my script) returns a list of all data, where the traces ‘He_’ have same y-axes as We_ and Ul (consistently with the chart).

So, if I instead print after the loop has completed (which is perhaps what you’re suggesting?), I can do:
print(fig_tm52['data'][0]) returns: name: 'He_3F_T09_SE_SW_Bed1''yaxis': 'y1'
print(fig_tm52['data'][1]) returns: name: 'We_3F_T09_SE_SW_Bed1''yaxis': 'y1'
print(fig_tm52['data'][2]) returns: name: 'Ul_3F_T09_SE_SW_Bed1''yaxis': 'y1'

With reference to my chart, this is the first subplot.

I was doing it outside the trace definition, and that kept giving me the same issue!
Withing the loop (and before defining traces) I had defined:
x_all = ‘x’ + str(i)
y_first = ‘y’ + str(i)
y_second = ‘y’ + str(i+no_charts)

and used those…I am desperate!
I am now trying to perform a fig_tm52['data'][k].update() although I don’t really know the correct syntax, so it will be a bit of trial and error
Thank you very much for your help.

@empet

I solved it!!! YEYYYYYY

with this:

i = 0
for r in room_list:
    h = i * 3
    j = h + 1
    k = h + 2
    i = i +1
    print(h, j ,k)
    #print(fig_tm52['data'][k])
    fig_tm52['data'][k].update(yaxis='y'+str(i+no_charts))

UPDATE: although with this change I have now lost the second y-axis on all column after the first one (see https://plot.ly/~andrea.botti/627.embed). Now sure why plotly does that

1 Like

@andrea.botti I

No matter how you set the yaxis in the trace definition, when you append the first three traces through:

fig.append_trace(trace1, 1,1)
fig.append_trace(trace2, 1, 1)
fig.append_trace(trace3, 1, 1)

the yaxis is set to ‘y1’. That is why you shoud perform the updates.