✊🏿 Black Lives Matter. Please consider donating to Black Girls Code today.
🐇 Announcing Dash VTK for 3d simulation graphics. Check out the March webinar.

Trying to make a uniform colorscale for each of the subplots

Dear Community,

I have created a graph with 8 subplots corresponding to the energy production of each wind turbine in a farm per year. Each subplot corresponds to a different year of operation. I managed to get a nice colorscale applied to each of the subplots but each of the colorscales has a different range (based on the data in each of the subplots).

I would like to make one where there is a “global” colorscale and the values in each plot correspond to the fixed colours. I would be grateful for your suggestions.

SUBPLOTS WITH AEP per turbine

def aep_turbine_subplot_fig(years, AEP):

fig = make_subplots(rows = 4, cols = 2, subplot_titles = years)

fig.add_trace(go.Bar(x = get_turbine_names(),
                y = AEP.iloc[0,:],
                name = '2012',
                marker = {'color': AEP.iloc[0,:],
                          'colorscale': 'RdBu'}),
                row = 1, col = 1)
fig.add_trace(go.Bar(x = get_turbine_names(),
                y = AEP.iloc[1,:],
                name = '2013',
                marker = {'color': AEP.iloc[1,:],
                          'colorscale': 'RdBu'}),
                row = 1, col = 2)
fig.add_trace(go.Bar(x = get_turbine_names(),
                y = AEP.iloc[2,:],
                name = '2014',
                marker = {'color': AEP.iloc[2,:],
                          'colorscale': 'RdBu'}),
                row = 2, col = 1)
fig.add_trace(go.Bar(x = get_turbine_names(),
                y = AEP.iloc[3,:],
                name = '2015',
                marker = {'color': AEP.iloc[3,:],
                          'colorscale': 'RdBu'}),
                row = 2, col = 2)
fig.add_trace(go.Bar(x = get_turbine_names(),
                y = AEP.iloc[4,:],
                name = '2016',
                marker = {'color': AEP.iloc[4,:],
                          'colorscale': 'RdBu'}),
                row = 3, col = 1)
fig.add_trace(go.Bar(x = get_turbine_names(),
                y = AEP.iloc[5,:],
                name = '2017',
                marker = {'color': AEP.iloc[5,:],
                          'colorscale': 'RdBu'}),
                row = 3, col = 2)
fig.add_trace(go.Bar(x = get_turbine_names(),
                y = AEP.iloc[6,:],
                name = '2018',
                marker = {'color': AEP.iloc[6,:],
                          'colorscale': 'RdBu'}),
                row = 4, col = 1)
fig.add_trace(go.Bar(x = get_turbine_names(),
                y = AEP.iloc[7,:],
                name = '2019 (Jan to Jun)',
                marker = {'color': AEP.iloc[7,:],
                          'colorscale': 'RdBu'}),
                row = 4, col = 2)

# editing the yaxes in each subplot
fig.update_yaxes(title_text='AEP [GWh] in 2012', title_font = dict(size = 14), row=1, col=1, range = [0,8.2])
fig.update_yaxes(title_text='AEP [GWh] in 2013', title_font = dict(size = 14), row=1, col=2, range = [0,8.2])
fig.update_yaxes(title_text='AEP [GWh] in 2014', title_font = dict(size = 14), row=2, col=1, range = [0,8.2])
fig.update_yaxes(title_text='AEP [GWh] in 2015', title_font = dict(size = 14), row=2, col=2, range = [0,8.2])
fig.update_yaxes(title_text='AEP [GWh] in 2016', title_font = dict(size = 14), row=3, col=1, range = [0,8.2])
fig.update_yaxes(title_text='AEP [GWh] in 2017', title_font = dict(size = 14), row=3, col=2, range = [0,8.2])
fig.update_yaxes(title_text='AEP [GWh] in 2018', title_font = dict(size = 14), row=4, col=1, range = [0,8.2])
fig.update_yaxes(title_text='AEP [GWh] in 2019', title_font = dict(size = 14), row=4, col=2, range = [0,8.2])

fig.update_layout(
        title = 'AEP per turbine',
        xaxis_tickfont_size = 14,
        barmode='group',
        bargap=0.15, # gap between bars of adjacent location coordinates.
        bargroupgap=0.1, # gap between bars of the same location coordinate.
        showlegend = False,
        plot_bgcolor ='rgb(160,160,160)',

    )
fig.write_image(get_fig_dir() + 'AEP_perTurbine.png', width = 800, height = 800)
fig.show(renderer = 'png', width = 800, height = 1000)
return plot(fig, auto_open = True)

@maciekmaj

