Matplotlib でカラーマップを選択する#

Matplotlib には、 経由でアクセスできる多数の組み込みカラーマップがあります matplotlib.colormaps。多くの追加のカラーマップを持つ外部ライブラリもあり 、Matplotlib ドキュメントのサードパーティ カラーマップセクションで表示できます。ここでは、多くのオプションから選択する方法について簡単に説明します。独自のカラーマップを作成する方法については、 Creating Colormaps in Matplotlibを参照してください。

概要#

適切なカラーマップを選択する背後にある考え方は、データ セットの 3D 色空間で適切な表現を見つけることです。任意のデータ セットに最適なカラーマップは、次のような多くの要素に依存します。

  • フォーム データまたはメトリック データを表すかどうか ( [Ware] )

  • データ セットに関する知識 (たとえば、他の値が逸脱する重要な値はありますか?)

  • プロットしているパラメーターに直感的な配色がある場合

  • その分野に標準がある場合、聴衆は期待しているかもしれません

多くのアプリケーションでは、知覚的に均一なカラーマップが最適です。つまり、データ内の等しいステップが色空間内の等しいステップとして認識されるカラーマップです。研究者は、人間の脳が明度パラメーターの変化を、たとえば色相の変化よりもデータの変化としてよりよく認識することを発見しました。したがって、カラーマップを通じて明度が単調に増加するカラーマップは、ビューアによってより適切に解釈されます。知覚的に均一なカラーマップの素晴らしい例は、 サードパーティのカラーマップセクションにもあります。

色は 3D 空間でさまざまな方法で表現できます。色を表現する 1 つの方法は、CIELAB を使用することです。CIELABでは色空間を明度で表現し、 \(L^*\); 赤、緑、\(a^*\); そしてイエローブルー、\(b^*\). 明度パラメータ\(L^*\)次に、matplotlib カラーマップが視聴者にどのように認識されるかについて詳しく知るために使用できます。

カラーマップに対する人間の認識について学習するための優れた開始リソースは、[IBM]にあります。

カラーマップのクラス#

カラーマップは、多くの場合、その機能に基づいていくつかのカテゴリに分割されます ( 例: [Moreland]を参照)。

  1. シーケンシャル: 明度と多くの場合、色の彩度を段階的に変化させます。多くの場合、単一の色相を使用します。順序のある情報を表すために使用する必要があります。

  2. 発散: 彩度の低い色で中間にある 2 つの異なる色の明度と彩度の変化。地形など、プロットされる情報に重要な中間値がある場合、またはデータがゼロ付近で逸脱している場合に使用する必要があります。

  3. Cyclic: 不飽和色の中間と開始/終了で交わる 2 つの異なる色の明るさの変化。位相角、風向、時刻など、エンドポイントでラップアラウンドする値に使用する必要があります。

  4. 質的: 多くの場合、さまざまな色です。順序または関係を持たない情報を表すために使用する必要があります。

import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from colorspacious import cspace_converter

まず、各カラーマップの範囲を示します。他のものよりも「速く」変化するように見えるものがあることに注意してください。

cmaps = {}

gradient = np.linspace(0, 1, 256)
gradient = np.vstack((gradient, gradient))


def plot_color_gradients(category, cmap_list):
    # Create figure and adjust figure height to number of colormaps
    nrows = len(cmap_list)
    figh = 0.35 + 0.15 + (nrows + (nrows - 1) * 0.1) * 0.22
    fig, axs = plt.subplots(nrows=nrows + 1, figsize=(6.4, figh))
    fig.subplots_adjust(top=1 - 0.35 / figh, bottom=0.15 / figh,
                        left=0.2, right=0.99)
    axs[0].set_title(f'{category} colormaps', fontsize=14)

    for ax, name in zip(axs, cmap_list):
        ax.imshow(gradient, aspect='auto', cmap=mpl.colormaps[name])
        ax.text(-0.01, 0.5, name, va='center', ha='right', fontsize=10,
                transform=ax.transAxes)

    # Turn off *all* ticks & spines, not just the ones with colormaps.
    for ax in axs:
        ax.set_axis_off()

    # Save colormap list for later.
    cmaps[category] = cmap_list

Sequential プロットの場合、明度の値はカラーマップを通じて単調に増加します。これはいい。いくつかの\(L^*\)カラーマップの値は 0 から 100 (バイナリおよびその他のグレースケール) の範囲で、他の値は約 \(L^*=20\). 範囲が狭いもの\(L^*\)したがって、知覚範囲が狭くなります。また、\(L^*\)関数はカラーマップ間で異なります。一部はほぼ線形です\(L^*\)その他はより湾曲しています。

