matplotlib에서 컬러 맵의 중간 점 정의


87

컬러 맵의 중간 지점을 설정하고 싶습니다. 즉, 데이터가 -5에서 10으로 이동하고 0이 중간이되기를 원합니다. 나는 그것을하는 방법이 정규화하고 표준을 사용하는 하위 클래스를 만드는 것이라고 생각하지만 나는 어떤 예도 찾지 못했고 정확히 구현해야 할 것이 무엇인지 명확하지 않습니다.


이를 "발산"또는 "양극"컬러 맵이라고합니다. 여기서지도의 중심점이 중요하고 데이터가이 지점을 위아래로 이동합니다. sandia.gov/~kmorel/documents/ColorMaps
endolith

3
이 스레드의 모든 답변은 다소 복잡해 보입니다. 사용하기 쉬운 솔루션은 이 훌륭한 답변 에 나와 있으며 그 동안 matplotlib 문서, Custom normalization : Two linear ranges 섹션에도 포함되었습니다 .
ImportanceOfBeingErnest

답변:


14

matplotlib 버전 3.1에서 DivergingNorm 클래스가 추가되었습니다. 나는 그것이 당신의 유스 케이스를 다루고 있다고 생각합니다. 다음과 같이 사용할 수 있습니다.

from matplotlib import colors
colors.DivergingNorm(vmin=-4000., vcenter=0., vmax=10000)

matplotlib 3.2에서 클래스 이름이 TwoSlopesNorm 으로 변경되었습니다 .


흥미로워 보이지만 플로팅하기 전에 데이터를 변환하는 데 사용해야하는 것 같습니다. 색상 막대의 범례는 원래 데이터가 아닌 변환 된 데이터와 관련됩니다.
bli

3
@bli는 그렇지 않습니다. 는 norm이미지에 대한 표준화 작업을 수행합니다. norms컬러 맵과 함께 사용할 수 있습니다.
Paul H

1
귀찮게도 이것은 대체 방법에 대한 문서없이 3.2부터 사용되지 않습니다. matplotlib.org/3.2.0/api/_as_gen/…
daknowles

1
예, 문서가 명확하지 않습니다. 이름이 TwoSlopeNorm다음과 같이 변경된 것 같습니다. matplotlib.org/3.2.0/api/_as_gen/…
macKaiver

91

나는 이것이 게임에 늦었다는 것을 알고 있지만 방금이 과정을 거쳐서 서브 클래 싱 정규화보다 덜 강력하지만 훨씬 더 간단한 솔루션을 찾았습니다. 후손을 위해 여기에서 공유하는 것이 좋을 것이라고 생각했습니다.

함수

import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import AxesGrid

def shiftedColorMap(cmap, start=0, midpoint=0.5, stop=1.0, name='shiftedcmap'):
    '''
    Function to offset the "center" of a colormap. Useful for
    data with a negative min and positive max and you want the
    middle of the colormap's dynamic range to be at zero.

    Input
    -----
      cmap : The matplotlib colormap to be altered
      start : Offset from lowest point in the colormap's range.
          Defaults to 0.0 (no lower offset). Should be between
          0.0 and `midpoint`.
      midpoint : The new center of the colormap. Defaults to 
          0.5 (no shift). Should be between 0.0 and 1.0. In
          general, this should be  1 - vmax / (vmax + abs(vmin))
          For example if your data range from -15.0 to +5.0 and
          you want the center of the colormap at 0.0, `midpoint`
          should be set to  1 - 5/(5 + 15)) or 0.75
      stop : Offset from highest point in the colormap's range.
          Defaults to 1.0 (no upper offset). Should be between
          `midpoint` and 1.0.
    '''
    cdict = {
        'red': [],
        'green': [],
        'blue': [],
        'alpha': []
    }

    # regular index to compute the colors
    reg_index = np.linspace(start, stop, 257)

    # shifted index to match the data
    shift_index = np.hstack([
        np.linspace(0.0, midpoint, 128, endpoint=False), 
        np.linspace(midpoint, 1.0, 129, endpoint=True)
    ])

    for ri, si in zip(reg_index, shift_index):
        r, g, b, a = cmap(ri)

        cdict['red'].append((si, r, r))
        cdict['green'].append((si, g, g))
        cdict['blue'].append((si, b, b))
        cdict['alpha'].append((si, a, a))

    newcmap = matplotlib.colors.LinearSegmentedColormap(name, cdict)
    plt.register_cmap(cmap=newcmap)

    return newcmap

