Matplotlib 개별 컬러 바


95

matplotlib에서 산점도에 대한 개별 컬러 바를 만들려고합니다.

내 x, y 데이터와 각 포인트에 대해 고유 한 색상으로 표시하려는 정수 태그 값이 있습니다.

plt.scatter(x, y, c=tag)

일반적으로 태그는 0-20 범위의 정수이지만 정확한 범위는 변경 될 수 있습니다.

지금까지 기본 설정을 사용했습니다.

plt.colorbar()

지속적인 색상 범위를 제공합니다. 이상적으로는 n 개의 개별 색상 세트를 원합니다 (이 예에서는 n = 20). 더 좋은 방법은 태그 값을 0으로 설정하여 회색을 생성하고 1-20을 색상으로 만드는 것입니다.

몇 가지 '요리 책'스크립트를 찾았지만 매우 복잡하고 단순 해 보이는 문제를 해결하는 올바른 방법이라고 생각할 수 없습니다.


1
수행 또는 도움을?
Francesco Montesano 2013

링크 주셔서 감사합니다.하지만 두 번째 예는 매우 복잡해 보이는 사소한 작업을 수행하는 것을 의미합니다. 첫 번째 링크는 유용합니다
bph

1
: 나는 기존의 컬러 맵을 이산화에 매우 도움이 링크를 발견 gist.github.com/jakevdp/91077b0cae40f8f8244a
BallpointBen

답변:


91

BoundaryNorm을 스 캐터에 대한 노멀 라이저로 사용하여 사용자 정의 이산 컬러 바를 매우 쉽게 만들 수 있습니다. 기발한 비트 (내 방법에서)는 0 표시를 회색으로 만들고 있습니다.

이미지의 경우 종종 cmap.set_bad ()를 사용하고 내 데이터를 numpy 마스크 배열로 변환합니다. 0을 회색으로 만드는 것이 훨씬 쉬울 것이지만 스 캐터 또는 사용자 정의 cmap과 함께 작동하도록 할 수는 없습니다.

대안으로 자신의 cmap을 처음부터 만들거나 기존 cmap을 읽고 일부 특정 항목 만 재정의 할 수 있습니다.

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

fig, ax = plt.subplots(1, 1, figsize=(6, 6))  # setup the plot

x = np.random.rand(20)  # define the data
y = np.random.rand(20)  # define the data
tag = np.random.randint(0, 20, 20)
tag[10:12] = 0  # make sure there are some 0 values to show up as grey

cmap = plt.cm.jet  # define the colormap
# extract all colors from the .jet map
cmaplist = [cmap(i) for i in range(cmap.N)]
# force the first color entry to be grey
cmaplist[0] = (.5, .5, .5, 1.0)

# create the new map
cmap = mpl.colors.LinearSegmentedColormap.from_list(
    'Custom cmap', cmaplist, cmap.N)

# define the bins and normalize
bounds = np.linspace(0, 20, 21)
norm = mpl.colors.BoundaryNorm(bounds, cmap.N)

# make the scatter
scat = ax.scatter(x, y, c=tag, s=np.random.randint(100, 500, 20),
                  cmap=cmap, norm=norm)

# create a second axes for the colorbar
ax2 = fig.add_axes([0.95, 0.1, 0.03, 0.8])
cb = plt.colorbar.ColorbarBase(ax2, cmap=cmap, norm=norm,
    spacing='proportional', ticks=bounds, boundaries=bounds, format='%1i')

ax.set_title('Well defined discrete colors')
ax2.set_ylabel('Very custom cbar [-]', size=12)

여기에 이미지 설명 입력

저는 개인적으로 20 가지 색상으로 특정 값을 읽기가 조금 어렵다고 생각하지만 물론 그것은 당신에게 달려 있습니다.


이것이 허용되는지 확실하지 않지만 여기 에서 내 질문을 볼 수 있습니까?
vwos

