Source code for xoa.color
# -*- coding: utf-8 -*-
"""
Colors and colormaps utilities
"""
# Copyright 2020-2026 Shom
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import cmocean
import matplotlib.pyplot as plt
from . import exceptions
[docs]
def crop_cmap(cmapin, vmin, vmax, pivot=0):
"""Crop a colormap so that it is centered around pivot
This is a wrapper for :func:`cmocean.tools.crop`.
Parameters
----------
cmapin: colormap
Compatible with :func:`matplotlib.pyplot.get_cmap`.
vmin: float
Min data value
vmax: float
Max data value
pivot: float
The colormap will be centered on this value.
Should be lower than vmax and greater than vmin.
"""
cmapin = plt.get_cmap(cmapin)
return cmocean.tools.crop(cmapin, vmin, vmax, pivot)
[docs]
class CmapAdapter(object):
"""Adapt a given colormap to data
Parameters
----------
cmap:
The colormap to adapt
specs: str, None
Transformation specifications or None.
When a string, it must have the format ``"<type><value>"``, where
type is ``"piv"`` or ``"cyc"``, and value is convertible to a float.
If type is ``"piv"``, that colormap is expected typically
to be **diverging**, and is cropped
using :func:`crop_cmap`, after min and max value are set with
:meth:`set_vlim`.
If type is ``"cyc"``, min is set to 0 and max to ``value``,
and the colormap is
expected to be **circular**, like ``"cmo.phase"``.
Example
-------
.. ipython:: python
@suppress
from xoa.color import CmapAdapter
@suppress
import matplotlib.pyplot as plt, numpy as np
cma = CmapAdapter('cmo.balance', 'piv0')
data = np.arange(100).reshape(10, 10) - 20
cma.set_vlim(data.min(), data.max())
plt.contourf(data, **cma.get_dict());
@savefig api.color.cmapadapter.png
plt.colorbar();
"""
[docs]
def __init__(self, cmap, specs=None):
self.cmap = plt.get_cmap(cmap)
self.vmin = self.vmax = None
if specs is None:
self.specs = None
if specs.startswith("piv"):
self.specs = ("pivot", float(specs[3:]))
elif specs.startswith("cyc"):
self.specs = ("cycle", float(specs[3:]))
self.vmin = 0
self.vmax = self.specs[1]
[docs]
def set_vlim(self, vmin, vmax):
"""Set the min and max data value for scaling"""
if self.specs and self.specs[0] == "cycle":
vmin, vmax = 0, 360.0
self.vmin = vmin
self.vmax = vmax
return vmin, vmax
[docs]
def get_cmap(self):
"""Get the adapted colormap"""
if self.specs[0] == "pivot":
if self.vmin is None or self.vmax is None:
exceptions.xoa_warn("cmap not adapted since vmin and vmax are not set")
return self.cmap
return crop_cmap(self.cmap, self.vmin, self.vmax, self.specs[1])
[docs]
def get_dict(self):
"""The specs for plots as a dict whose keys are cmap, vmin and vmax"""
return dict(cmap=self.get_cmap(), vmin=self.vmin, vmax=self.vmax)