Search code examples
pythonmatplotlibcolormap

Plot sequence of colors in 1-d using associated x-values and labels by x-value and color value (Matplotlib)


Update

This question provided a different method which did more accurately display the color values but I still have x-value and label issues.

cmap_ = ListedColormap(rgb_values)

fig = plt.figure(figsize=(10,4))
ax = fig.add_axes([0.05, 0.1, 0.9, 0.85])

mpl.colorbar.ColorbarBase(ax, cmap=cmap_, orientation='horizontal')
plt.show()

Updated Figure 1

Background

I am generating custom color sequences (lists of hex values). Each color is associated with a numerical value (held in a separate list). I am attempting to plot a 1-d grid along an x-axis described by the list of numerical values and filling the cells of said grid with the color described in the color sequence. I am struggling to generate a satisfactory plot in matplotlib. Currently, I can plot the sequence of colors but I am struggling with defining the x-axis using my list of numerical values.

Example

Here is a simplified version of what I have working.

import matplotlib.pyplot as plt
from matplotlib.colors import hex2color, ListedColormap

num_values = [-10000000, -5000000, -2500000, -1000000, -500000, -250000, -100000, -50000, -10000, 0, 10000, 50000, 100000, 250000, 500000, 1000000, 2500000, 5000000, 10000000]
hex_values = ['#345f79', '#367aa3', '#368cbf', '#3690c0', '#74a9cf', '#a6bddb', '#d0d1e6', '#ece7f2', '#fff7fb', '#f0f0f0', '#ffffcc', '#ffeda0', '#fed976', '#feb24c', '#fda362', '#fc7154', '#d04c67', '#bd0026', '#a64c67']
rgb_values = [hex2color(hex) for hex in hex_values]

plt.imshow((num_values,),  cmap=ListedColormap(rgb_values))
plt.show()

I am able to generate Figure 1 with the above code.

Figure 1

Figure 1

Questions

This is not bad, but has some issues.

  1. The first issue is that the colors toward the center (which do trend gray) do not appear to plot the explicit values. Is it possible that values are being interpolated leading to these washing out in saturation?

  2. As soon as I start playing around with xticks or similar, the plot throws an error and I'm stuck. How may I configure the plot to use the num_values list as the x-tick values?

  3. I'd eventually like to add labels showing the hex value for each cell but a functioning plot is the first priority and so I have not done as much research on this question at this point in time. That said, if you have any insights here, I'd appreciate them.

References

I've reviewed a number of sources but have been unable to find a good solution.

imshow

colormaps (here they plot colormaps with imshow but I don't understand how to modify this use to my case)

Colormap Reference

Color Maps

Creating Colormaps using Matplotlib


Solution

  • imshow can work in two ways:

    • usually, it gets a 2D input, which are interpreted as scalar values which get color mapped
    • on the other hand, a 3D input is interpreted as a 2D grid of explicit rgb values

    So, the idea is to create such a 3D list for your values. [rgb_values] serves that goal.

    imshow([rgb_values]) creates a plot going from -0.5 to 18.5 on the x-axis. That way x-positions 0, 1, ..., 18 are the centers of the cells. ax.set_xticks() can then label these positions. As it is hard to fit 19 values horizontally, the labels can be rotated a bit. (I am not sure how you want to fit both the numeric and the hex labels with the limited space. Maybe place one at the top? Or create a vertical bar?)

    import matplotlib.pyplot as plt
    from matplotlib.colors import hex2color
    
    num_values = [-10000000, -5000000, -2500000, -1000000, -500000, -250000, -100000, -50000, -10000, 0, 10000, 50000, 100000, 250000, 500000, 1000000, 2500000, 5000000, 10000000]
    hex_values = ['#345f79', '#367aa3', '#368cbf', '#3690c0', '#74a9cf', '#a6bddb', '#d0d1e6', '#ece7f2', '#fff7fb', '#f0f0f0', '#ffffcc', '#ffeda0', '#fed976', '#feb24c', '#fda362', '#fc7154', '#d04c67', '#bd0026', '#a64c67']
    rgb_values = [hex2color(hex) for hex in hex_values]
    
    fig, ax = plt.subplots(figsize=(12, 3))
    ax.imshow([rgb_values], interpolation='nearest')
    ax.set_yticks([])
    # ax.set_xticks(range(len(num_values)), num_values, rotation=30)
    ax.set_xticks(range(len(hex_values)), hex_values, rotation=30)
    plt.tight_layout()
    plt.show()
    

    1D array of explicit colors