Dağılım veri kümesi kullanarak MatPlotLib'de bir ısı haritası oluşturma


187

Bir dağılım grafiği olarak çizmek kolay ama ben bir ısı haritası olarak temsil etmek istiyorum X, Y veri noktaları (yaklaşık 10k) bir dizi var.

MatPlotLib örnekleri inceledim ve hepsi zaten görüntü oluşturmak için heatmap hücre değerleri ile başlamak gibi görünüyor.

Bir grup x, y, tamamen farklı bir ısı eşlemesine dönüştüren bir yöntem var mı?


Yanıtlar:


182

Altıgenler istemiyorsanız numpy histogram2dişlevini kullanabilirsiniz :

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

# Generate some test data
x = np.random.randn(8873)
y = np.random.randn(8873)

heatmap, xedges, yedges = np.histogram2d(x, y, bins=50)
extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]]

plt.clf()
plt.imshow(heatmap.T, extent=extent, origin='lower')
plt.show()

Bu 50x50 ısı haritası yapar. İsterseniz, diyelim ki, 512x384, sen koyabilirsiniz bins=(512, 384)çağrısında histogram2d.

Misal: Matplotlib ısı haritası örneği


1
Bir aptal olmak istemiyorum, ama aslında bu etkileşimi sadece etkileşimli bir IPython oturumunda göstermek yerine bir PNG / PDF dosyasına nasıl sahip oluyorsunuz? Ben axesbir başlık, eksen etiketleri, vb ekleyebilir ve daha sonra savefig()herhangi bir diğer tipik matplotlib arsa için yapacağım gibi normal yapmak normal örnek bir tür olarak almaya çalışıyorum .
gotgenes

3
@gotgenes: çalışmıyor plt.savefig('filename.png')? Bir eksen örneği almak istiyorsanız, Matplotlib'in nesneye yönelik arayüzünü kullanın:fig = plt.figure() ax = fig.gca() ax.imshow(...) fig.savefig(...)
ptomato

1
Gerçekten, teşekkürler! Sanırım bununla imshow()aynı işlev kategorisinde olduğunu tam olarak anlamıyorum scatter(). Dürüst olmak gerekirse neden böyle bir dizi ile imshow()ne scatter()yapılması gerektiğini anlıyorum, yüzen bir 2d dizi uygun renk blokları dönüştürür anlamıyorum .
gotgenes

14
Aşağıdaki gibi x / y değerlerinin 2d histogramını çizmek için imshow kullanma hakkında bir uyarı: varsayılan olarak imshow, orijini sol üst köşeye çizer ve görüntüyü aktarır. Dağılım arsa ile aynı yönelimi elde etmek için ne yapacağımplt.imshow(heatmap.T, extent=extent, origin = 'lower')
Jamie

7
Logaritmik bir renk çubuğu yapmak isteyenler için şu soruya bakın stackoverflow.com/questions/17201172/… ve basitçe yapınfrom matplotlib.colors import LogNorm plt.imshow(heatmap, norm=LogNorm()) plt.colorbar()
tommy.carstensen

109

In Matplotlib sözlüğü sana bir istediğini düşünüyorum hexbin arsa.

Bu tür bir arsaya aşina değilseniz , xy-düzleminin düzenli bir altıgen ızgarası ile döşendiği sadece iki değişkenli bir histogramdır .

Yani bir histogramdan, her altıgene düşen nokta sayısını sayabilir, çizim bölgesini bir dizi olarak ayrıştırabilirsiniz. pencere her noktayı bu pencerelerden birine atayabilirsiniz; Son olarak, pencereleri bir renk dizisine eşleştirdiğinizde bir hexbin diyagramınız olur.

Daireler veya karelerden daha az yaygın olmasına rağmen, altıgenler binleme kabının geometrisi için daha iyi bir seçimdir sezgisel:

  • altıgenler sahip en yakın komşuya simetrisi (örneğin, kare kutuları yapamaz, örneğin, mesafe gelen bir meydanın sınırında bir noktaya kadar bu kare içinde bir noktadan her yerde eşit değildir) ve

  • altıgen, düzenli düzlem mozaikleme sağlayan en yüksek n-çokgendir (yani, mutfak zemini altıgen şekilli karolarla güvenle yeniden modelleyebilirsiniz, çünkü işiniz bittiğinde fayanslar arasında boşluk bulunmaz - doğru değil diğer tüm yüksek-n, n> = 7, çokgenler).

