Coloring Plotly Box-Plots. Applying a custom color scale to Plotly... | by Shah Newaz Khan | Towards Data Science

I was recently asked by my boss to apply a color scale to a series of Plotly Box plots I was working on for a Dash application. The notion was to plot multiple box plots on the same graph and have each box plot be darker or lighter based on its distance from the overall median in the dataset.
The issue here is that Plotly only supports color scales for heatmaps, scatter plots & contour plots.
I will demonstrate the default behavior by plotting some generated data for Canucks players +/- per game all time as follows:
Note: Complete code at the end of the post
The dashed green line represents the NHL league average +/- per game at +2.0, what my boss wanted was to color each box plot darker or lighter based on how far away each players median +/- value was from the league average .
Given that I was already in a Python environment, I chose to use the colormap & colormap normalizer features from the Matplotlib Python module.
First step was to import Matplotlib:
import matplotlib.pyplot as pltimport matplotlibimport pandas as pd
Then determine the minand maxvalues in the dataset:
x_data = ['Henrik Sedin', 'Daniel Sedin',          'Brock Boeser', 'Elias Pettersen',          'Bo Horvat', 'Pavel Bure',]# Generate random datay0 = np.random.randn(50)+4y1 = np.random.randn(50)+4y2 = np.random.randn(50)+2y3 = np.random.randn(50)+2y4 = np.random.randn(50)+1y5 = np.random.randn(50)+3y_data = [y0,y1,y2,y3,y4,y5]df = pd.DataFrame(y_data)vmin, vmax = df.min().min(), df.max().max()
Initialize the Matplotlib cmap & normalizer:
norm = matplotlib.colors.Normalize(vmin=vmin, vmax=vmax)cmap = matplotlib.cm.get_cmap('GnBu') # green to blue color way
Find the median of each y_data and use the normalizer to map it to an appropriate color based on the median value:
for xd, yd in zip(x_data, y_data):                median = np.median(yd) # find the median        color = 'rgb' + str(cmap(norm(median))[0:3]) # normalize                traces.append(go.Box(            y=yd,            name=xd,            boxpoints='all',            jitter=0.5,            whiskerwidth=0.2,            fillcolor=color,      # add the box plot color            marker=dict(                size=2,            ),            line=dict(width=1)        ))
The resulting plot will render a darker fillcolorthe further positive the players median +/- is from the league average and vice versa.
Here is the complete code to get the result above:
from plotly import __version__from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplotinit_notebook_mode(connected=True)import plotly.graph_objs as goimport numpy as npimport pandas as pdimport matplotlib.pyplot as pltimport matplotlibx_data = ['Henrik Sedin', 'Daniel Sedin',          'Brock Boeser', 'Elias Pettersen',          'Bo Horvat', 'Pavel Bure',]y0 = np.random.randn(50)+4y1 = np.random.randn(50)+4y2 = np.random.randn(50)+2y3 = np.random.randn(50)+2y4 = np.random.randn(50)+1y5 = np.random.randn(50)+3y_data = [y0,y1,y2,y3,y4,y5]traces = []df = pd.DataFrame(y_data)vmin, vmax = df.min().min(), df.max().max()norm = matplotlib.colors.Normalize(vmin=vmin, vmax=vmax)cmap = matplotlib.cm.get_cmap('GnBu')for xd, yd in zip(x_data, y_data):        median = np.median(yd)        color = 'rgb' + str(cmap(norm(median))[0:3])                traces.append(go.Box(            y=yd,            name=xd,            boxpoints='all',            jitter=0.5,            whiskerwidth=0.2,            fillcolor=color,            marker=dict(                size=2,                color='rgb(0, 0, 0)'            ),            line=dict(width=1),        ))layout = go.Layout(    title='Canucks all time +/- per game',    yaxis=dict(        autorange=True,        showgrid=True,        zeroline=True,        dtick=5,        gridcolor='rgb(255, 255, 255)',        gridwidth=1,        zerolinecolor='rgb(255, 255, 255)',        zerolinewidth=2,    ),    margin=dict(        l=40,        r=30,        b=80,        t=100,    ),    paper_bgcolor='rgb(243, 243, 243)',    plot_bgcolor='rgb(243, 243, 243)',    showlegend=False,    shapes= [{      'type': 'line',      'x0': -1,      'y0': 2,      'x1': 6,      'y1': 2,      'line': {        'color': 'rgb(50, 171, 96)',        'width': 4,        'dash': 'dashdot'      }    }])fig = go.Figure(data=traces, layout=layout)iplot(fig)