proplot-dev / proplot

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

Set default color for only one level contour #182

Closed zxdawn closed 4 years ago

zxdawn commented 4 years ago

Description

contour doesn't work when only one level is available in levels.

Steps to reproduce

import proplot as plot
import pandas as pd
import numpy as np
fig, axs = plot.subplots()
state = np.random.RandomState(51423)
data = state.rand(6, 6)
data = pd.DataFrame(data, index=pd.Index(['a', 'b', 'c', 'd', 'e', 'f']))

# Line contours with labels
axs.contour(
    data.cumsum(axis=1) - 2,
    # color='gray8',
    levels=[0]
)
axs.format(title='Line contour plot with labels')

Expected behavior: Just like the color is specified:

color='gray8'

Actual behavior:

Traceback (most recent call last):
  File "/home/xin/Desktop/test.py", line 13, in <module>
    levels=[0]
  File "/home/xin/Software/miniconda3/envs/s5p/lib/python3.7/site-packages/proplot/ui.py", line 682, in _iterator
    result.append(func(*args, **kwargs))
  File "/home/xin/Software/miniconda3/envs/s5p/lib/python3.7/site-packages/proplot/axes/plot.py", line 3867, in wrapper
    return driver(self, func, *args, **kwargs)
  File "/home/xin/Software/miniconda3/envs/s5p/lib/python3.7/site-packages/proplot/axes/plot.py", line 897, in standardize_2d
    return func(self, x, y, *Zs, **kwargs)
  File "/home/xin/Software/miniconda3/envs/s5p/lib/python3.7/site-packages/proplot/axes/plot.py", line 3867, in wrapper
    return driver(self, func, *args, **kwargs)
  File "/home/xin/Software/miniconda3/envs/s5p/lib/python3.7/site-packages/proplot/internals/warnings.py", line 97, in wrapper
    return func_orig(*args, **kwargs)
  File "/home/xin/Software/miniconda3/envs/s5p/lib/python3.7/site-packages/proplot/axes/plot.py", line 2867, in cmap_changer
    minlength=(1 if name in ('contour', 'tricontour') else 2),
  File "/home/xin/Software/miniconda3/envs/s5p/lib/python3.7/site-packages/proplot/axes/plot.py", line 2552, in _build_discrete_norm
    levels, descending = pcolors._check_levels(levels)
  File "/home/xin/Software/miniconda3/envs/s5p/lib/python3.7/site-packages/proplot/colors.py", line 1760, in _check_levels
    raise ValueError(f'Levels {levels} must be 1d vector with size >= 2.')
ValueError: Levels [0] must be 1d vector with size >= 2.

Proplot version

0.6.3

lukelbd commented 4 years ago

This was due to the fact that DiscreteNorm (used for all colormaps in proplot) requires at least 2 levels. I added an edge condition to fix it -- the result of your example is now a single contour whose color is the central color of the specified (or default) colormap, which matches the behavior in matplotlib.

Example:

import proplot as plot
import pandas as pd
import numpy as np
fig, axs = plot.subplots()
state = np.random.RandomState(51423)
data = state.rand(6, 6)
data = pd.DataFrame(data, index=pd.Index(['a', 'b', 'c', 'd', 'e', 'f']))

# Line contours with labels
axs.contour(
    data.cumsum(axis=1) - 2,
    cmap='grays',
    levels=[0],
)
axs.format(title='Line contour plot with labels')

tmp

zxdawn commented 4 years ago

Thanks Luke! Nice fix ;)