मैं मेटप्लोटलिब में घनत्व द्वारा एक बिखरे हुए प्लॉट को कैसे रंगीन बना सकता हूं?


83

मैं एक स्कैटर प्लॉट बनाना चाहूंगा जहां प्रत्येक बिंदु पास के बिंदुओं के स्थानिक घनत्व द्वारा रंगीन हो।

मैं एक बहुत ही समान प्रश्न पर आया हूं, जो R का उपयोग करके इसका एक उदाहरण दिखाता है:

स्कैटर प्लॉट: प्रतीक रंग अतिव्यापी बिंदुओं की संख्या का प्रतिनिधित्व करता है

माइटप्लोटलिब का उपयोग करके अजगर में कुछ इसी तरह से पूरा करने का सबसे अच्छा तरीका क्या है?


4
नमस्ते! लोग आपको शायद नीचा दिखा रहे हैं क्योंकि आपने प्रश्न को फिर से नहीं लिखा है और न ही कोई संदर्भ दिया है, और न ही आपने खुद को ऐसा करने का कोई प्रयास किया है। प्रश्न को आत्मनिर्भर बनाने के लिए (केवल एक लिंक नहीं) और भविष्य के प्रश्नों के लिए, कृपया पोस्ट करने से पहले कुछ प्रयास करें।
'20

जवाबों:


157

hist2dया hexbinजैसा कि @askewchan ने सुझाव दिया है, इसके अलावा , आप उसी विधि का उपयोग कर सकते हैं जो आपके द्वारा उपयोग किए गए प्रश्न में स्वीकृत उत्तर है।

यदि आप ऐसा करना चाहते हैं:

import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import gaussian_kde

# Generate fake data
x = np.random.normal(size=1000)
y = x * 3 + np.random.normal(size=1000)

# Calculate the point density
xy = np.vstack([x,y])
z = gaussian_kde(xy)(xy)

fig, ax = plt.subplots()
ax.scatter(x, y, c=z, s=100, edgecolor='')
plt.show()

यहाँ छवि विवरण दर्ज करें

यदि आप चाहते हैं कि घनत्व के क्रम में बिंदुओं को प्लॉट किया जाए ताकि घने बिंदु हमेशा शीर्ष पर (लिंक किए गए उदाहरण के समान) हों, तो बस उन्हें z-मानों द्वारा क्रमबद्ध करें। मैं यहाँ एक छोटे मार्कर आकार का उपयोग करने जा रहा हूँ क्योंकि यह थोड़ा बेहतर दिखता है:

import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import gaussian_kde

# Generate fake data
x = np.random.normal(size=1000)
y = x * 3 + np.random.normal(size=1000)

# Calculate the point density
xy = np.vstack([x,y])
z = gaussian_kde(xy)(xy)

# Sort the points by density, so that the densest points are plotted last
idx = z.argsort()
x, y, z = x[idx], y[idx], z[idx]

fig, ax = plt.subplots()
ax.scatter(x, y, c=z, s=50, edgecolor='')
plt.show()

यहाँ छवि विवरण दर्ज करें


4
चतुर, विशेष रूप से शीर्ष पर 'घने' वाले हो रहे हैं :)
Askewchan

5
@Leszek - ईथर कॉल plt.colorbar(), या यदि आप अधिक स्पष्ट होना पसंद करते हैं, तो cax = ax.scatter(...)और फिर fig.colorbar(cax)। विदित हो कि इकाइयां अलग-अलग हैं। यह विधि अंकों के लिए संभाव्यता वितरण फ़ंक्शन का अनुमान लगाती है, इसलिए मान 0 1 1 (और आम तौर पर 1 के बहुत करीब नहीं मिलेगा) के बीच होगा। आप हिस्टोग्राम काउंट्स के करीब वापस कुछ में परिवर्तित कर सकते हैं, लेकिन इसमें थोड़ा काम लगता है (आपको gaussian_kdeडेटा से अनुमानित मापदंडों को जानने की आवश्यकता है )।
जो किंगटन

1
बहुत अच्छा! पायथन में अन्य केडीई की जाँच करना भी उपयोगी हो सकता है: jakevdp.github.io/blog/2013/12/01/kernel-density-estimation और scikit-learn.org/stable/modules/density.html मेरे मामले में scipy.stats 'केडीई को बहुत लंबा समय लग रहा था
रीम्स

1
गाऊसी कर्नेल को दो बार (xy) के साथ क्यों कहा जाता है?
अर्जन ग्रोएन

@ArjanGroen पहली कॉल एक नई गाऊसी_केड ऑब्जेक्ट बनाता है और दूसरा कॉल बिंदुओं के सेट पर अनुमानित पीडीएफ का मूल्यांकन करता है (मूल्यांकन पद्धति को कॉल करने के लिए शॉर्टकट)।
qRTPCR

35

आप हिस्टोग्राम बना सकते हैं:

import numpy as np
import matplotlib.pyplot as plt

# fake data:
a = np.random.normal(size=1000)
b = a*3 + np.random.normal(size=1000)

plt.hist2d(a, b, (50, 50), cmap=plt.cm.jet)
plt.colorbar()

2dhist


जो किंगटन के समाधान के पैमाने से बेहतर मिलान करने के लिए, आप लॉगस्केल में प्लॉट करना चाह सकते हैं  : plt.hist2d(…, norm = LogNorm())(साथ from matplotlib.colors import LogNorm)।
स्किप्पी ले ग्रैंड गौरू

29

इसके अलावा, अगर बिंदु की संख्या केडीई गणना को बहुत धीमा कर देती है, तो रंग को np.histogram2d में इंटरपोल किया जा सकता है [टिप्पणियों के जवाब में अपडेट करें: यदि आप कलरबार दिखाना चाहते हैं, तो ax.scatter () के बजाय plt.scatter () का उपयोग करें। plt.colorbar ()] द्वारा:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.colors import Normalize 
from scipy.interpolate import interpn

def density_scatter( x , y, ax = None, sort = True, bins = 20, **kwargs )   :
    """
    Scatter plot colored by 2d histogram
    """
    if ax is None :
        fig , ax = plt.subplots()
    data , x_e, y_e = np.histogram2d( x, y, bins = bins, density = True )
    z = interpn( ( 0.5*(x_e[1:] + x_e[:-1]) , 0.5*(y_e[1:]+y_e[:-1]) ) , data , np.vstack([x,y]).T , method = "splinef2d", bounds_error = False)

    #To be sure to plot all data
    z[np.where(np.isnan(z))] = 0.0

    # Sort the points by density, so that the densest points are plotted last
    if sort :
        idx = z.argsort()
        x, y, z = x[idx], y[idx], z[idx]

    ax.scatter( x, y, c=z, **kwargs )

    norm = Normalize(vmin = np.min(z), vmax = np.max(z))
    cbar = fig.colorbar(cm.ScalarMappable(norm = norm), ax=ax)
    cbar.ax.set_ylabel('Density')

    return ax


if "__main__" == __name__ :

    x = np.random.normal(size=100000)
    y = x * 3 + np.random.normal(size=100000)
    density_scatter( x, y, bins = [30,30] )


1
यह एक शानदार टिप है, धन्यवाद। मैं 100k अंक की साजिश रच रहा था और गाऊसी_केड निषेधात्मक रूप से धीमा था।
इमानुएल

2
चेतावनी, मैंने देखा कि कुछ मामलों में यह NaN उत्पन्न करता है और क्योंकि "सीमा = गलत" यह मौन है। NaNs के लिए c सेट वाले पॉइंट्स प्लॉट नहीं किए गए हैं। यह gaussian_kde के साथ कोई समस्या नहीं है।
इमानुएल

इस प्रतिक्रिया के लिए बहुत धन्यवाद। आमतौर पर हम इस तरह का हीटमैप चाहते हैं जब हमारे पास बड़ी संख्या में डेटा पॉइंट हों, और केडीई इस मामले में बहुत धीमा हो। हालांकि, अभी भी एक खुला मुद्दा है। मैं आवृत्ति का संकेत देने वाला एक रंगीन बार शामिल करना चाहता हूं! यह एक त्रुटि फेंकता है: 'AxesSubplot' ऑब्जेक्ट में कोई विशेषता नहीं है 'autoscale_None'। मैंने "pl..colorbar (scat, ax = ax)" किया
विनोद कुमार

@VinodKumar आपको पता चला कि कोलोरबार की साजिश कैसे की जाती है?
डैनियल

1
@ डैनियल हां यह संभव है, संपादित जवाब देखें। आपको हिस्टोग्राम बनाते समय "घनत्व = सही" सेट करना होगा, अन्यथा, रंग पट्टी बिन आकार पर निर्भर करती है। @ इमानुएल, वास्तव में! मैंने सभी बिंदुओं पर साजिश करने के लिए NaNs को शून्य से बदल दिया है (NaNs तब होना चाहिए जब बहुत अधिक डेटा न हो, ताकि 0.0 पर्याप्त रूप से ठीक हो जाए)
Guillaume

6

प्लॉटिंग> 100k डेटा पॉइंट्स?

स्वीकार किए जाते हैं जवाब , का उपयोग कर gaussian_kde () बहुत समय लगेगा। मेरी मशीन पर, 100k पंक्तियों में लगभग 11 मिनट लगे । यहाँ मैं दो वैकल्पिक विधियाँ ( mpl- तितर बितर-घनत्व और डेटाशेयर ) जोड़ूँगा और समान डेटासेट के साथ दिए गए उत्तरों की तुलना करूँगा

निम्नलिखित में, मैंने 100k पंक्तियों के एक परीक्षण डेटा सेट का उपयोग किया:

import matplotlib.pyplot as plt
import numpy as np

# Fake data for testing
x = np.random.normal(size=100000)
y = x * 3 + np.random.normal(size=100000)

आउटपुट और गणना समय की तुलना

नीचे विभिन्न तरीकों की तुलना है।

1: mpl-scatter-density

इंस्टालेशन

pip install mpl-scatter-density

उदाहरण कोड

import mpl_scatter_density # adds projection='scatter_density'
from matplotlib.colors import LinearSegmentedColormap

# "Viridis-like" colormap with white background
white_viridis = LinearSegmentedColormap.from_list('white_viridis', [
    (0, '#ffffff'),
    (1e-20, '#440053'),
    (0.2, '#404388'),
    (0.4, '#2a788e'),
    (0.6, '#21a784'),
    (0.8, '#78d151'),
    (1, '#fde624'),
], N=256)

def using_mpl_scatter_density(fig, x, y):
    ax = fig.add_subplot(1, 1, 1, projection='scatter_density')
    density = ax.scatter_density(x, y, cmap=white_viridis)
    fig.colorbar(density, label='Number of points per pixel')

fig = plt.figure()
using_mpl_scatter_density(fig, x, y)
plt.show()

इसे खींचने में 0.05 सेकंड का समय लगा: mpl-बिखराव-घनत्व का उपयोग करना

और ज़ूम इन काफी अच्छा लगता है: mpl-बिखराव-घनत्व में ज़ूम करें

2: datashader

pip install "git+https://github.com/nvictus/datashader.git@mpl"

कोड ( यहाँ dsshow का स्रोत ):

from functools import partial

import datashader as ds
from datashader.mpl_ext import dsshow
import pandas as pd

dyn = partial(ds.tf.dynspread, max_px=40, threshold=0.5)

def using_datashader(ax, x, y):

    df = pd.DataFrame(dict(x=x, y=y))
    da1 = dsshow(df, ds.Point('x', 'y'), spread_fn=dyn, aspect='auto', ax=ax)
    plt.colorbar(da1)

fig, ax = plt.subplots()
using_datashader(ax, x, y)
plt.show()
  • इसे ड्रा करने में 0.83 सेकंड लगे:

यहाँ छवि विवरण दर्ज करें

और ज़ूम की गई छवि बहुत अच्छी लगती है!

यहाँ छवि विवरण दर्ज करें

3: scatter_with_gaussian_kde

def scatter_with_gaussian_kde(ax, x, y):
    # https://stackoverflow.com/a/20107592/3015186
    # Answer by Joel Kington

    xy = np.vstack([x, y])
    z = gaussian_kde(xy)(xy)

    ax.scatter(x, y, c=z, s=100, edgecolor='')
  • इसे बनाने में 11 मिनट लगे: scatter_with_gaussian_kde

4: using_hist2d

import matplotlib.pyplot as plt
def using_hist2d(ax, x, y, bins=(50, 50)):
    # https://stackoverflow.com/a/20105673/3015186
    # Answer by askewchan
    ax.hist2d(x, y, bins, cmap=plt.cm.jet)

  • इस डिब्बे को खींचने में 0.021 सेकेंड लगते हैं = (50,50): using_hist2d_50
  • इस डिब्बे को खींचने में 0.173 सेकेंड का समय लगा (= 1000,1000): using_hist2d_1000
  • विपक्ष: ज़ूम-इन डेटा mpl-बिखराव-घनत्व या डेटाशेयर के साथ उतना अच्छा नहीं दिखता है। इसके अलावा, आपको अपने आप डिब्बे की संख्या निर्धारित करनी होगी।

hist2d 1000bins में ज़ूम किया गया

5: density_scatter

  • कोड Guillaume द्वारा उत्तर में है ।
  • इसे बीन = (50,50) के साथ खींचने में 0.073 सेकेंड का समय लगा: density_scatter_50bins
  • इसे बिन्स के साथ निकालने के लिए 0.368 s = (1000,1000) लिया गया: density_scatter_1000bins
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.