biased_data = np.random.random_integers(low=-15, high=5, size=(37,37))

orig_cmap = matplotlib.cm.coolwarm
shifted_cmap = shiftedColorMap(orig_cmap, midpoint=0.75, name='shifted')
shrunk_cmap = shiftedColorMap(orig_cmap, start=0.15, midpoint=0.75, stop=0.85, name='shrunk')

fig = plt.figure(figsize=(6,6))
grid = AxesGrid(fig, 111, nrows_ncols=(2, 2), axes_pad=0.5,
                label_mode="1", share_all=True,
                cbar_location="right", cbar_mode="each",
                cbar_size="7%", cbar_pad="2%")

# normal cmap
im0 = grid[0].imshow(biased_data, interpolation="none", cmap=orig_cmap)
grid.cbar_axes[0].colorbar(im0)
grid[0].set_title('Default behavior (hard to see bias)', fontsize=8)

im1 = grid[1].imshow(biased_data, interpolation="none", cmap=orig_cmap, vmax=15, vmin=-15)
grid.cbar_axes[1].colorbar(im1)
grid[1].set_title('Centered zero manually,\nbut lost upper end of dynamic range', fontsize=8)

im2 = grid[2].imshow(biased_data, interpolation="none", cmap=shifted_cmap)
grid.cbar_axes[2].colorbar(im2)
grid[2].set_title('Recentered cmap with function', fontsize=8)

im3 = grid[3].imshow(biased_data, interpolation="none", cmap=shrunk_cmap)
grid.cbar_axes[3].colorbar(im3)
grid[3].set_title('Recentered cmap with function\nand shrunk range', fontsize=8)

for ax in grid:
    ax.set_yticks([])
    ax.set_xticks([])

예의 결과 :

여기에 이미지 설명 입력


귀하의 멋진 기여에 감사드립니다! 그러나 코드는 할 수 없었다 모두 자르기와 같은 색상 맵을 이동하고 지시는 약간의 부정확하고 오해의 소지가 있었다. 이제이 문제를 수정하고 자유롭게 게시물을 수정할 수 있습니다. 또한 내 개인 라이브러리 중 하나에 포함 시키고 귀하를 저자로 추가했습니다. 괜찮 으시길 바랍니다.
TheChymera 2014

@TheChymera 오른쪽 하단 모서리의 컬러 맵이 잘리고 최근에 정렬되었습니다. 당신이 적합하다고 생각되면 이것을 자유롭게 사용하십시오.
Paul H

예, 슬프게도 우연의 일치로 보입니다. 경우 startstop0과 1은 각각 당신이 후하지 않습니다 reg_index = np.linspace(start, stop, 257), 당신은 더 이상 그 값 129 따라서 전체 스케일링은자를 때마다 아무 의미는하지 않으며, 원래 cmap를의 중간 지점 인지지 않습니다. 또한 지시에 따라 0에서 1까지가 아닌 start0에서 0.5와 stop0.5에서 1 사이 여야합니다 .
TheChymera 2014

@TheChymera 나는 당신의 버전을 시험해 보았고 그것에 대해 두 가지 생각을했습니다. 1) 당신이 만든 색인은 모두 길이가 257이고 matplotlib에서는 기본값이 256으로 설정되어 있다고 생각합니까? 2) 내 데이터 범위가 -1에서 1000 사이라고 가정하면 긍정이 지배적이므로 더 많은 수준 / 계층이 긍정 분기로 이동해야합니다. 하지만 당신의 기능은 부정적인 것과 긍정적 인 모두에 128 개의 레벨을 제공하므로 레벨을 고르지 않게 분할하는 것이 더 "공정"하다고 생각합니다.
Jason