6
plt.colorbar.ColorbarBase오류가 발생합니다. 사용mpl.colorbar.ColorbarBase
zeeshan 칸

이 답변에 감사드립니다. 문서에서 정말 그리워하십시오. 나는 그것을 백분위 수의 바람 장미로 바꾸려고 시도했고 색상 매핑에 버그가있었습니다. 그것은 다른 유스 케이스이지만, 그것은 것을 제안 할 수 있습니다 N-1cmap = mpl.colors.LinearSegmentedColormap.from_list('Custom cmap', cmaplist, cmap.N-1). 색상이 빈 내에서 균등하게 분배되지 않고 울타리 장벽 문제가있는 경우.
jlandercy

1
다음은 균등하게 분산 된 매핑을 재현하는 코드입니다.q=np.arange(0.0, 1.01, 0.1) cmap = mpl.cm.get_cmap('jet') cmaplist = [cmap(x) for x in q] cmap = mpl.colors.LinearSegmentedColormap.from_list('Custom cmap', cmaplist, len(q)-1) norm = mpl.colors.BoundaryNorm(q, cmap.N)
jlandercy

에 대해 잘 모르겠습니다 N-1. 당신이 맞을 수도 있지만 제 예에서는 복제 할 수 없습니다. 을 사용하여 LinearSegmentedColormap(그리고 N인수)를 피할 수 있습니다 ListedColormap. 문서는 '13 년 이후로 많이 개선되었습니다. 예를 들면 다음을 참조하십시오. matplotlib.org/3.1.1/tutorials/colors/…
Rutger Kassies

62

예를 따를 수 있습니다 .

#!/usr/bin/env python
"""
Use a pcolor or imshow with a custom colormap to make a contour plot.

Since this example was initially written, a proper contour routine was
added to matplotlib - see contour_demo.py and
http://matplotlib.sf.net/matplotlib.pylab.html#-contour.
"""

from pylab import *


delta = 0.01
x = arange(-3.0, 3.0, delta)
y = arange(-3.0, 3.0, delta)
X,Y = meshgrid(x, y)
Z1 = bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
Z2 = bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
Z = Z2 - Z1 # difference of Gaussians

cmap = cm.get_cmap('PiYG', 11)    # 11 discrete colors

im = imshow(Z, cmap=cmap, interpolation='bilinear',
            vmax=abs(Z).max(), vmin=-abs(Z).max())
axis('off')
colorbar()

show()

다음 이미지를 생성합니다.

poormans_contour


14
cmap = cm.get_cmap ( 'jet', 20) then scatter (x, y, c = tags, cmap = cmap)은 저를 거기까지
데려다줍니다-matplotlib에

링크가 끊어진 것 같습니다. 참고로.
Quinn Culver

44

위의 답변은 색상 막대에 적절한 눈금 배치가 없다는 점을 제외하면 좋습니다. 나는 숫자-> 색상 매핑이 더 명확하도록 색상 중간에 틱을 갖는 것을 좋아합니다. matshow 호출의 한계를 변경하여이 문제를 해결할 수 있습니다.

import matplotlib.pyplot as plt
import numpy as np

def discrete_matshow(data):
    #get discrete colormap
    cmap = plt.get_cmap('RdBu', np.max(data)-np.min(data)+1)
    # set limits .5 outside true range
    mat = plt.matshow(data,cmap=cmap,vmin = np.min(data)-.5, vmax = np.max(data)+.5)
    #tell the colorbar to tick at integers
    cax = plt.colorbar(mat, ticks=np.arange(np.min(data),np.max(data)+1))

#generate data
a=np.random.randint(1, 9, size=(10, 10))
discrete_matshow(a)

개별 컬러 바의 예