Welcome to Plotly forum!! To add a global colorbar you should to find the min and max values, cmin, cmax, of the union of your DataFrame columns, and add to each go.Bar instance the attributes marker_cmin=cmin, marker_cmax=cmax.
Example:

import numpy as np
import plotly.graph_objects as go
from plotly.subplots import make_subplots

d = {'2014': 2+ 8*np.random.rand(14),
     '2015': 1+7*np.random.rand(14)}

fig = make_subplots(rows=1, cols=2)

fig.add_trace(go.Bar(x=[f't0{k}'  for k in range(1, 10)]+[[f't{k}'] for k in range(10,15)],
                    y = d['2014'], marker_color=d['2014'], marker_colorscale='Viridis' ), 1, 1)
fig.add_trace(go.Bar(x=[f't0{k}'  for k in range(1, 10)]+[[f't{k}'] for k in range(10,15)],
                    y = d['2015'], marker_color=d['2015'], marker_colorscale='Viridis'), 1,2);

fig.update_layout(width=800, height=400, showlegend=False)

cmin = min([d['2014'].min(), d['2015'].min()])
cmax = max([d['2014'].max(), d['2015'].max()])

#Update the traces inserted in the two subplots to get a global colorscale
for k in range(2):
    fig.data[k].update(marker_cmin=cmin, marker_cmax=cmax)
fig.data[1].update(marker_colorbar = dict(x=1.05, y=0.5, thickness=20))

Hi @maciekmaj and @empet, it’s also possible to do this using a coloraxis as in the example below, if you want a more automatic solution. We should document this more!

import plotly.graph_objects as go
from plotly.subplots import make_subplots
fig = make_subplots(1, 2)
fig.add_trace(go.Bar(x=[1, 2, 3], y=[4, 6, 7],
                    marker=dict(color=[4, 6, 7], 
                                coloraxis="coloraxis1")), 
              1, 1)
fig.add_trace(go.Bar(x=[1, 2, 3], y=[2, 3, 5],
                    marker=dict(color=[2, 3, 5],
                                coloraxis="coloraxis1")),
              1, 2)
fig.update_layout(coloraxis=dict(colorscale='RdBu'), showlegend=False)
fig.show()

@emmanuelle Thanks, I know that we can use coloraxis (see this notebook https://plot.ly/~empet/15283 uploaded to Plotly cloud a month ago), but for someone who posts for the first time on this forum it’s much clearer to set colorscale in each trace.

OK :slight_smile: ! Of course I never doubted your plotly.py proficiency ;-). One of the reasons the coloraxis is not so clear is that it’s not well documented. Anyway, future readers will have the two solutions! Thank you so much for your amazing contribution to the community!

I would say that coloraxis is the preferred way to do this, given how much less code/knowledge-of-internals is involved… it’s documented here: https://plot.ly/python/colorscales/#share-color-axis

1 Like

(The place where coloraxis really shines, btw, is in multiple histogram2d subplots, where it’s not practical to compute the bounds in Python without replicating all of Plotly.js’ binning logic)

1 Like

Yes, you right that using coloraxis you have to write fewer lines of code, but there are users who don’t know how the colormapping is performed.
From my example a beginner learns what range of color values is mapped to the given colorscale, while in the tutorial you mentioned this aspect is not textually emphasized ( it is a “mute tutorial”).
Only an experienced user can notice looking at the subplot colorbar that using
coloraxis for subplots with the same colorscale, the union of z value ranges is colormapped.

@Emmanuelle @empet

Thank you guys for your responses and help!
I applied coloraxis and it worked fine! It was much quicker for me as a beginner python coder and plotly user than the extended application by empet.

Anyhow great help. I am super happy with plotly.

Thanks a lot Nicolas!

Thanks for the feedback on the documentation! I will edit it to make this clearer :slight_smile:

@nicolaskruchten

Would you advise me lastly how to solve an issue deriving from this thread’s key point?

Having applied the changes suggested by @emanuelle to all the subplots but the last one (I named the coloraxis of the last subplot as ‘coloraxis2’ instead of ‘coloraxis1’) due to smaller values of the bars, I observed that the colorbar now has two sets of ticks with values that interfere. I would like to ask if it’s possible to hide the colorbar for the single trace only. Which command should I apply?

If not, how to hide the colorbar completely?

Thanks in advance for your response.

@maciekmaj the issue is that you actually have two colorbars that are overlapping: one for coloraxis1 and one for coloraxis2… You can hide one or both of them or you could resize/move them so they are both visible. The relevant settings will be under layout.coloraxis<n>.colorbar and the reference for those is here: https://plot.ly/python/reference/#layout-coloraxis-colorbar … you can set x/y/len etc to taste.