이것은 훌륭한 솔루션이지만 midpoint데이터가 0 또는 1이면 실패합니다 . 해당 문제에 대한 간단한 수정은 아래 내 대답을 참조하십시오.
DaveTheScientist

22

다음은 Normalize를 하위 분류하는 솔루션입니다. 그것을 사용하려면

norm = MidPointNorm(midpoint=3)
imshow(X, norm=norm)

클래스는 다음과 같습니다.

import numpy as np
from numpy import ma
from matplotlib import cbook
from matplotlib.colors import Normalize

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

    def __call__(self, value, clip=None):
        if clip is None:
            clip = self.clip

        result, is_scalar = self.process_value(value)

        self.autoscale_None(result)
        vmin, vmax, midpoint = self.vmin, self.vmax, self.midpoint

        if not (vmin < midpoint < vmax):
            raise ValueError("midpoint must be between maxvalue and minvalue.")       
        elif vmin == vmax:
            result.fill(0) # Or should it be all masked? Or 0.5?
        elif vmin > vmax:
            raise ValueError("maxvalue must be bigger than minvalue")
        else:
            vmin = float(vmin)
            vmax = float(vmax)
            if clip:
                mask = ma.getmask(result)
                result = ma.array(np.clip(result.filled(vmax), vmin, vmax),
                                  mask=mask)

            # ma division is very slow; we can take a shortcut
            resdat = result.data

            #First scale to -1 to 1 range, than to from 0 to 1.
            resdat -= midpoint            
            resdat[resdat>0] /= abs(vmax - midpoint)            
            resdat[resdat<0] /= abs(vmin - midpoint)

            resdat /= 2.
            resdat += 0.5
            result = ma.array(resdat, mask=result.mask, copy=False)                

        if is_scalar:
            result = result[0]            
        return result

    def inverse(self, value):
        if not self.scaled():
            raise ValueError("Not invertible until scaled")
        vmin, vmax, midpoint = self.vmin, self.vmax, self.midpoint

        if cbook.iterable(value):
            val = ma.asarray(value)
            val = 2 * (val-0.5)  
            val[val>0]  *= abs(vmax - midpoint)
            val[val<0] *= abs(vmin - midpoint)
            val += midpoint
            return val
        else:
            val = 2 * (value - 0.5)
            if val < 0: 
                return  val*abs(vmin-midpoint) + midpoint
            else:
                return  val*abs(vmax-midpoint) + midpoint

더 많은 하위 클래스를 만들지 않고도 로그 또는 심볼 로그 확장 외에이 클래스를 사용할 수 있습니까? 내 현재 사용 사례는 이미 "norm = SymLogNorm (linthresh = 1)"을 사용합니다.
AnnanFay

완벽합니다. 바로 제가 찾던 것입니다. 차이점을 보여주는 그림을 추가해야할까요? 여기서 중간 점이 사지쪽으로 드래그 될 수있는 다른 중간 점 노멀 라이저와는 달리 막대의 중앙에 있습니다.
gaborous

18

(이미지 데이터로 작업한다고 가정 할 때)에 하위 클래스를 지정하는 대신 vminvmax인수를 사용하는 것이 가장 쉽습니다 .imshowmatplotlib.colors.Normalize

import numpy as np
import matplotlib.pyplot as plt

data = np.random.random((10,10))
# Make the data range from about -5 to 10
data = 10 / 0.75 * (data - 0.25)

plt.imshow(data, vmin=-10, vmax=10)
plt.colorbar()

plt.show()

여기에 이미지 설명 입력


1
색상의 그라데이션을 더 잘 볼 수 있도록 예제를 가우스 곡선으로 업데이트 할 수 있습니까?
Dat Chu