1
이산 데이터를 볼 때 해당 색상의 중간에 틱을 배치하는 것이 매우 유용하다는 데 동의합니다. 두 번째 방법이 맞습니다. 그러나 첫 번째 방법은 일반적으로 잘못 되었습니다. 색상 막대의 위치와 일치하지 않는 값으로 눈금에 레이블을 지정합니다. set_ticklabels(...)레이블 형식 (예 : 십진수 등)을 제어하는 ​​데만 사용해야합니다. 데이터가 실제로 불연속적인 경우 문제를 발견하지 못할 수 있습니다. 시스템에 노이즈가있는 경우 (예 : 2-> 1.9)이 일관되지 않은 라벨링으로 인해 오해의 소지가있는 잘못된 컬러 바가 생성됩니다.
E. Davis

E., 나는 당신이 한계를 바꾸는 것이 더 나은 해결책이라고 생각한다. 그래서 나는 "노이즈"를 잘 처리 할 수는 없지만 다른 것을 제거했다. 연속 데이터를 처리하려면 일부 조정이 필요합니다.
ben.dichter

37

컬러 맵 범위 위 또는 아래 값을 설정하려면 컬러 맵의 set_overset_under메서드 를 사용하는 것이 좋습니다 . 특정 값에 플래그를 지정하려면 마스킹 (즉, 마스킹 된 배열 생성)하고 set_bad메서드를 사용합니다 . (기본 컬러 맵 클래스에 대한 문서를보십시오 : http://matplotlib.org/api/colors_api.html#matplotlib.colors.Colormap )

다음과 같은 것을 원하는 것 같습니다.

import matplotlib.pyplot as plt
import numpy as np

# Generate some data
x, y, z = np.random.random((3, 30))
z = z * 20 + 0.1

# Set some values in z to 0...
z[:5] = 0

cmap = plt.get_cmap('jet', 20)
cmap.set_under('gray')

fig, ax = plt.subplots()
cax = ax.scatter(x, y, c=z, s=100, cmap=cmap, vmin=0.1, vmax=z.max())
fig.colorbar(cax, extend='min')

plt.show()

여기에 이미지 설명 입력


정말 좋습니다-나는 set_under를 사용해 보았지만 vmin을 포함하지 않았기 때문에 아무것도하고 있지 않다고 생각합니다
bph

9

이 주제는 이미 잘 다루었지만 더 구체적인 내용을 추가하고 싶었습니다. 특정 값이 해당 색상 (어떤 색상이 아닌)에 매핑되는지 확인하고 싶었습니다.

복잡하지는 않지만 시간이 걸리므로 다른 사람들이 내가 한 것만 큼 많은 시간을 잃지 않도록 도울 수 있습니다. :)

import matplotlib
from matplotlib.colors import ListedColormap

# Let's design a dummy land use field
A = np.reshape([7,2,13,7,2,2], (2,3))
vals = np.unique(A)

# Let's also design our color mapping: 1s should be plotted in blue, 2s in red, etc...
col_dict={1:"blue",
          2:"red",
          13:"orange",
          7:"green"}

# We create a colormar from our list of colors
cm = ListedColormap([col_dict[x] for x in col_dict.keys()])

# Let's also define the description of each category : 1 (blue) is Sea; 2 (red) is burnt, etc... Order should be respected here ! Or using another dict maybe could help.
labels = np.array(["Sea","City","Sand","Forest"])
len_lab = len(labels)

# prepare normalizer
## Prepare bins for the normalizer
norm_bins = np.sort([*col_dict.keys()]) + 0.5
norm_bins = np.insert(norm_bins, 0, np.min(norm_bins) - 1.0)
print(norm_bins)
## Make normalizer and formatter
norm = matplotlib.colors.BoundaryNorm(norm_bins, len_lab, clip=True)
fmt = matplotlib.ticker.FuncFormatter(lambda x, pos: labels[norm(x)])

# Plot our figure
fig,ax = plt.subplots()
im = ax.imshow(A, cmap=cm, norm=norm)

