✊🏿 Black Lives Matter. Please consider donating to Black Girls Code today.
⚡️ Concerned about the grid? Kyle Baranko teaches how to predicting peak loads using XGBoost. Register for the August webinar!

Logarithmic normalization for colorscale/colorbar?

Is there a proper way to display log-normal values with a colorscale and colobar with Scatter3d? The options found at https://plotly.com/python/colorscales/ are not sufficient because they do not show the lower values—which are the ones of interest. Is there some way to do a log normalization like in matplotlib?

In the example below, consider val which has a log normal distribution and is indexed by x, y, z which are linear. Notice how in plotly the data are mostly blue and in matplotlib the whole colormap is used.

import plotly
import plotly.graph_objs as go


x = np.random.uniform(1, 100, 100)
y = np.random.uniform(1, 100, 100)
z = np.random.uniform(1, 100, 100)
val = np.random.lognormal(8, 1, 100)

trace1 = go.Scatter3d(x=x,
                      y=y,
                      z=z,
                      mode='markers',
                      marker=dict(
                          color=val,
                          showscale=True,
                          size=8,
                          colorscale='rdylbu_r',
                          #colorscale=[[0, 'rgb(250, 250, 250)'],        #0   # from plotly docs
                                     #[1./10000, 'rgb(200, 200, 200)'],  #10
                                     #[1./1000, 'rgb(150, 150, 150)'],   #100
                                     #[1./100, 'rgb(100, 100, 100)'],    #1000
                                     #[1./10, 'rgb(50, 50, 50)'],        #10000
                                     #[1., 'rgb(0, 0, 0)'],       ],     #100000
                          colorbar=dict(x=0.8),
                     ))


                             
                      
layout = go.Layout(scene=dict(xaxis=dict(title='x'),
                              yaxis=dict(title='y'),
                              zaxis=dict(title='z'),
                              ))
                   
data = [trace1]

fig = go.Figure(data=data, layout=layout)

plotly.offline.plot(fig, filename='log-test.html')
import matplotlib as mpl
import matplotlib.pyplot as plt

fig = plt.figure(dpi=125)
ax = fig.gca(projection='3d')

cax = ax.scatter(x, y, z, c=val, 
                 cmap=plt.cm.RdYlBu_r, 
                 norm=mpl.colors.LogNorm(vmin=val.min(), vmax=val.max())
                )
fig.colorbar(cax)
plt.show()

My apologies, I found the answer (below) however, it may be nice to have a colorscale type = log feature.

import plotly
import plotly.graph_objs as go


x = np.random.uniform(1, 100, 100)
y = np.random.uniform(1, 100, 100)
z = np.random.uniform(1, 100, 100)
val = np.random.lognormal(8, 1, 100)

tickvals = [1e2, 2e2, 3e2, 4e2, 5e2, 6e2, 7e2, 8e2, 9e2, 1e2,
            1e3, 2e3, 3e3, 4e3, 5e3, 6e3, 7e3, 8e3, 9e3, 1e4,
            2e4, 3e4, 4e4]

trace1 = go.Scatter3d(x=x,
                      y=y,
                      z=z,
                      mode='markers',
                      marker=dict(
                          color=np.log10(val),
                          showscale=True,
                          size=8,
                          colorscale='rdylbu_r',
                          colorbar=dict(
                              x=0.8,
                              tickvals=np.log10(tickvals),
                              ticktext=tickvals,
                          ),                          
                     ))


                             
                      
layout = go.Layout(scene=dict(xaxis=dict(title='x'),
                              yaxis=dict(title='y'),
                              zaxis=dict(title='z'),
                              ))
                   
data = [trace1]

fig = go.Figure(data=data, layout=layout)

plotly.offline.plot(fig, filename='log-test.html')