3
이 솔루션은 사용 가능한 색상의 전체 동적 범위를 사용하지 않기 때문에 마음에 들지 않습니다. 또한 나는 정규화의 예를 들어 symlog와 같은 정규화를 구축하고 싶습니다.
tillsten 2011-09-13

2
@tillsten-혼란 스러워요 ... 중간에 0을 원하면 컬러 바의 전체 동적 범위를 사용할 수 없죠? 그렇다면 비선형 스케일을 원하십니까? 0보다 큰 값에 대해 하나의 스케일, 아래 값에 대해 하나? 이 경우 네, 하위 클래스가 필요합니다 Normalize. 나는 약간의 예제를 추가 할 것입니다 (다른 누군가가 나를 이기지 않는다고 가정합니다 ...).
Joe Kington 2011 년

@Joe : 맞습니다. 선형이 아닙니다 (정확히 말하자면 두 개의 선형 부분). vmin / vmax를 사용하면 -5보다 작은 값에 대한 colorange는 사용되지 않습니다 (일부 응용 프로그램에서는 의미가 있지만 내 것이 아닙니다.).
tillsten 2011 년

2
: Z에서 일반 데이터에 대한vmax=abs(Z).max(), vmin=-abs(Z).max()
endolith

12

여기 Normalize에 최소한의 예제 가 뒤 따르는 하위 클래스를 만듭니다 .

import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt


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

    def __call__(self, value, clip=None):
        normalized_min = max(0, 1 / 2 * (1 - abs((self.midpoint - self.vmin) / (self.midpoint - self.vmax))))
        normalized_max = min(1, 1 / 2 * (1 + abs((self.vmax - self.midpoint) / (self.midpoint - self.vmin))))
        normalized_mid = 0.5
        x, y = [self.vmin, self.midpoint, self.vmax], [normalized_min, normalized_mid, normalized_max]
        return np.ma.masked_array(np.interp(value, x, y))


vals = np.array([[-5., 0], [5, 10]]) 
vmin = vals.min()
vmax = vals.max()

norm = MidpointNormalize(vmin=vmin, vmax=vmax, midpoint=0)
cmap = 'RdBu_r' 

plt.imshow(vals, cmap=cmap, norm=norm)
plt.colorbar()
plt.show()

결과: 그림 -1

긍정적 인 데이터 만있는 동일한 예 vals = np.array([[1., 3], [6, 10]])

그림 -2

속성 :

  • 중간 점은 중간 색상을 얻습니다.
  • 상한 및 하한 범위는 동일한 선형 변환에 의해 재조정됩니다.
  • 컬러 바에는 사진에 나타나는 색상 만 표시됩니다.
  • vmin더 큰 경우에도 잘 작동하는 것 같습니다 midpoint(모든 가장자리 사례를 테스트하지는 않았습니다).

이 솔루션은 이 페이지 에서 이름 같은 클래스에서 영감을 얻었습니다 .


3
단순성으로 인한 최고의 답변입니다. 다른 답변은 이미 최고 전문가가 되려는 Matplotlib 전문가 인 경우에만 가장 좋습니다. 대부분의 matplotlib 답변 구직자는 개 및 / 또는 가족에게 집으로 돌아 가기 위해 무언가를 시도하고 있으며,이 답변이 가장 좋습니다.
sapo_cosmico

이 솔루션은 실제로 최고로 보이지만 작동하지 않습니다! 방금 테스트 스크립트를 실행했는데 결과가 완전히 다릅니다 (파란색 사각형 만 포함하고 빨간색 없음). @icemtel, 확인해 주시겠습니까? (에 들여 쓰기 문제 옆에 def __call__)
Filipe

좋아, 나는 문제 (들) 발견의 계산에 숫자를 normalized_min하고 normalized_max정수로 가져옵니다. 0.0으로 입력하십시오. 또한 그림의 올바른 출력을 얻으려면 vals = sp.array([[-5.0, 0.0], [5.0, 10.0]]) . 어쨌든 답변 주셔서 감사합니다!
Filipe