plot_color_gradients('Perceptually Uniform Sequential',
                     ['viridis', 'plasma', 'inferno', 'magma', 'cividis'])
知覚的に均一な順次カラーマップ
plot_color_gradients('Sequential',
                     ['Greys', 'Purples', 'Blues', 'Greens', 'Oranges', 'Reds',
                      'YlOrBr', 'YlOrRd', 'OrRd', 'PuRd', 'RdPu', 'BuPu',
                      'GnBu', 'PuBu', 'YlGnBu', 'PuBuGn', 'BuGn', 'YlGn'])
順次カラーマップ

シーケンシャル2 #

多くの\(L^*\)Sequential2 プロットの値は単調に増加していますが、一部 (秋、寒冷、春、冬) は横ばいになるか、上下に変化します。\(L^*\)スペース。その他 (afmhot、copper、gist_heat、および hot) には、\(L^*\)機能。プラトーまたはキンクにあるカラーマップの領域で表されているデータは、カラーマップ内のそれらの値のデータのバンディングの認識につながります (この優れた例については、[mycarta-banding]を参照してください)。

plot_color_gradients('Sequential (2)',
                     ['binary', 'gist_yarg', 'gist_gray', 'gray', 'bone',
                      'pink', 'spring', 'summer', 'autumn', 'winter', 'cool',
                      'Wistia', 'hot', 'afmhot', 'gist_heat', 'copper'])
順次 (2) カラーマップ

発散#

発散マップの場合、単調に増加する必要があります\(L^*\) に近いはずの最大値までの値\(L^*=100\)、続いて単調減少\(L^*\)値。ほぼ等しい最小値を探しています\(L^*\)カラーマップの両端の値。これらの手段により、BrBG と RdBu は適切なオプションです。coolwarm は良いオプションですが、広範囲に及ぶわけではありません。\(L^*\)値 (以下のグレースケールのセクションを参照)。

plot_color_gradients('Diverging',
                     ['PiYG', 'PRGn', 'BrBG', 'PuOr', 'RdGy', 'RdBu', 'RdYlBu',
                      'RdYlGn', 'Spectral', 'coolwarm', 'bwr', 'seismic'])
発散カラーマップ

サイクリック#

巡回マップの場合、同じ色で開始および終了し、中央で対称的な中心点を満たしたいと考えています。\(L^*\)最初から中間までは単調に変化し、中間から最後までは逆に変化するはずです。増加側と減少側で対称で、色相のみが異なる必要があります。端と真ん中に、\(L^*\)で平滑化する必要がある方向を逆にします \(L^*\)アーティファクトを減らすスペース。巡回写像の設計の詳細については、[kovesi-colormaps]を参照してください。

よく使用される HSV カラーマップは、中心点に対して対称ではありませんが、このカラーマップのセットに含まれています。さらに、\(L^*\)値はカラーマップ全体で大きく異なるため、閲覧者が知覚的に見るデータを表すには適していません。[mycarta-jet]でこのアイデアの拡張を参照してください 。

plot_color_gradients('Cyclic', ['twilight', 'twilight_shifted', 'hsv'])
巡回カラーマップ

定性的#

質的カラーマップは知覚マップを目的としていませんが、明度パラメータを見ることでそれを確認できます。の\(L^*\)値はカラーマップ全体にわたって移動し、明らかに単調増加していません。これらは、知覚カラーマップとして使用するのに適したオプションではありません。

plot_color_gradients('Qualitative',
                     ['Pastel1', 'Pastel2', 'Paired', 'Accent', 'Dark2',
                      'Set1', 'Set2', 'Set3', 'tab10', 'tab20', 'tab20b',
                      'tab20c'])
定性的カラーマップ

その他#

その他のカラーマップの中には、作成された特定の用途があるものがあります。たとえば、gist_earth、ocean、terrain はすべて、地形 (緑/茶色) と水深 (青) を一緒にプロットするために作成されているようです。その場合、これらのカラーマップに発散が見られると予想されますが、gist_earth や Terrain などのように、複数のキンクは理想的ではない可能性があります。CMRmap は、グレースケールに適切に変換するように作成されていますが、いくつかの小さなねじれがあるように見えます。 \(L^*\). cubehelix は、明度と色相の両方が滑らかに変化するように作成されましたが、緑の色相領域に小さなこぶがあるように見えます。Turbo は、深度と視差のデータを表示するために作成されました。