( Matplotlib terim kullanır hexbin arsa; bunu (AFAIK) tüm komplo kütüphaneleri için Ar ; bu bu tip araziler için genel kabul görmüş bir terimdir eğer ben büyük olasılıkla o verdi şüpheli rağmen hala ben, bilmiyorum hexbin kısadır için altıgen binning , hangi ekran verileri hazırlanmasında esas teşkil eden aşamayı anlatmaktadır.)


from matplotlib import pyplot as PLT
from matplotlib import cm as CM
from matplotlib import mlab as ML
import numpy as NP

n = 1e5
x = y = NP.linspace(-5, 5, 100)
X, Y = NP.meshgrid(x, y)
Z1 = ML.bivariate_normal(X, Y, 2, 2, 0, 0)
Z2 = ML.bivariate_normal(X, Y, 4, 1, 1, 1)
ZD = Z2 - Z1
x = X.ravel()
y = Y.ravel()
z = ZD.ravel()
gridsize=30
PLT.subplot(111)

# if 'bins=None', then color of each hexagon corresponds directly to its count
# 'C' is optional--it maps values to x-y coordinates; if 'C' is None (default) then 
# the result is a pure 2D histogram 

PLT.hexbin(x, y, C=z, gridsize=gridsize, cmap=CM.jet, bins=None)
PLT.axis([x.min(), x.max(), y.min(), y.max()])

cb = PLT.colorbar()
cb.set_label('mean value')
PLT.show()   

resim açıklamasını buraya girin


"Altıgenlerin en yakın komşu simetrisine sahip oldukları" ne anlama geliyor? "Bir karenin sınırındaki bir nokta ile o karenin içindeki bir nokta arasındaki mesafenin her yerde eşit olmadığını" ama neye olan mesafenin olduğunu söylüyorsunuz?
Jaan

9
Bir altıgen için, merkezden bir kenara birleştirilen bir tepe noktasına olan mesafe de bir kenarın ortasından ortasından daha uzundur, sadece oran daha küçüktür (2 / metrekare (3) hex altıgen yerine metrekare (2) vs. 1,41 kare için). Merkezden sınırdaki her noktaya olan mesafenin eşit olduğu tek şekil daire.
Jaan

5
@Jaan Altıgen için her komşu aynı mesafede. 8 ya da 4 mahallede herhangi bir sorun yoktur. Diyagonal komşular yok, sadece bir tür komşu.
isarandi

@doug Parametreyi nasıl seçersiniz gridsize=. Bunu seçmek istiyorum, böylece altıgenler üst üste binmeden sadece dokunuyorlar. Bunun gridsize=100daha küçük altıgenler üreteceğini fark ettim , ancak uygun değeri nasıl seçebilirim?
Alexander Cska

40

Düzenleme: Alejandro'nun cevabının daha iyi bir tahmini için aşağıya bakın.

Bunun eski bir soru olduğunu biliyorum, ancak Alejandro'nun anwser'ına bir şey eklemek istedim: Py-sphviewer kullanmadan güzel bir düzgünleştirilmiş görüntü istiyorsanız, bunun yerine ısı haritasına np.histogram2dbir gauss filtresi (from scipy.ndimage.filters) kullanabilirsiniz:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from scipy.ndimage.filters import gaussian_filter


def myplot(x, y, s, bins=1000):
    heatmap, xedges, yedges = np.histogram2d(x, y, bins=bins)
    heatmap = gaussian_filter(heatmap, sigma=s)

    extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]]
    return heatmap.T, extent


fig, axs = plt.subplots(2, 2)

# Generate some test data
x = np.random.randn(1000)
y = np.random.randn(1000)

sigmas = [0, 16, 32, 64]

for ax, s in zip(axs.flatten(), sigmas):
    if s == 0:
        ax.plot(x, y, 'k.', markersize=5)
        ax.set_title("Scatter plot")
    else:
        img, extent = myplot(x, y, s)
        ax.imshow(img, extent=extent, origin='lower', cmap=cm.jet)
        ax.set_title("Smoothing with  $\sigma$ = %d" % s)