안녕하세요 @Filipe 내 컴퓨터에서 문제를 재현 할 수 없습니다 (Python 3.7, matplotlib 2.2.3, 새 버전에서도 동일해야한다고 생각합니다). 어떤 버전이 있습니까? 어쨌든 float 유형의 배열을 만드는 작은 편집을 수행하고 들여 쓰기 문제를 해결했습니다. 그것을 지적 주셔서 감사합니다
icemtel을

흠 .. 방금 python3로 시도했는데 작동합니다. 하지만 python2.7을 사용하고 있습니다. 수정 해주셔서 감사합니다. 사용하기 매우 간단합니다! :)
Filipe

5

여전히 답을 찾고 있는지 확실하지 않습니다. 저에게는 하위 클래스를 시도하는 Normalize것이 실패했습니다. 그래서 저는 여러분이 목표로하는 효과를 얻기 위해 새로운 데이터 세트, 눈금 및 눈금 레이블을 수동으로 만드는 데 집중했습니다.

scale'syslog'규칙에 따라 라인 플롯을 변환하는 데 사용되는 클래스가있는 matplotlib 에서 모듈을 찾았 으므로이를 사용하여 데이터를 변환합니다. 그런 다음 데이터를 0에서 1 ( Normalize일반적으로 수행하는 작업)로 조정하지만 양수와 음수를 다르게 조정합니다. 이는 vmax와 vmin이 동일하지 않을 수 있으므로 .5-> 1이 .5-> 0보다 더 큰 양의 범위를 포함 할 수 있고 음의 범위가 그러하기 때문입니다. 눈금과 레이블 값을 계산하는 루틴을 만드는 것이 더 쉬웠습니다.

아래는 코드와 예제 그림입니다.

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.mpl as mpl
import matplotlib.scale as scale

NDATA = 50
VMAX=10
VMIN=-5
LINTHRESH=1e-4

def makeTickLables(vmin,vmax,linthresh):
    """
    make two lists, one for the tick positions, and one for the labels
    at those positions. The number and placement of positive labels is 
    different from the negative labels.
    """
    nvpos = int(np.log10(vmax))-int(np.log10(linthresh))
    nvneg = int(np.log10(np.abs(vmin)))-int(np.log10(linthresh))+1
    ticks = []
    labels = []
    lavmin = (np.log10(np.abs(vmin)))
    lvmax = (np.log10(np.abs(vmax)))
    llinthres = int(np.log10(linthresh))
    # f(x) = mx+b
    # f(llinthres) = .5
    # f(lavmin) = 0
    m = .5/float(llinthres-lavmin)
    b = (.5-llinthres*m-lavmin*m)/2
    for itick in range(nvneg):
        labels.append(-1*float(pow(10,itick+llinthres)))
        ticks.append((b+(itick+llinthres)*m))
    # add vmin tick
    labels.append(vmin)
    ticks.append(b+(lavmin)*m)

    # f(x) = mx+b
    # f(llinthres) = .5
    # f(lvmax) = 1
    m = .5/float(lvmax-llinthres)
    b = m*(lvmax-2*llinthres) 
    for itick in range(1,nvpos):
        labels.append(float(pow(10,itick+llinthres)))
        ticks.append((b+(itick+llinthres)*m))
    # add vmax tick
    labels.append(vmax)
    ticks.append(b+(lvmax)*m)

    return ticks,labels


data = (VMAX-VMIN)*np.random.random((NDATA,NDATA))+VMIN

# define a scaler object that can transform to 'symlog'
scaler = scale.SymmetricalLogScale.SymmetricalLogTransform(10,LINTHRESH)
datas = scaler.transform(data)

# scale datas so that 0 is at .5
# so two seperate scales, one for positive and one for negative
data2 = np.where(np.greater(data,0),
                 .75+.25*datas/np.log10(VMAX),
                 .25+.25*(datas)/np.log10(np.abs(VMIN))
                 )

ticks,labels=makeTickLables(VMIN,VMAX,LINTHRESH)

