Search code examples
pythonmatplotlibscatter-plotcolorbar

My colorbar doesn't show the right colors (Python, matplotlib)


I'm stuck trying to get my colorbar to show the same colorspectrum as my scatterplot. Instead of the pink/purple to black spectrum of my colorgraded datapoints, it shows the default colors of a colorbar. I have read multiple other threads on here to no avail, but please alert me to a similar thread, if I have missed something that could solve my problem.

I have made a short code illustrating my problem:

import numpy as np
import matplotlib.pyplot as plt

rng = np.random.default_rng()
arr = np.arange(7000)
rng.shuffle(arr)
r = np.sqrt(np.random.random(7000))
theta = np.random.uniform(high = 2*np.pi, size = 7000)
X = np.array(r*np.cos(theta))
Y = np.array(r*np.sin(theta))

def values_to_colormap(values):
    values_scale = values/np.max(values)
    (a,) = np.shape(values)
    cmap = values_scale.reshape(a,1)*np.array([[0.6, 0.4, 0.6]])
    return cmap

points_colors = values_to_colormap(arr)

ps = plt.scatter(X,Y, marker = '.', color = points_colors)
plt.colorbar(ps, orientation='horizontal')
plt.axis('equal')
plt.show();

My resulting plot and colorbar


Solution

  • The colorbar uses the cmap and the norm of the scatter plot. In this case, individual colors are given, and the colorbar falls back to the default colormap ('viridis') and the default norm (as no vmin nor vmax nor explicit color values are given, 0 and 1 are used).

    Your values_to_colormap function maps 0 to color (0, 0, 0) and the maximum value to (0.6, 0.4, 0.6). This is equivalent to use a norm with vmin=0, vmax=arr.max() and a LinearSegmentedColormap between the given colors:

    import numpy as np
    import matplotlib.pyplot as plt
    from matplotlib.colors import LinearSegmentedColormap
    
    rng = np.random.default_rng()
    arr = np.arange(7000)
    rng.shuffle(arr)
    r = np.sqrt(np.random.random(7000))
    theta = np.random.uniform(high=2 * np.pi, size=7000)
    X = np.array(r * np.cos(theta))
    Y = np.array(r * np.sin(theta))
    
    ps = plt.scatter(X, Y, marker='.', c=arr, vmin=0, vmax=arr.max(),
                     cmap=LinearSegmentedColormap.from_list('', [(0, 0, 0), (0.6, 0.4, 0.6)]))
    plt.colorbar(ps, orientation='horizontal')
    plt.axis('equal')
    plt.show()
    

    Using a LinearSegmentedColormap to generate the colorbar