proplot-dev / proplot

🎨 A succinct matplotlib wrapper for making beautiful, publication-quality graphics
https://proplot.readthedocs.io
MIT License
1.07k stars 96 forks source link

Colormap modified by proplot.imshow (unexpected) #416

Open lkugler opened 1 year ago

lkugler commented 1 year ago

Hi, thank you for this tool. I think it's great as it saves a lot of time. Sometimes though, there are unexpected features (bugs?)

Description

The colormap is weird if used with proplot.

Steps to reproduce

Compare these two plots. The colormap is changed when used via proplot.

import numpy as np
import matplotlib.pyplot as plt

# load a colormap
cmap = 'ir_rgbv'
from metpy.plots import colortables
cmap = colortables.get_colortable(cmap)

# some random data
data = np.random.rand(50, 50)

# test with matplotlib
fig, ax = plt.subplots(figsize=(5, 5))
m = ax.imshow(data, cmap=cmap)
cb = fig.colorbar(m, ax=ax)
ax.set_title(cmap)
fig.savefig('test_mpl.png', dpi=100)

# test with proplot
import proplot as pplt
fig, ax = pplt.subplots(nrows=1, ncols=1, figsize=(5, 5))
m = ax.imshow(data, cmap=cmap)
cb = fig.colorbar(m, ax=ax)
ax.set_title(cmap)
fig.savefig('test_proplot.png', dpi=100)

Expected behavior: The output png should be identical

Actual behavior: Only part of the colormap is used.

Equivalent steps in matplotlib

See above.

Proplot version

0.9.5.post332

My workaround/quickfix is

wv_cols = colortables.get_colortable('ir_rgbv').reversed()
from matplotlib import colors
cmap = colors.LinearSegmentedColormap.from_list('ir_rgbv', wv_cols.colors)

import proplot as pplt
fig, ax = pplt.subplots(nrows=1, ncols=1, figsize=(5, 5))
m = ax.imshow(data, cmap=cmap)
cb = fig.colorbar(m, ax=ax)
ax.set_title(cmap)

fig.savefig('test_proplot.png', dpi=100)
lukelbd commented 1 year ago

Thanks for the report! Could you share your example images? You can click and drag the files into the comment box (you may also be able to click and drag the image displays from your interactive python session).

If you want to import ir_rgbv as a colormap with smooth gradations, changing rc['cmap.listedthresh'] to a smaller number (e.g. rc['cmap.listedthresh'] = 50) should have the same effect as your work-around. This doesn't happen by default since the colormap only has 57 levels -- maybe I'll give this setting a smaller default in the next release.

The reason for this behavior and this rc['cmap.listedthresh'] setting is that lots of external packages register "smooth", continuous colormaps as ListedColormap, even though ListedColormap was designed to handle "qualitative", discrete colormaps with abrupt color transitions -- so proplot tries to automatically figure out whether the colormap is intended to indicate "smooth" transitions when reading the colormap / converting to its own colormap subclasses. Proplot then enforces some safer standards for qualitative colormaps, e.g. ensuring we don't use the same color level twice in succession.

...however unfortunately, in the current dev version, when a qualitative colormap is detected and levels are not specified, proplot also cuts off colors above the automatically-deteremined level count (I'm guessing this is the cutting-off behavior you mentioned). But there are uncommitted changes on my machine that fix this behavior while preserving those standards I mentioned. When I commit them, the number of colorbar levels will match the number of qualitative colormap colors by default when you don't explicitly specify levels. So even if a colormap is interpreted as "qualitiatve", or when you are intentially working with qualitative colormaps, the default result should be a little less confusing / surprising.

lkugler commented 1 year ago

Hi Luke, thanks for your detailed response. Setting proplot.rc['cmap.listedthresh'] = 50 solves it too as you said. Great!

Without this line, the result was test_mpl test_proplot