cmap = mpl.cm.jet
fig = plt.figure()
ax = fig.add_subplot(111)
im = ax.imshow(data2,cmap=cmap,vmin=0,vmax=1)
cbar = plt.colorbar(im,ticks=ticks)
cbar.ax.set_yticklabels(labels)

fig.savefig('twoscales.png')

vmax = 10, vmin = -5 및 linthresh = 1e-4

VMAX스크립트 상단에 있는 "상수"(예 :)를 자유롭게 조정하여 제대로 작동하는지 확인하십시오.


제안 해 주셔서 감사합니다. 아래에서 볼 수 있듯이 서브 클래 싱에 성공했습니다. 그러나 코드는 여전히 틱 레이블을 올바르게 만드는 데 매우 유용합니다.
tillsten

4

나는 Paul H의 훌륭한 대답을 사용하고 있었지만 내 데이터 중 일부는 음수에서 양수로, 다른 세트는 0에서 양수 또는 음수에서 0으로 범위가 다양했기 때문에 문제가 발생했습니다. 두 경우 모두 0이 흰색 (사용중인 컬러 맵의 중간 점)으로 지정되기를 원했습니다. 기존 구현에서 midpoint값이 1 또는 0이면 원래 매핑을 덮어 쓰지 않았습니다. 다음 그림에서 확인할 수 있습니다 편집 전 그래프 . 세 번째 열은 정확 해 보이지만 두 번째 열의 진한 파란색 영역과 나머지 열의 진한 빨간색 영역은 모두 흰색으로 간주됩니다 (데이터 값은 실제로 0 임). 내 수정 사항을 사용하면 편집 후 그래프 다음과 같은 결과가 나타납니다 . 내 기능은 for루프 시작 부분에서 편집 한 내용이 포함 된 Paul H의 기능과 기본적으로 동일 합니다.

def shiftedColorMap(cmap, min_val, max_val, name):
    '''Function to offset the "center" of a colormap. Useful for data with a negative min and positive max and you want the middle of the colormap's dynamic range to be at zero. Adapted from /programming/7404116/defining-the-midpoint-of-a-colormap-in-matplotlib

    Input
    -----
      cmap : The matplotlib colormap to be altered.
      start : Offset from lowest point in the colormap's range.
          Defaults to 0.0 (no lower ofset). Should be between
          0.0 and `midpoint`.
      midpoint : The new center of the colormap. Defaults to
          0.5 (no shift). Should be between 0.0 and 1.0. In
          general, this should be  1 - vmax/(vmax + abs(vmin))
          For example if your data range from -15.0 to +5.0 and
          you want the center of the colormap at 0.0, `midpoint`
          should be set to  1 - 5/(5 + 15)) or 0.75
      stop : Offset from highets point in the colormap's range.
          Defaults to 1.0 (no upper ofset). Should be between
          `midpoint` and 1.0.'''
    epsilon = 0.001
    start, stop = 0.0, 1.0
    min_val, max_val = min(0.0, min_val), max(0.0, max_val) # Edit #2
    midpoint = 1.0 - max_val/(max_val + abs(min_val))
    cdict = {'red': [], 'green': [], 'blue': [], 'alpha': []}
    # regular index to compute the colors
    reg_index = np.linspace(start, stop, 257)
    # shifted index to match the data
    shift_index = np.hstack([np.linspace(0.0, midpoint, 128, endpoint=False), np.linspace(midpoint, 1.0, 129, endpoint=True)])
    for ri, si in zip(reg_index, shift_index):
        if abs(si - midpoint) < epsilon:
            r, g, b, a = cmap(0.5) # 0.5 = original midpoint.
        else:
            r, g, b, a = cmap(ri)
        cdict['red'].append((si, r, r))
        cdict['green'].append((si, g, g))
        cdict['blue'].append((si, b, b))
        cdict['alpha'].append((si, a, a))
    newcmap = matplotlib.colors.LinearSegmentedColormap(name, cdict)
    plt.register_cmap(cmap=newcmap)
    return newcmap