このカラーマップ セットには、よく使用されるジェット カラーマップが含まれています。我々はそれを見ることができます\(L^*\)値はカラーマップ全体で大きく異なるため、閲覧者が知覚的に見るデータを表すには適していません。[mycarta-jet][turbo]でこのアイデアの拡張を参照してください。

plot_color_gradients('Miscellaneous',
                     ['flag', 'prism', 'ocean', 'gist_earth', 'terrain',
                      'gist_stern', 'gnuplot', 'gnuplot2', 'CMRmap',
                      'cubehelix', 'brg', 'gist_rainbow', 'rainbow', 'jet',
                      'turbo', 'nipy_spectral', 'gist_ncar'])

plt.show()
その他のカラーマップ

Matplotlib カラーマップの明るさ#

ここでは、matplotlib カラーマップの明度の値を調べます。カラーマップに関するいくつかのドキュメントが利用可能であることに注意してください ( [list-colormaps] )。

mpl.rcParams.update({'font.size': 12})

# Number of colormap per subplot for particular cmap categories
_DSUBS = {'Perceptually Uniform Sequential': 5, 'Sequential': 6,
          'Sequential (2)': 6, 'Diverging': 6, 'Cyclic': 3,
          'Qualitative': 4, 'Miscellaneous': 6}

# Spacing between the colormaps of a subplot
_DC = {'Perceptually Uniform Sequential': 1.4, 'Sequential': 0.7,
       'Sequential (2)': 1.4, 'Diverging': 1.4, 'Cyclic': 1.4,
       'Qualitative': 1.4, 'Miscellaneous': 1.4}

# Indices to step through colormap
x = np.linspace(0.0, 1.0, 100)

# Do plot
for cmap_category, cmap_list in cmaps.items():

    # Do subplots so that colormaps have enough space.
    # Default is 6 colormaps per subplot.
    dsub = _DSUBS.get(cmap_category, 6)
    nsubplots = int(np.ceil(len(cmap_list) / dsub))

    # squeeze=False to handle similarly the case of a single subplot
    fig, axs = plt.subplots(nrows=nsubplots, squeeze=False,
                            figsize=(7, 2.6*nsubplots))

    for i, ax in enumerate(axs.flat):

        locs = []  # locations for text labels

        for j, cmap in enumerate(cmap_list[i*dsub:(i+1)*dsub]):

            # Get RGB values for colormap and convert the colormap in
            # CAM02-UCS colorspace.  lab[0, :, 0] is the lightness.
            rgb = mpl.colormaps[cmap](x)[np.newaxis, :, :3]
            lab = cspace_converter("sRGB1", "CAM02-UCS")(rgb)

            # Plot colormap L values.  Do separately for each category
            # so each plot can be pretty.  To make scatter markers change
            # color along plot:
            # https://stackoverflow.com/q/8202605/

            if cmap_category == 'Sequential':
                # These colormaps all start at high lightness but we want them
                # reversed to look nice in the plot, so reverse the order.
                y_ = lab[0, ::-1, 0]
                c_ = x[::-1]
            else:
                y_ = lab[0, :, 0]
                c_ = x

            dc = _DC.get(cmap_category, 1.4)  # cmaps horizontal spacing
            ax.scatter(x + j*dc, y_, c=c_, cmap=cmap, s=300, linewidths=0.0)

            # Store locations for colormap labels
            if cmap_category in ('Perceptually Uniform Sequential',
                                 'Sequential'):
                locs.append(x[-1] + j*dc)
            elif cmap_category in ('Diverging', 'Qualitative', 'Cyclic',
                                   'Miscellaneous', 'Sequential (2)'):
                locs.append(x[int(x.size/2.)] + j*dc)

        # Set up the axis limits:
        #   * the 1st subplot is used as a reference for the x-axis limits
        #   * lightness values goes from 0 to 100 (y-axis limits)
        ax.set_xlim(axs[0, 0].get_xlim())
        ax.set_ylim(0.0, 100.0)

        # Set up labels for colormaps
        ax.xaxis.set_ticks_position('top')
        ticker = mpl.ticker.FixedLocator(locs)
        ax.xaxis.set_major_locator(ticker)
        formatter = mpl.ticker.FixedFormatter(cmap_list[i*dsub:(i+1)*dsub])
        ax.xaxis.set_major_formatter(formatter)
        ax.xaxis.set_tick_params(rotation=50)
        ax.set_ylabel('Lightness $L^*$', fontsize=12)

    ax.set_xlabel(cmap_category + ' colormaps', fontsize=14)

    fig.tight_layout(h_pad=0.0, pad=1.5)
    plt.show()
  • カラーマップ
  • カラーマップ
  • カラーマップ
  • カラーマップ
  • カラーマップ
  • カラーマップ
  • カラーマップ