plt.show()

üretir:

Çıktı görüntüleri

Agape Gal'lo için saçılma grafiği ve s = 16 birbirinin üstüne çizilmiştir (daha iyi görüntülemek için tıklayın):

Birbirinin üstünde


Gauss filtre yaklaşımı ve Alejandro'nun yaklaşımı ile fark ettiğim bir fark, yönteminin yerel yapıları benimkinden daha iyi göstermesiydi. Bu yüzden piksel düzeyinde en yakın komşu yöntemi uyguladım. Bu yöntem, her piksel için mesafelerin ters toplamını hesaplar.n için verilerdeki en yakın noktaların . Bu yöntem oldukça hesaplamalı olarak yüksek bir çözünürlükte ve daha hızlı bir yol olduğunu düşünüyorum, bu yüzden herhangi bir gelişme varsa bana bildirin.

Güncelleme: Şüphelendiğim gibi, Scipy's kullanarak çok daha hızlı bir yöntem var scipy.cKDTree. Uygulama için Gabriel'in cevabına bakınız .

Her neyse, işte kodum:

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


def data_coord2view_coord(p, vlen, pmin, pmax):
    dp = pmax - pmin
    dv = (p - pmin) / dp * vlen
    return dv


def nearest_neighbours(xs, ys, reso, n_neighbours):
    im = np.zeros([reso, reso])
    extent = [np.min(xs), np.max(xs), np.min(ys), np.max(ys)]

    xv = data_coord2view_coord(xs, reso, extent[0], extent[1])
    yv = data_coord2view_coord(ys, reso, extent[2], extent[3])
    for x in range(reso):
        for y in range(reso):
            xp = (xv - x)
            yp = (yv - y)

            d = np.sqrt(xp**2 + yp**2)

            im[y][x] = 1 / np.sum(d[np.argpartition(d.ravel(), n_neighbours)[:n_neighbours]])

    return im, extent


n = 1000
xs = np.random.randn(n)
ys = np.random.randn(n)
resolution = 250

fig, axes = plt.subplots(2, 2)

for ax, neighbours in zip(axes.flatten(), [0, 16, 32, 64]):
    if neighbours == 0:
        ax.plot(xs, ys, 'k.', markersize=2)
        ax.set_aspect('equal')
        ax.set_title("Scatter Plot")
    else:
        im, extent = nearest_neighbours(xs, ys, resolution, neighbours)
        ax.imshow(im, origin='lower', extent=extent, cmap=cm.jet)
        ax.set_title("Smoothing over %d neighbours" % neighbours)
        ax.set_xlim(extent[0], extent[1])
        ax.set_ylim(extent[2], extent[3])
plt.show()

Sonuç:

En Yakın Komşu Düzeltme


1
Bunu sev. Grafik Alejandro'nun yanıtı kadar güzel, ancak yeni paketler gerekli değil.
Nathan Clement

Çok hoş ! Ama bu yöntemle bir ofset üretiyorsunuz. Bunu, normal bir dağılım grafiğini renkli grafikle karşılaştırarak görebilirsiniz. Düzeltmek için bir şeyler ekleyebilir misiniz? Ya da sadece grafiği x ve y değerlerine taşımak için?
Agape Gal'lo

1
Agape Gal'lo, ofset ile ne demek istiyorsun? Bunları birbirinin üzerine çizerseniz, eşleşirler (yazımın düzenlenmesine bakın). Belki ertelersiniz çünkü saçılımın genişliği diğer üç ile tam olarak eşleşmez.
Jurgy

Grafiği sadece benim için çizdiğiniz için çok teşekkürler! Hatamı anladım: x ve y sınırlarını tanımlamak için "kapsamı" değiştirmiştim. Şimdi grafiğin kökenini değiştirdiğini anlıyorum. Sonra, son bir sorum var: mevcut verilerin olmadığı alan için bile grafiğin sınırlarını nasıl genişletebilirim? Örneğin, x ve y için -5 ila +5 arasında.
Agape Gal'lo

