Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Python discrete colormap use #49

Open
Nkehoe-QUB opened this issue Jan 17, 2025 · 5 comments
Open

Python discrete colormap use #49

Nkehoe-QUB opened this issue Jan 17, 2025 · 5 comments

Comments

@Nkehoe-QUB
Copy link

Hello,

I am trying to use the discrete version of the colourmaps but it just throws errors.

fig,ax = plt.subplots()
cax = ax.pcolormesh(x, y, data.T, norm=cm.LogNorm(), cmap=cmaps.batlow20)
cbar = fig.colorbar(cax)
plt.show()

My understanding from the documentation is that this should split Batlow into 20 discrete colour bins but I just get the following error:

AttributeError: module 'cmcrameri.cm' has no attribute 'batlow20'

Any assistance would be appreciated.

@callumrollo
Copy link
Owner

Hi @Nkehoe-QUB

You should be able to use matplotlib.color.BoundaryNorm to normalize the colormaps to whatever number of discrete intervals you want. For 20 bins, the example would be like this:

import cmcrameri.cm as cmc
import matplotlib.pyplot as plt
import numpy as np
import matplotlib 

x = np.linspace(0, 1, 100)[np.newaxis, :]
levels = np.linspace(0,1,20) # change 20 to whatever number of levels you want
cmap =cmc.batlow
norm = matplotlib.colors.BoundaryNorm(levels, cmap.N)
plt.imshow(x, aspect='auto', cmap=cmap, norm = norm)
plt.axis('off')
plt.show()

Image

Does this work for your use case?

@burggraaff
Copy link

cmap=cmaps.batlow.resampled(20) also works in your application

@callumrollo
Copy link
Owner

I didn't even know you could do that resampling! Way more elegant. Thanks @burggraaff I'm putting that in the README

@Zerosimi
Copy link

Zerosimi commented Feb 3, 2025

I really like the resampling approach. Makes it really simple to have the discrete colormap. I noticed however, that the resampling did not behave as expected for the categorical colormap. I was hoping for the first 5 colors of the categorical colormap, as they are picked to have high contrast, but it selects colors from the whole color range, which in this case does look worse than the non-categorical colormap. See below

import numpy as np
import matplotlib.pyplot as plt
import cmcrameri as cmc

# Data generation
np.random.seed(42)
x = np.random.uniform(-1, 1, 250)
y = np.random.uniform(-1, 1, 250)
categorical_data = np.random.randint(0, 5, size=250)

fig = plt.figure()

im = plt.scatter(x, y, c=categorical_data, cmap=cmc.cm.batlowS.resampled(5))
plt.colorbar(im)
plt.title("batlowS.resampled(5)")

plt.show()
plt.close()

Image
Image

@burggraaff
Copy link

@Zerosimi The .resampled method comes from matplotlib and its qualitative/categorical colour maps have the same behaviour, as you can see below where I compare viridis (sequential, continuous) and Dark2 (qualitative, discrete):

Image

Correct me if I'm wrong, but I think it's just a consequence of the way these colour maps are implemented in matplotlib: not as a list of N colours, but as a continuous range from 0..1 with N discrete values assigned to equally spaced sections. If you want to change the behaviour of .resampled, you'll have to do it in matplotlib itself.

As a workaround for selecting the first N colours, you can define a new cmap based on that range. Here's an example where I wanted to resample devon without the near-white bits at the far end:

from cmcrameri import cm as cmc
from matplotlib.colors import LinearSegmentedColormap

N_colours = 12
devon_discrete = LinearSegmentedColormap.from_list("devon_discrete", cmc.devon.colors[:-20]).resampled(N_colours)

Here's a comparison of the result with different limits (the last colour in the first bar might be hard to make out compared to the white background):

Image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants