माटप्लोटलिब असतत रंगबार


94

मैं मैटलपोटलिब में स्कैटरप्लॉट के लिए असतत रंग बनाने की कोशिश कर रहा हूं

मेरे पास मेरा x, y डेटा है और प्रत्येक बिंदु के लिए एक पूर्णांक टैग मान है जिसे मैं एक अद्वितीय रंग के साथ प्रस्तुत करना चाहता हूं, जैसे

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

आम तौर पर टैग 0-20 से पूर्णांक होगा, लेकिन सटीक सीमा बदल सकती है

अब तक मैंने सिर्फ डिफ़ॉल्ट सेटिंग्स का उपयोग किया है, उदाहरण के लिए

plt.colorbar()

जो रंगों की एक निरंतर श्रृंखला देता है। आदर्श रूप से मैं n असतत रंगों का एक सेट (n = 20 इस उदाहरण में) चाहूंगा। इससे भी बेहतर होगा कि ग्रे रंग का उत्पादन करने के लिए 0 का टैग मूल्य प्राप्त किया जाए और 1-20 रंगीन हो।

मुझे कुछ 'कुकबुक' स्क्रिप्ट मिली हैं, लेकिन वे बहुत जटिल हैं और मुझे नहीं लगता कि वे एक उचित सरल समस्या को हल करने का सही तरीका हैं


1
करता है इस या इस मदद करता है?
फ्रांसेस्को मोंटेसानो

लिंक के लिए धन्यवाद, लेकिन दूसरा उदाहरण है कि मैं क्या मतलब है कि बहुत अधिक जटिल के बारे में मतलब है (प्रतीत होता है) तुच्छ कार्य करने के लिए - 1 लिंक उपयोगी है
bph

1
मुझे यह लिंक मौजूदा कॉलोर्मैप को समझने
BallpointBen

जवाबों:


91

आप अपने तितर बितर के लिए normalizer के रूप में एक बाउंडरीऑर्म का उपयोग करके एक कस्टम असतत colorbar काफी आसानी से बना सकते हैं। विचित्र बिट (मेरी विधि में) 0 शोअप को ग्रे बना रहा है।

छवियों के लिए मैं अक्सर cmap.set_bad () का उपयोग करता हूं और अपने डेटा को एक सुस्पष्ट नकाबपोश सरणी में परिवर्तित करता हूं। यह 0 ग्रे बनाने के लिए बहुत आसान होगा, लेकिन मैं इस बिखराव या कस्टम 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
जीशान खान

इस जवाब के लिए धन्यवाद, वास्तव में यह डॉक्टर से याद आती है। मैंने इसे प्रतिशत के विंड्रोस के लिए स्थानांतरित करने की कोशिश की और मेरे पास रंग मानचित्रण के साथ एक बग था। यह एक अलग उपयोग मामला है, लेकिन यह सुझाव दे सकता है कि यह N-1अंदर है cmap = mpl.colors.LinearSegmentedColormap.from_list('Custom cmap', cmaplist, cmap.N-1)। यदि रंग डिब्बे के भीतर समान रूप से वितरित नहीं किए जाते हैं और आपके पास बाड़ बाधा समस्या है।
जेंलडर्की

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 ('जेट', 20) फिर तितर बितर (x, y, c = टैग, cmap = cmap) मुझे वहाँ का हिस्सा मिलता है - इसकी बहुत मुश्किल है matplotlib के लिए उपयोगी दस्तावेज
ढूंढना

लिंक टूटा हुआ लगता है, FYI करें।
क्विन

42

उपरोक्त उत्तर अच्छे हैं, सिवाय इसके कि उनके पास कलरबार पर उचित टिक प्लेसमेंट नहीं है। मुझे रंग के बीच में टिक्स होना पसंद है ताकि नंबर -> कलर मैपिंग अधिक स्पष्ट हो। आप इस समस्या को 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)

असतत colorbar का उदाहरण


1
मैं सहमत हूं कि असतत डेटा को देखते समय संबंधित रंग के बीच में टिक को रखने से बहुत मदद मिलती है। आपका दूसरा तरीका सही है। हालांकि, आपकी पहली विधि, सामान्य रूप से, गलत है : आप उन मानों के साथ टिक्स को लेबल कर रहे हैं , जो कलरबार पर उनके प्लेसमेंट के साथ असंगत हैं। set_ticklabels(...)केवल लेबल स्वरूपण (जैसे दशमलव संख्या, आदि) को नियंत्रित करने के लिए उपयोग किया जाना चाहिए। यदि डेटा वास्तव में असतत है, तो आपको कोई समस्या नहीं दिख सकती है। यदि सिस्टम में शोर है (उदाहरण 2 -> 1.9), तो इस असंगत लेबलिंग के परिणामस्वरूप एक भ्रामक और गलत रंग पट्टी हो जाएगी।
ई। डेविस

ई।, मुझे लगता है कि आप सही हैं कि सीमाएं बदलना बेहतर समाधान है इसलिए मैंने एक दूसरे को हटा दिया- हालांकि न तो "शोर" को अच्छी तरह से संभालना होगा। निरंतर डेटा को संभालने के लिए कुछ समायोजन की आवश्यकता होगी।
बेन्दिच्टर

37

कॉलोर्मैप की सीमा के ऊपर या नीचे एक मान सेट करने के लिए, आप कॉलोरामैप के तरीकों set_overऔर set_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' अपरिभाषित है। यह भी स्पष्ट नहीं है कि लैम्ब्डा फ़ंक्शन में 'पॉस' क्या है। धन्यवाद!
जॉर्ज लियू

@GeorgeLiu वास्तव में आप लिखे गए थे! मैंने एक कॉपी / पेस्ट गलती की है और यह अब fxed है! कोड का स्निपेट अब चल रहा है! इस बारे में posमुझे पूरी तरह से यकीन नहीं है कि यह यहाँ क्यों है, लेकिन यह फंकफॉर्मर () द्वारा अनुरोध किया गया है ... हो सकता है कि कोई और हमें इसके बारे में बता सके!
एनजौपी 12

7

मैं इन विचारों की जांच कर रहा हूं और यहां मेरे पांच सेंट का मूल्य है। यह बुला टाल BoundaryNormके साथ ही निर्दिष्ट करने normके लिए एक तर्क के रूप scatterऔर colorbar। हालाँकि मुझे लंबे समय से प्रसारित कॉल को खत्म करने का कोई तरीका नहीं मिला है matplotlib.colors.LinearSegmentedColormap.from_list

कुछ पृष्ठभूमि यह है कि matplotlib तथाकथित गुणात्मक कॉलॉर्मैप प्रदान करता है, जिसका उद्देश्य असतत डेटा के साथ उपयोग करना है। Set1, उदाहरण के लिए, 9 आसानी से अलग रंग हैं, और tab2020 रंगों के लिए इस्तेमाल किया जा सकता है। इन मानचित्रों के साथ, यह निम्न उदाहरणों के अनुसार, बिखरे हुए भूखंडों को 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_list निर्दिष्ट के साथ एक नक्शा के निर्माण के लिए nरंग (डिफ़ॉल्ट जा रहा है 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

मुझे लगता है कि आप अपने colormap को उत्पन्न करने के लिए रंगों को देखना चाहते हैं। LolColormap , या यदि आपको बस एक स्थैतिक कॉलोराम की आवश्यकता है, तो मैं एक ऐसे ऐप पर काम कर रहा हूँ जो मदद कर सकता है।


मेरी जरूरतों के लिए संभवतः शांत दिख रहा है - क्या आप मौजूदा कॉलॉर्मैप पर ग्रे मान टैग करने का एक तरीका सुझा सकते हैं? ताकि 0 मूल्य भूरे रंग के और दूसरे रंग के रूप में सामने आएं?
17

@ क्या आप अपने y मूल्यों के आधार पर आरजीबी सरणी color_list पैदा करने और ListedColormap को पारित करने के बारे में क्या? आप color_list [y == value_to_tag] = grey_color के साथ एक मान टैग कर सकते हैं।
क्रिस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.