diff = norm_bins[1:] - norm_bins[:-1]
tickz = norm_bins[:-1] + diff / 2
cb = fig.colorbar(im, format=fmt, ticks=tickz)
fig.savefig("example_landuse.png")
plt.show()

여기에 이미지 설명 입력


이것을 복제하려고 시도했지만 'tmp'가 정의되지 않았기 때문에 코드가 실행되지 않습니다. 또한 람다 함수에 'pos'가 무엇인지 명확하지 않습니다. 감사!
George Liu

@GeorgeLiu 정말 당신이 쓰고 있었다! 복사 / 붙여 넣기 실수를했는데 이제 fxed입니다! 이제 코드 조각이 실행 중입니다! 에 관해서는 pos나는 여기에 왜의 완전히 확실하지 오전하지만이 FuncFormatter ()에 의해 요청 ... 어쩌면 다른 사람이 그것에 대해 우리를 계몽 할 수 있습니다!
Enzoupi

7

나는 이러한 아이디어를 조사해 왔으며 여기에 내 5 센트 가치가 있습니다. 및에 대한 인수 BoundaryNorm로 지정 하는 것뿐만 아니라 호출 을 방지 합니다. 그러나 나는.에 대한 다소 긴 호출을 제거 할 방법을 찾지 못했습니다 .normscattercolorbarmatplotlib.colors.LinearSegmentedColormap.from_list

일부 배경은 matplotlib가 불연속 데이터와 함께 사용하기위한 소위 정성 컬러 맵을 제공한다는 것입니다. Set1예를 들어 9 가지 색상을 쉽게 구분할 tab20수 있으며 20 가지 색상에 사용할 수 있습니다. 이러한 맵을 사용하면 다음 예제와 같이 처음 n 개의 색상을 사용하여 n 개의 범주가있는 산점도를 색칠하는 것이 자연 스러울 수 있습니다. 이 예제는 또한 적절하게 레이블이 지정된 n 개의 개별 색상이있는 컬러 바를 생성합니다.

import matplotlib, numpy as np, matplotlib.pyplot as plt
n = 5
from_list = matplotlib.colors.LinearSegmentedColormap.from_list
cm = from_list(None, plt.cm.Set1(range(0,n)), n)
x = np.arange(99)
y = x % 11
z = x % n
plt.scatter(x, y, c=z, cmap=cm)
plt.clim(-0.5, n-0.5)
cb = plt.colorbar(ticks=range(0,n), label='Group')
cb.ax.tick_params(length=0)

아래 이미지를 생성합니다. n에 대한 호출 의 는 해당 컬러 맵 Set1의 첫 번째 n색상 을 지정하고 n에 대한 호출 의 마지막 색상 from_listn색상 이있는지도를 구성 하도록 지정합니다 (기본값은 256). 를 사용하여 cm기본 컬러 맵 으로 설정하려면 plt.set_cmap이름을 지정하고 등록해야합니다. 즉,

cm = from_list('Set15', plt.cm.Set1(range(0,n)), n)
plt.cm.register_cmap(None, cm)
plt.set_cmap(cm)
...
plt.scatter(x, y, c=z)

분산 된 색상이있는 산점도


1

컬러 맵을 생성하기 위해 colors.ListedColormap 을 보고 싶 거나 정적 컬러 맵이 필요한 경우 도움이 될 수 있는 앱 에서 작업 하고 있습니다.


내 필요에 따라 멋지거나 과도하게 보일 수 있습니다. 기존 컬러 맵에 회색 값을 태그하는 방법을 제안 해 주시겠습니까? 0 값은 회색으로 나오고 다른 값은 색상으로 나오나요?
bph

@Hiett y 값을 기반으로 RGB 배열 color_list를 생성하고 ListedColormap에 전달하는 것은 어떻습니까? color_list [y == value_to_tag] = gray_color로 값에 태그를 지정할 수 있습니다.
ChrisC 2013
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.