Асимметричная цветная полоса со справедливой расходящейся цветовой картой - PullRequest
0 голосов
/ 13 апреля 2019

Я пытаюсь построить асимметричный диапазон цветов на графике рассеяния.Я хочу, чтобы цвета были точным представлением интенсивности, используя расходящуюся карту цветов .У меня проблемы с изменением цветовой шкалы, чтобы представить это.

Например, я хочу построить xy-данные с диапазоном [-2, 10] на диаграмме рассеяния так, чтобы цветная полоса показывала только диапазон -2до 10 с нейтральным цветом на 0, но «интенсивность» на -2 и 2 одинаковы.

Я пытался использовать Нормализация ColorMap и усечение цветовой карты , но, похоже, мне нужна какая-то комбинация из двух, которую я не могу понять.

MCV Пример

x = np.arange( 0, 1, 1e-1 )
xlen = x.shape[ 0 ]
z = np.random.random( xlen**2 )*12 - 2


splt = plt.scatter( 
    np.repeat( x, xlen ), 
    np.tile( x, xlen ), 
    c = z, cmap = 'seismic',
    s = 400
)

plt.colorbar( splt )

Используя MidpointNormalize

class MidpointNormalize(colors.Normalize):
    def __init__(self, vmin=None, vmax=None, midpoint=None, clip=False):
        self.midpoint = midpoint
        colors.Normalize.__init__(self, vmin, vmax, clip)

    def __call__(self, value, clip=None):
        # I'm ignoring masked values and all kinds of edge cases to make a
        # simple example...
        x, y = [self.vmin, self.midpoint, self.vmax], [0, 0.5, 1]
        return np.ma.masked_array(np.interp(value, x, y))
x = np.arange( 0, 1, 1e-1 )
xlen = x.shape[ 0 ]
z = np.random.random( xlen**2 )*12 - 2

norm = MidpointNormalize( midpoint = 0 )

splt = plt.scatter( 
    np.repeat( x, xlen ), 
    np.tile( x, xlen ), 
    c = z, cmap = 'seismic', s = 400,
    norm = norm
)

plt.colorbar( splt )

, я могу получить цветовой центр по центру в 0, но интенсивностинесправедливыт.е. интенсивность в -2 намного темнее, чем в + 2.

Проблема с усечением карты цветов, с которой я столкнулся, заключается в том, что я не знаю, где находится правильное место для усечения.

Вот пример изменения, которое я хочу внести в цветную полосу: exaple of colorbar change

Ответы [ 2 ]

2 голосов
/ 13 апреля 2019

Если я правильно вас понял, проблема в том, что ваша карта, центрированная по средней точке, равномерно масштабирует цвет с -2 до 0 (синий) и аналогичным образом (красный) с 0 до 10.

Вместо того, чтобы масштабировать [self.vmin, self.midpoint, self.vmax] = [-2, 0, 10], вам лучше изменить масштаб между [-v_ext, self.midpoint, v_ext] = [-10, 0, 10], где:

v_ext = np.max( [ np.abs(self.vmin), np.abs(self.vmax) ] )  ## = np.max( [ 2, 10 ] )

Полный код может выглядеть следующим образом:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors

x = np.arange( 0, 1, 1e-1 )
xlen = x.shape[ 0 ]
z = np.random.random( xlen**2 )*12 - 2

class MidpointNormalize(mcolors.Normalize):
    def __init__(self, vmin=None, vmax=None, midpoint=None, clip=False):
        self.midpoint = midpoint
        mcolors.Normalize.__init__(self, vmin, vmax, clip)

    def __call__(self, value, clip=None):
        v_ext = np.max( [ np.abs(self.vmin), np.abs(self.vmax) ] )
        x, y = [-v_ext, self.midpoint, v_ext], [0, 0.5, 1]
        return np.ma.masked_array(np.interp(value, x, y))

x = np.arange( 0, 1, 1e-1 )
xlen = x.shape[ 0 ]
z = np.random.random( xlen**2 )*12 - 2

norm = MidpointNormalize( midpoint = 0 )

splt = plt.scatter( 
    np.repeat( x, xlen ), 
    np.tile( x, xlen ), 
    c = z, cmap = 'seismic', s = 400,
    norm = norm
)

plt.colorbar( splt )
plt.show()

enter image description here

0 голосов
/ 13 апреля 2019

На основе ответа @ Asmus я создал класс MidpointNormalizeFair, который выполняет это масштабирование на основе данных.

class MidpointNormalizeFair(mpl.colors.Normalize):
    """ From: https://matplotlib.org/users/colormapnorms.html"""
    def __init__(self, vmin=None, vmax=None, midpoint=None, clip=False):
        self.midpoint = midpoint
        mpl.colors.Normalize.__init__(self, vmin, vmax, clip)

    def __call__(self, value, clip=None):
        # I'm ignoring masked values and all kinds of edge cases to make a
        # simple example...

        result, is_scalar = self.process_value(value)
        self.autoscale_None(result)

        vlargest = max( abs( self.vmax - self.midpoint ), abs( self.vmin - self.midpoint ) )
        x, y = [ self.midpoint - vlargest, self.midpoint, self.midpoint + vlargest], [0, 0.5, 1]
        return np.ma.masked_array(np.interp(value, x, y))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...