1
X ekseninin -5'ten 5'e ve y ekseninin -3'ten 4'e gitmesini istediğinizi varsayalım; olarak myplotişlev eklemek rangeiçin parametre np.histogram2d: np.histogram2d(x, y, bins=bins, range=[[-5, 5], [-3, 4]])ve dongu içerisinde x ve eksen y lmt ayarlayın: ax.set_xlim([-5, 5]) ax.set_ylim([-3, 4]). Ayrıca, varsayılan olarak, imshowsizin eksenlerinin oranı aynı boy oranını tutar (yani benim örnekte 10 oranı: 7), ancak bunu, senin çizim penceresine uyacak parametre eklemek istiyorsanız aspect='auto'için imshow.
Jurgy

31

Genel olarak oldukça çirkin histogramlar üreten np.hist2d kullanmak yerine, uyarlanabilir bir yumuşatma çekirdeği kullanarak parçacık simülasyonları yapmak için bir python paketi olan py-sphviewer'ı geri dönüştürmek istiyorum (web sayfasının belgelerine kolayca bakın). Örneğe dayanan aşağıdaki kodu göz önünde bulundurun:

import numpy as np
import numpy.random
import matplotlib.pyplot as plt
import sphviewer as sph

def myplot(x, y, nb=32, xsize=500, ysize=500):   
    xmin = np.min(x)
    xmax = np.max(x)
    ymin = np.min(y)
    ymax = np.max(y)

    x0 = (xmin+xmax)/2.
    y0 = (ymin+ymax)/2.

    pos = np.zeros([3, len(x)])
    pos[0,:] = x
    pos[1,:] = y
    w = np.ones(len(x))

    P = sph.Particles(pos, w, nb=nb)
    S = sph.Scene(P)
    S.update_camera(r='infinity', x=x0, y=y0, z=0, 
                    xsize=xsize, ysize=ysize)
    R = sph.Render(S)
    R.set_logscale()
    img = R.get_image()
    extent = R.get_extent()
    for i, j in zip(xrange(4), [x0,x0,y0,y0]):
        extent[i] += j
    print extent
    return img, extent

fig = plt.figure(1, figsize=(10,10))
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222)
ax3 = fig.add_subplot(223)
ax4 = fig.add_subplot(224)


# Generate some test data
x = np.random.randn(1000)
y = np.random.randn(1000)

#Plotting a regular scatter plot
ax1.plot(x,y,'k.', markersize=5)
ax1.set_xlim(-3,3)
ax1.set_ylim(-3,3)

heatmap_16, extent_16 = myplot(x,y, nb=16)
heatmap_32, extent_32 = myplot(x,y, nb=32)
heatmap_64, extent_64 = myplot(x,y, nb=64)

ax2.imshow(heatmap_16, extent=extent_16, origin='lower', aspect='auto')
ax2.set_title("Smoothing over 16 neighbors")

ax3.imshow(heatmap_32, extent=extent_32, origin='lower', aspect='auto')
ax3.set_title("Smoothing over 32 neighbors")

#Make the heatmap using a smoothing over 64 neighbors
ax4.imshow(heatmap_64, extent=extent_64, origin='lower', aspect='auto')
ax4.set_title("Smoothing over 64 neighbors")

plt.show()

aşağıdaki görüntüyü üretir:

resim açıklamasını buraya girin