グレースケール変換#

カラー プロットは白黒プリンタで印刷される可能性があるため、グレースケールへの変換に注意することが重要です。慎重に検討しないと、カラーマップによってグレースケールが予期せず変化するため、読者は判読できないプロットになってしまう可能性があります。

グレースケールへの変換は、さまざまな方法で行われます[bw]。より優れたものの中には、ピクセルの RGB 値の線形結合を使用するものもありますが、色の濃さをどのように知覚するかに応じて重み付けされています。グレースケールへの非線形変換方法は、\(L^*\)ピクセルの値。一般に、情報を知覚的に提示する場合と同様の原則がこの質問にも適用されます。つまり、単調に増加するカラーマップが選択された場合\(L^*\)適切な方法でグレースケールに印刷されます。

これを念頭に置いて、シーケンシャル カラーマップがグレースケールで適切に表現されていることがわかります。Sequential2 カラーマップの中には、適切なグレースケール表現を持つものもありますが、一部 (秋、春、夏、冬) はグレースケールの変化がほとんどありません。このようなカラーマップがプロットで使用され、プロットがグレースケールに印刷された場合、多くの情報が同じグレー値にマッピングされる可能性があります。Diverging カラーマップは、ほとんどの場合、外側のエッジの濃いグレーから中央の白まで変化します。一部 (PuOr および地震) は、一方の側が他方の側よりも著しく暗い灰色になっているため、あまり対称的ではありません。coolwarm にはグレー スケールの範囲がほとんどなく、より均一なプロットに印刷され、多くの詳細が失われます。重ねてラベル付けされた等高線は、カラーマップの一方の側と他方の側を区別するのに役立つことに注意してください。もう 1 つは、プロットがグレースケールに印刷されると色を使用できないためです。Accent、hsv、jet、turbo などの質的およびその他のカラーマップの多くは、カラーマップ全体で暗い灰色から明るい灰色に変化し、暗い灰色に戻ります。これにより、プロットがグレースケールで印刷されると、視聴者はプロット内の情報を解釈できなくなります。

mpl.rcParams.update({'font.size': 14})

# Indices to step through colormap.
x = np.linspace(0.0, 1.0, 100)

gradient = np.linspace(0, 1, 256)
gradient = np.vstack((gradient, gradient))


def plot_color_gradients(cmap_category, cmap_list):
    fig, axs = plt.subplots(nrows=len(cmap_list), ncols=2)
    fig.subplots_adjust(top=0.95, bottom=0.01, left=0.2, right=0.99,
                        wspace=0.05)
    fig.suptitle(cmap_category + ' colormaps', fontsize=14, y=1.0, x=0.6)

    for ax, name in zip(axs, cmap_list):

        # Get RGB values for colormap.
        rgb = mpl.colormaps[name](x)[np.newaxis, :, :3]

        # Get colormap in CAM02-UCS colorspace. We want the lightness.
        lab = cspace_converter("sRGB1", "CAM02-UCS")(rgb)
        L = lab[0, :, 0]
        L = np.float32(np.vstack((L, L, L)))

        ax[0].imshow(gradient, aspect='auto', cmap=mpl.colormaps[name])
        ax[1].imshow(L, aspect='auto', cmap='binary_r', vmin=0., vmax=100.)
        pos = list(ax[0].get_position().bounds)
        x_text = pos[0] - 0.01
        y_text = pos[1] + pos[3]/2.
        fig.text(x_text, y_text, name, va='center', ha='right', fontsize=10)

    # Turn off *all* ticks & spines, not just the ones with colormaps.
    for ax in axs.flat:
        ax.set_axis_off()

    plt.show()


for cmap_category, cmap_list in cmaps.items():

    plot_color_gradients(cmap_category, cmap_list)
  • 知覚的に均一な順次カラーマップ
  • 順次カラーマップ
  • 順次 (2) カラーマップ
  • 発散カラーマップ
  • 巡回カラーマップ
  • 定性的カラーマップ
  • その他のカラーマップ

色覚異常#

色盲については、多くの情報が入手できます (例: [ colorblindness] )。さらに、さまざまなタイプの色覚障害に対応するように画像を変換するためのツールがあります。

色覚異常の最も一般的な形態には、赤と緑の区別が含まれます。したがって、赤と緑の両方を含むカラーマップを避けることで、一般的に多くの問題を回避できます。

参考文献#

スクリプトの合計実行時間: ( 0 分 14.251 秒)

Sphinx-Gallery によって生成されたギャラリー