3

The ProPlot Python package adds additional features to the Matplotlib library, including colourmap manipulations. One feature that is particularly attractive to me is the ability to rotate/shift colourmaps. To give you an example:

import proplot as pplot
import matplotlib.pyplot as plt
import numpy as np

state = np.random.RandomState(51423)
data = state.rand(30, 30).cumsum(axis=1)

fig, axes = plt.subplots(ncols=3, figsize=(9, 4))
fig.patch.set_facecolor("white")

axes[0].pcolormesh(data, cmap="Blues")
axes[0].set_title("Blues")
axes[1].pcolormesh(data, cmap="Blues_r")
axes[1].set_title("Reversed Blues")
axes[2].pcolormesh(data, cmap="Blues_s")
axes[2].set_title("Rotated Blues")

plt.tight_layout()
plt.show()

enter image description here

In the third column, you see the 180° rotated version of Blues. Currently ProPlot suffers from a bug that doesn't allow the user to revert the plotting style to Matplotlib's default style, so I was wondering if there was an easy way to rotate a colourmap in Matplotlib without resorting to ProPlot. I always found cmap manipulations in Matplotlib a bit arcane, so any help would be much appreciated.

2
  • You can give each one a suitable color bar in proplot, but does that not solve the question? See this(8). Commented Nov 26, 2020 at 10:22
  • @r-beginners my question isn't about the colour bar. My problem is that ProPlot has a bug, and so I wonder if the same can be achieved with vanilla Matplotlib Commented Nov 26, 2020 at 10:29

2 Answers 2

5

If what you are trying to do is shift the colormaps, this can be done (relatively) easily:

def shift_cmap(cmap, frac):
    """Shifts a colormap by a certain fraction.

    Keyword arguments:
    cmap -- the colormap to be shifted. Can be a colormap name or a Colormap object
    frac -- the fraction of the colorbar by which to shift (must be between 0 and 1)
    """
    N=256
    if isinstance(cmap, str):
        cmap = plt.get_cmap(cmap)
    n = cmap.name
    x = np.linspace(0,1,N)
    out = np.roll(x, int(N*frac))
    new_cmap = matplotlib.colors.LinearSegmentedColormap.from_list(f'{n}_s', cmap(out))
    return new_cmap

demonstration:

x = np.linspace(0,1,100)
x = np.vstack([x,x])

cmap1 = plt.get_cmap('Blues')
cmap2 = shift_cmap(cmap1, 0.25)

fig, (ax1, ax2) = plt.subplots(2,1)
ax1.imshow(x, aspect='auto', cmap=cmap1)
ax2.imshow(x, aspect='auto', cmap=cmap2)

enter image description here

Sign up to request clarification or add additional context in comments.

Comments

1

To reverse a ListedColormap, there is a built-in reversed() but for the intended rotation, we have to create our own function.

#fake data generation 
import numpy as np
np.random.seed(123)
#numpy array containing x, y, and color
arr = np.random.random(30).reshape(3, 10)


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

def rotate_cm(co_map, deg=180): 
    #define a function where the colormap is rotated by a certain degree 
    #180° shifts by 50%, 360° no change
    n = co_map.N
    #if rotating in the opposite direction feels more intuitive, reverse the sign here
    deg = -deg%360
    if deg < 0:
        deg += 360
    cutpoint = n * deg // 360
    new_col_arr = [co_map(i) for i in range(cutpoint, n)] + [co_map(i) for i in range(cutpoint)]
    return ListedColormap(new_col_arr)
     

fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(21,7))
#any listed colormap
my_cm = plt.cm.get_cmap("inferno")

#normal color map
cb1 = ax1.scatter(*arr[:2,:], c=arr[2,:], cmap=my_cm, marker="o")
plt.colorbar(cb1, ax=ax1)
ax1.set_title("regular colormap")

#reversed colormap
cb2 = ax2.scatter(*arr[:2,:], c=arr[2,:], cmap=my_cm.reversed(), marker="o")
plt.colorbar(cb2, ax=ax2)
ax2.set_title("reversed colormap")

#rotated colormap
cb3 = ax3.scatter(*arr[:2,:], c=arr[2,:], cmap=rotate_cm(my_cm, 90), marker="o")
#you can also combine the rotation with reversed()
#cb3 = ax3.scatter(*arr[:2,:], c=arr[2,:], cmap=rotate_cm(my_cm, 90).reversed(), marker="o")
plt.colorbar(cb3, ax=ax3)
ax3.set_title("colormap rotated by 90°")


plt.show()

Sample output: ![enter image description here

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.