Gördüğünüz gibi, görüntüler oldukça güzel görünüyor ve üzerinde farklı alt yapıları belirleyebiliyoruz. Bu görüntüler, belirli bir etki alanı içindeki her nokta için belirli bir ağırlıkta, düzgünleştirme uzunluğu ile tanımlanan, sırayla daha yakın nb komşusuna olan mesafeyle verilen bir ağırlık yayılarak oluşturulur (örnekler için 16, 32 ve 64'ü seçtim). Bu nedenle, daha yüksek yoğunluklu bölgeler, daha düşük yoğunluklu bölgelere kıyasla tipik olarak daha küçük bölgelere yayılır.

Myplot işlevi, sihir yapmak için py-sphviewer'a x, y verilerini vermek için yazdığım çok basit bir işlevdir.


2
OSX'e py-sphviewer kurmaya çalışan herkes için bir yorum: Oldukça çok zorluk yaşadım
Sam Finnigan

Çok kötü python3 ile çalışmıyor. Yükler, ancak kullanmaya çalıştığınızda çöküyor ...
Fábio Dias

1
@Fabio Dias, En son sürüm (1.1.x) şimdi Python 3 ile çalışıyor
Alejandro

29

1.2.x kullanıyorsanız

import numpy as np
import matplotlib.pyplot as plt

x = np.random.randn(100000)
y = np.random.randn(100000)
plt.hist2d(x,y,bins=100)
plt.show()

gaussian_2d_heat_map


17

Seaborn şimdi burada güzel çalışması gereken ortak çizim fonksiyonuna sahip:

import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt

# Generate some test data
x = np.random.randn(8873)
y = np.random.randn(8873)

sns.jointplot(x=x, y=y, kind='hex')
plt.show()

demo görüntüsü


Basit, güzel ve analitik olarak faydalı.
ryanjdillon

@wordsforthewise 600k veriyi bunu kullanarak görsel olarak nasıl okunabilir hale getirirsiniz? (yeniden boyutlandırma)
nrmb

Ne demek istediğinden pek emin değilim; belki ayrı bir soru sormak ve buraya bağlamak en iyisidir. Bütün inciri yeniden boyutlandırmak mı demek istiyorsun? Öncelikle ile çıkarmalarıiçin fig = plt.figure(figsize=(12, 12)), daha sonra şimdiki eksenini olsun ax=plt.gca()sonra argüman ekleyin ax=axüzere jointplotişlevi.
wordsforthewise

@wordsforthewise lütfen bu soruya cevap verebilir misiniz: stackoverflow.com/questions/50997662/… teşekkürler
ebrahimi

4

ve ilk soru şudur: dağılım değerlerini ızgara değerlerine dönüştürme, değil mi? histogram2dhücre başına sıklığı sayar, ancak hücre başına yalnızca frekanstan başka verileriniz varsa, yapmanız gereken bazı ek işler gerekir.

x = data_x # between -10 and 4, log-gamma of an svc
y = data_y # between -4 and 11, log-C of an svc
z = data_z #between 0 and 0.78, f1-values from a difficult dataset

Yani, X ve Y koordinatları için Z-sonuçları içeren bir veri setim var. Ancak, ilgi alanı dışında birkaç nokta (büyük boşluklar) ve küçük bir ilgi alanındaki nokta yığınları hesaplıyordum.

Evet burada daha zor ama aynı zamanda daha eğlenceli hale geliyor. Bazı kütüphaneler (üzgünüm):

from matplotlib import pyplot as plt
from matplotlib import cm
import numpy as np
from scipy.interpolate import griddata

pyplot bugün benim grafik motorum, cm bazı initeresting seçenekleriyle bir dizi renkli harita. hesaplamalar için numpy ve sabit bir ızgaraya değerler eklemek için griddata.

Sonuncusu özellikle xy noktalarının sıklığı verilerimde eşit dağılmadığı için önemlidir. İlk olarak, verilerime uyan bazı sınırlarla ve rastgele bir ızgara boyutuyla başlayalım. Orijinal veriler, bu x ve y sınırlarının dışında da veri noktalarına sahiptir.

#determine grid boundaries
gridsize = 500
x_min = -8
x_max = 2.5
y_min = -2
y_max = 7

Bu nedenle, x ve y'nin min ve maks değerleri arasında 500 piksellik bir ızgara tanımladık.

Verilerimde, yüksek ilgi alanında 500'den fazla değer var; düşük faizli alanda, toplam şebekede 200 değer bile yoktur; grafik sınırları arasında x_minve x_maxhatta daha az var.

Güzel bir resim elde etmek için görev, yüksek faiz değerleri için bir ortalama elde etmek ve başka yerlerdeki boşlukları doldurmaktır.

Izgaramı şimdi tanımlıyorum. Her xx-yy çifti için bir renk istiyorum.

xx = np.linspace(x_min, x_max, gridsize) # array of x values
yy = np.linspace(y_min, y_max, gridsize) # array of y values
grid = np.array(np.meshgrid(xx, yy.T))
grid = grid.reshape(2, grid.shape[1]*grid.shape[2]).T

Neden garip şekil? scipy.griddata (n, D) şeklini istiyor.

Griddata, önceden tanımlanmış bir yöntemle ızgaradaki her nokta için bir değer hesaplar. "En yakın" ı seçiyorum - boş ızgara noktaları en yakın komşunun değerleriyle doldurulacak. Bu, daha az bilgi içeren alanların daha büyük hücrelere sahip gibi görünüyor (durum olmasa bile). Birisi "doğrusal" enterpolasyon seçebilir, daha az bilgi ile alanlar daha az keskin görünüyor. Lezzet meselesi, gerçekten.

points = np.array([x, y]).T # because griddata wants it that way
z_grid2 = griddata(points, z, grid, method='nearest')
# you get a 1D vector as result. Reshape to picture format!
z_grid2 = z_grid2.reshape(xx.shape[0], yy.shape[0])

Ve hop, arsa görüntülemek için matplotlib'e teslim ediyoruz

fig = plt.figure(1, figsize=(10, 10))
ax1 = fig.add_subplot(111)
ax1.imshow(z_grid2, extent=[x_min, x_max,y_min, y_max,  ],
            origin='lower', cmap=cm.magma)
ax1.set_title("SVC: empty spots filled by nearest neighbours")
ax1.set_xlabel('log gamma')
ax1.set_ylabel('log C')
plt.show()

V Şeklinin sivri kısmının etrafında, tatlı noktayı araştırırken çok fazla hesaplama yaptığımı görürsünüz, oysa neredeyse her yerde daha az ilginç olan kısımlar daha düşük bir çözünürlüğe sahiptir.

Yüksek çözünürlükte bir SVC'nin ısı haritası


Tam ve çalıştırılabilir kodlara sahip olmak için cevabınızı geliştirebilir misiniz? Bu ilginç bir yöntem. Şu anda daha iyi anlamaya çalışıyorum. Neden bir V şekli olduğunu da tam olarak anlamıyorum. Teşekkürler.
ldmtwo

V-Şekli verilerimden geliyor. Eğitimli bir SVM için f1-değeri: SVM teorisinde bu biraz ilerliyor. Yüksek C'ye sahipseniz, hesaplamadaki tüm puanlarınızı içerir ve daha geniş bir gamma aralığının çalışmasına izin verir. Gama, iyi ve kötü arasındaki eğrinin sertliğidir. Bu iki değer SVM'ye verilmelidir (grafiğimde X ve Y); bir sonuç elde edersiniz (grafiğimde Z). En iyi alanda umarım anlamlı yüksekliklere ulaşırsınız.
Anderas

ikinci deneme: V-Şekli verilerimde. Bir SVM için f1-değeridir: Yüksek C'ye sahipseniz, hesaplamadaki tüm puanlarınızı içerir, daha geniş bir gamma aralığının çalışmasına izin verir, ancak hesaplamayı yavaşlatır. Gama, iyi ve kötü arasındaki eğrinin sertliğidir. Bu iki değer SVM'ye verilmelidir (grafiğimde X ve Y); bir sonuç elde edersiniz (grafiğimde Z). Optimize edilmiş alanda yüksek değerler, başka yerlerde düşük değerler elde edersiniz. Burada gösterdiğim, başka bir yerde (X, Y) ve birçok boşluk için Z değerleriniz varsa kullanılabilir. (X, Y, Z) veri noktalarınız varsa kodumu kullanabilirsiniz.
Anderas

4

İşte Jurgy'nin en yakın komşu yaklaşımı ancak scipy.cKDTree kullanılarak uygulandı . Testlerimde yaklaşık 100 kat daha hızlı.

resim açıklamasını buraya girin

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from scipy.spatial import cKDTree


def data_coord2view_coord(p, resolution, pmin, pmax):
    dp = pmax - pmin
    dv = (p - pmin) / dp * resolution
    return dv


n = 1000
xs = np.random.randn(n)
ys = np.random.randn(n)

resolution = 250

extent = [np.min(xs), np.max(xs), np.min(ys), np.max(ys)]
xv = data_coord2view_coord(xs, resolution, extent[0], extent[1])
yv = data_coord2view_coord(ys, resolution, extent[2], extent[3])


def kNN2DDens(xv, yv, resolution, neighbours, dim=2):
    """
    """
    # Create the tree
    tree = cKDTree(np.array([xv, yv]).T)
    # Find the closest nnmax-1 neighbors (first entry is the point itself)
    grid = np.mgrid[0:resolution, 0:resolution].T.reshape(resolution**2, dim)
    dists = tree.query(grid, neighbours)
    # Inverse of the sum of distances to each grid point.
    inv_sum_dists = 1. / dists[0].sum(1)

    # Reshape
    im = inv_sum_dists.reshape(resolution, resolution)
    return im


fig, axes = plt.subplots(2, 2, figsize=(15, 15))
for ax, neighbours in zip(axes.flatten(), [0, 16, 32, 63]):

    if neighbours == 0:
        ax.plot(xs, ys, 'k.', markersize=5)
        ax.set_aspect('equal')
        ax.set_title("Scatter Plot")
    else:

        im = kNN2DDens(xv, yv, resolution, neighbours)

        ax.imshow(im, origin='lower', extent=extent, cmap=cm.Blues)
        ax.set_title("Smoothing over %d neighbours" % neighbours)
        ax.set_xlim(extent[0], extent[1])
        ax.set_ylim(extent[2], extent[3])

plt.savefig('new.png', dpi=150, bbox_inches='tight')

1
Uygulamamın çok verimsiz olduğunu biliyordum ama cKDTree hakkında bir şey bilmiyordum. Aferin! Size cevabımda referans vereceğim.
Jurgy

2

Son görüntünüzde say denilen hücrelere karşılık gelen 2 boyutlu bir dizi yapın heatmap_cellsve tüm sıfırlar olarak başlatın .

Her boyut için, gerçek birimleri her bir dizi elemanı arasındaki farkı tanımlayan iki ölçekleme faktörleri seçim, söz x_scaleve y_scale. Bunları, tüm veri noktalarınız ısı haritası dizisinin sınırları içinde kalacak şekilde seçin.

İle her bir ham veri noktasının için x_valueve y_value:

heatmap_cells[floor(x_value/x_scale),floor(y_value/y_scale)]+=1


1

resim açıklamasını buraya girin

İşte 3 kategoriyle (Kırmızı, Yeşil ve Mavi renkli) 1 Milyon noktada yaptığım. İşlevi denemek istiyorsanız, depoya bir bağlantı. Github Repo

histplot(
    X,
    Y,
    labels,
    bins=2000,
    range=((-3,3),(-3,3)),
    normalize_each_label=True,
    colors = [
        [1,0,0],
        [0,1,0],
        [0,0,1]],
    gain=50)

0

@ Piti'nin cevabına çok benzer , ancak puan oluşturmak için 2 yerine 1 çağrı kullanın:

import numpy as np
import matplotlib.pyplot as plt

pts = 1000000
mean = [0.0, 0.0]
cov = [[1.0,0.0],[0.0,1.0]]

x,y = np.random.multivariate_normal(mean, cov, pts).T
plt.hist2d(x, y, bins=50, cmap=plt.cm.jet)
plt.show()

Çıktı:

2d_gaussian_heatmap


0

Korkarım partiye biraz geç kaldım ama bir süre önce benzer bir sorum vardı. Kabul edilen cevap (@ptomato tarafından) bana yardımcı oldu, ancak birisinin kullanılması durumunda da bunu göndermek istiyorum.


''' I wanted to create a heatmap resembling a football pitch which would show the different actions performed '''

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

#fixing random state for reproducibility
np.random.seed(1234324)

fig = plt.figure(12)
ax1 = fig.add_subplot(121)
ax2 = fig.add_subplot(122)

#Ratio of the pitch with respect to UEFA standards 
hmap= np.full((6, 10), 0)
#print(hmap)

xlist = np.random.uniform(low=0.0, high=100.0, size=(20))
ylist = np.random.uniform(low=0.0, high =100.0, size =(20))

#UEFA Pitch Standards are 105m x 68m
xlist = (xlist/100)*10.5
ylist = (ylist/100)*6.5

ax1.scatter(xlist,ylist)

#int of the co-ordinates to populate the array
xlist_int = xlist.astype (int)
ylist_int = ylist.astype (int)

#print(xlist_int, ylist_int)

for i, j in zip(xlist_int, ylist_int):
    #this populates the array according to the x,y co-ordinate values it encounters 
    hmap[j][i]= hmap[j][i] + 1   

#Reversing the rows is necessary 
hmap = hmap[::-1]

#print(hmap)
im = ax2.imshow(hmap)

İşte sonuç resim açıklamasını buraya girin

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.