편집 : 내 데이터 중 일부가 작은 양의 값에서 더 큰 양의 값에 이르기까지 매우 낮은 값이 흰색 대신 빨간색으로 표시되었을 때 비슷한 문제가 다시 발생했습니다. Edit #2위의 코드에 줄을 추가하여 수정했습니다 .


이것은 멋져 보이지만 Paul H (및 주석)의 대답에서 인수가 변경된 것 같습니다 ... 대답에 예제 호출을 추가 할 수 있습니까?
Filipe

1

vmin, vmax 및 0 사이의 비율을 계산하는 데 신경 쓰지 않는다면 이것은 비율에 따라 흰색을 설정하는 파란색에서 흰색, 빨간색으로 매우 기본적인 선형 맵입니다 z.

def colormap(z):
    """custom colourmap for map plots"""

    cdict1 = {'red': ((0.0, 0.0, 0.0),
                      (z,   1.0, 1.0),
                      (1.0, 1.0, 1.0)),
              'green': ((0.0, 0.0, 0.0),
                        (z,   1.0, 1.0),
                        (1.0, 0.0, 0.0)),
              'blue': ((0.0, 1.0, 1.0),
                       (z,   1.0, 1.0),
                       (1.0, 0.0, 0.0))
              }

    return LinearSegmentedColormap('BlueRed1', cdict1)

cdict 형식은 매우 간단합니다. 행은 생성되는 그래디언트의 포인트입니다. 첫 번째 항목은 x 값 (0에서 1까지의 그래디언트에 따른 비율)이고 두 번째 항목은 이전 세그먼트의 끝 값입니다. 세 번째는 다음 세그먼트의 시작 값입니다. 부드러운 그래디언트를 원하면 두 번째 세그먼트는 항상 동일합니다. 자세한 내용은 문서참조하십시오 .


1
LinearSegmentedColormap.from_list()튜플 내에서 지정 하고이 메소드 (val,color)color인수에 목록으로 전달 하는 옵션도 있습니다 val0=0<val1<...<valN==1.
maurizio

0

비슷한 문제가 있었지만 가장 높은 값은 전체 빨간색이고 낮은 값의 파란색은 잘라내어 기본적으로 컬러 바의 하단이 잘린 것처럼 보이도록했습니다. 이것은 나를 위해 일했습니다 (선택적 투명도 포함).

def shift_zero_bwr_colormap(z: float, transparent: bool = True):
    """shifted bwr colormap"""
    if (z < 0) or (z > 1):
        raise ValueError('z must be between 0 and 1')

    cdict1 = {'red': ((0.0, max(-2*z+1, 0), max(-2*z+1, 0)),
                      (z,   1.0, 1.0),
                      (1.0, 1.0, 1.0)),

              'green': ((0.0, max(-2*z+1, 0), max(-2*z+1, 0)),
                        (z,   1.0, 1.0),
                        (1.0, max(2*z-1,0),  max(2*z-1,0))),

              'blue': ((0.0, 1.0, 1.0),
                       (z,   1.0, 1.0),
                       (1.0, max(2*z-1,0), max(2*z-1,0))),
              }
    if transparent:
        cdict1['alpha'] = ((0.0, 1-max(-2*z+1, 0), 1-max(-2*z+1, 0)),
                           (z,   0.0, 0.0),
                           (1.0, 1-max(2*z-1,0),  1-max(2*z-1,0)))

    return LinearSegmentedColormap('shifted_rwb', cdict1)

cmap =  shift_zero_bwr_colormap(.3)

x = np.arange(0, np.pi, 0.1)
y = np.arange(0, 2*np.pi, 0.1)
X, Y = np.meshgrid(x, y)
Z = np.cos(X) * np.sin(Y) * 5 + 5
plt.plot([0, 10*np.pi], [0, 20*np.pi], color='c', lw=20, zorder=-3)
plt.imshow(Z, interpolation='nearest', origin='lower', cmap=cmap)
plt.colorbar()
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.