colorcetを用いて均一なカラーバーを作成する

# はじめに
カラーマップの色を調べていた時に`colorcet`というライブラリを見つけたので紹介します。
`colorcet`は均一な色のカラーバーを作成してくれるライブラリです。

# 環境

Mac OS
Python 3.9.1

colorcet 2.0.6
matplotlib 3.3.3
numpy 1.19.2

`pip install colorcet matplotlib numpy`

# colorcet

以下のサイトから引用します。
[colorcet 1.0.0 documentation](https://colorcet.holoviz.org/)

> Background
Apart from the four uniform colormaps now provided with matplotlib, most continuous colormaps shipping with Python plotting programs are highly perceptually nonuniform. That is, small changes in data values result in large changes in the perceptual appearance of the corresponding colors, or vice versa. For instance, the popular matplotlib "hot" and "jet" colormaps have long stretches where the apparent colors change imperceptibly, such as the yellow region in "hot" and the cyan/green region in "jet":
When colormaps are used for visualizing scientific datasets, these perceptual nonlinearities can make interpretation of this data very difficult, because false boundaries appear in the data, and genuine boundaries and changes can be obscured.

大体の訳

- matplotlibのカラーマップは色の範囲が見た目的に不均一だよ
- 可視化の時に不均一なカラーマップを使用するとデータの解釈が困難になるよ

１行目がmatplotlibのカラーマップ(jet, hot)
2行目がjet, hotに対応した`colorcet`のカラーマップ
<img width=500 alt='colorbars_.png' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/779817/f66f290c-34c0-e61a-a1d3-8e4630543026.png'>

matplotlibのカラーバーに赤線が引かれてある個所は、パッと見た時に色の違いがあまりわかりません。
その為この範囲のデータの解釈が難しくなってしまいます。
この問題を解決するのが`colorcet`です。

以下にサンプルのカラーパレットがあります。
[colorcet/named.png at master · holoviz/colorcet · GitHub](https://github.com/holoviz/colorcet/blob/master/examples/assets/images/named.png)

※ 翻訳間違えていたら申し訳ありません

# 詳細

`colorcet.***`, `colorcet.b_***`は16進数のリスト
`colorcet.m_***`は`matplotlib`の`LinearSegmentedColormap`
で取得できます

## リストで受け取る

```python
import colorcet as cc

rainbow = cc.rainbow
# >>> ['#0034f8', '#0037f6', ..., '#ff2d00', '#ff2a00']
rainbow_l = len(rainbow)
# >>> 256
```

colorcet.palateから文字列を使用して取得することもできます

```python
rainbow = cc.palette['rainbow']
```

その他パレット例

```python

# その他

# blue, green, yellow, red
b_rain = cc.b_rainbow_bgyr_35_85_c72
# blue, green, yellow, red, magenta
b_rain2 = cc.b_rainbow_bgyrm_35_85_c71

fire = cc.fire

```

## `LinearSegmentedColormap`で受け取る

```python
import colorcet as cc

rainbow = cc.m_rainbow_bgyr_35_85_c73
print(rainbow.N)
# >>> 256
print(type(rainbow))
# >>> <class 'matplotlib.colors.LinearSegmentedColormap'>
```

colorcet.cmから文字列で取得することもできます

```python
r = cc.cm['rainbow_bgyr_35_85_c73']
```

その他パレット例

```python

# blue, green, yellow, red
m_rain = cc.m_rainbow_bgyr_35_85_c72
# blue, green, yellow, red, magenta
m_rain2 = cc.m_rainbow_bgyrm_35_85_c71

fire = cc.m_fire
# reverse
fire_r = cc.m_fire_r

```


# 使用例
## matplotlib

```python
import colorcet as cc
import numpy as np
import matplotlib.pyplot as plt

X, Y = np.linspace(0, 10, 101), np.linspace(0, 10, 101)
XX, YY = np.meshgrid(X, Y)
Z = np.sin(XX) + np.cos(YY)

fig, ax = plt.subplots()

cmap = cc.m_rainbow_bgyrm_35_85_c71

colormap = ax.pcolormesh(XX, YY, Z, cmap=cmap)
fig.colorbar(colormap)

plt.show()

```

<img width=500 alt='mat_ex.png' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/779817/a0f3ffb0-509d-0e54-11f1-c37124d62aec.png'>

## pyqtgraph
自分がよく使うのでついでに

```terminal
pip install PyQt5 pyqtgraph pgcolorbar
```

```python
import colorcet as cc
import numpy as np
from PyQt5 import QtWidgets
from pgcolorbar.colorlegend import ColorLegendItem
import pyqtgraph as pg


def make_lookup_table_b() -> np.ndarray:
    """colorcet.b_***を使用してlookup table作成"""

    def hex_to_rgb(hex_: str) -> list:
        h = hex_.lstrip('#')
        return [int(h[i:i + 2], 16) for i in (0, 2, 4)]

    cmap = cc.b_rainbow_bgyrm_35_85_c71

    rgb = list(map(hex_to_rgb, cmap))
    lookup_table = np.array(rgb, dtype=np.uint8)
    return lookup_table


def make_lookup_table_m() -> np.ndarray:
    """colorcet.m_***を使用してlookup table作成"""

    cmap = cc.m_rainbow_bgyrm_35_85_c71

    rgb = np.array([cmap(i)[:-1] for i in range(cmap.N)]) * 255
    lookup_table = rgb.astype(np.uint8)
    return lookup_table


class Colormap(QtWidgets.QGraphicsWidget):
    def __init__(self, *args, **kwargs) -> None:
        super(Colormap, self).__init__(*args, **kwargs)

        self.image = pg.ImageItem(axisOrder='row-major')
        self.image.setLookupTable(make_lookup_table_b())

        self.view_box = pg.ViewBox(lockAspect=True)
        self.view_box.addItem(self.image)

        self.plot = pg.PlotItem(viewBox=self.view_box)

        self.color_bar = ColorLegendItem(imageItem=self.image)

        self.layout = QtWidgets.QGraphicsGridLayout()
        self.layout.setContentsMargins(1, 1, 1, 1)
        self.layout.setSpacing(0)
        self.layout.addItem(self.plot, 0, 0)
        self.layout.addItem(self.color_bar, 0, 1)
        self.setLayout(self.layout)


if __name__ == '__main__':
    import sys

    X, Y = np.linspace(0, 10, 101), np.linspace(0, 10, 101)
    XX, YY = np.meshgrid(X, Y)
    Z = np.sin(XX) + np.cos(YY)

    app = QtWidgets.QApplication(sys.argv)

    colormap = Colormap()
    colormap.image.setImage(Z)
    colormap.color_bar.resetColorLevels()

    window = pg.GraphicsLayoutWidget()
    window.addItem(colormap)
    window.show()

    sys.exit(app.exec_())

```

<img width=500 alt='pyqtgraph_ex.png' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/779817/8cae76b0-a1d2-9aa6-e833-71f8efa612f3.png'>


# 参考
[colorcet 1.0.0 documentation](https://colorcet.holoviz.org/)
[GitHub - holoviz/colorcet: A set of useful perceptually uniform colormaps for plotting scientific data](https://github.com/holoviz/colorcet)