python - قم بإنشاء مخطط heatmap في MatPlotLib باستخدام مجموعة بيانات مبعثرة




histogram2d (6)

لدي مجموعة من نقاط بيانات X ، Y (حوالي 10 كيلو بايت) يسهل رسمها كمؤامرة مبعثرة ولكن أود أن أمثلها كخريطة للحرارة.

نظرت من خلال الأمثلة في MatPlotLib ويبدو أنها جميعا بدأت بالفعل مع قيم خلية heatmap لتوليد الصورة.

هل هناك طريقة لتحويل مجموعة من x ، y ، كل شيء مختلف ، إلى خريطة حرارية (حيث تكون المناطق ذات تردد أعلى من x ، y "warmer")؟


أنا أعلم أن هذا سؤال قديم ، لكنه أراد إضافة شيء إلى Anjandro's anwser: إذا كنت ترغب في الحصول على صورة سلسة لطيفة دون استخدام py-sphviewer ، يمكنك بدلاً من ذلك استخدام np.histogram2d وتطبيق مرشح scipy.ndimage.filters (من scipy.ndimage.filters ) إلى خريطة التمثيل:

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()

ينتج عنه:


أنشئ صفيفًا ثنائي الأبعاد يتوافق مع الخلايا في صورتك النهائية ، ويُطلق عليها اسم heatmap_cells هيئة جميع الأصفار.

اختر اثنين من عوامل القياس التي تحدد الفرق بين كل عنصر صفيف في وحدات حقيقية ، لكل بعد ، x_scale و y_scale . اختر هذه بحيث تسقط جميع نقاط البيانات الخاصة بك ضمن حدود مصفوفة heatmap.

لكل datapoint خام بـ x_value و y_value :

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


فبدلاً من استخدام np.hist2d ، التي تنتج بشكل عام رسمًا بيانيًا قبيحًا تمامًا ، أود إعادة تدوير py-sphviewer ، حزمة python لتقديم محاكاة الجسيمات باستخدام نواة تنعيم قابلة للتكيف والتي يمكن تثبيتها بسهولة من نقطة (انظر وثائق صفحة الويب). خذ بعين الاعتبار التعليمة البرمجية التالية ، والتي تستند إلى المثال:

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()

والتي تنتج الصورة التالية:

كما ترون ، تبدو الصور جميلة ، ونحن قادرون على تحديد البنية التحتية المختلفة عليها. يتم إنشاء هذه الصور بنشر وزن معين لكل نقطة داخل نطاق معين ، يتم تحديدها بطول التجانس ، والذي يتم تحديده من خلال المسافة إلى الجار القريب من nb (لقد اخترت 16 و 32 و 64 للأمثلة). لذلك ، فإن المناطق ذات الكثافة العالية عادة ما تنتشر على مناطق أصغر مقارنة بالمناطق الأقل كثافة.

وظيفة myplot هي مجرد وظيفة بسيطة جدا لقد كتبت من أجل إعطاء البيانات س ، ص ل py-sphviewer للقيام السحر.


في قاموس Matplotlib ، أعتقد أنك تريد مؤامرة هيكسبين .

إذا لم تكن على دراية بهذا النوع من المؤامرة ، فهذا مجرد رسم بياني ثنائي متغيّر يتم فيه تمييز المستوى xy بواسطة شبكة منتظمة من السداسيات.

من خلال المدرج التكراري ، يمكنك فقط حساب عدد النقاط التي تقع في كل مسدس ، وتخصيص منطقة التآمر كمجموعة من النوافذ ، وتخصيص كل نقطة إلى واحدة من هذه النوافذ ؛ وأخيرًا ، قم بتعيين الإطارات على صفيف ألوان ، ولديك رسم تخطيطي سداسي.

على الرغم من الاستخدام الأقل شيوعًا ، على سبيل المثال ، الدوائر ، أو المربعات ، يعتبر هذا السداسي الاختيار الأفضل لهندسة حاوية binning أمرًا بديهيًا:

  • تحتوي الأشكال السداسية على تناظر أقرب إلى الجار (على سبيل المثال ، لا تحتوي صناديق مربعة ، على سبيل المثال ، المسافة من نقطة على حدود مربع إلى نقطة داخل تلك الساحة ليست متساوية)

  • السداسي هو أعلى ن- مضلع يعطي طبقة أرضية منتظمة (أي يمكنك إعادة تصميم أرضية المطبخ بأرضية سداسية الشكل لأنك لن يكون لديك فراغ باطني بين البلاط عند الانتهاء - وليس صحيحًا جميع الأخرى أعلى ن ، ن> = 7 ، والمضلعات).

(يستخدم Matplotlib مصطلح hexbin plot ؛ هكذا تفعل (AFAIK) جميع مكتبات التآمر لـ R ؛ ما زلت لا أعرف ما إذا كان هذا هو المصطلح المقبول بشكل عام لمؤامرات من هذا النوع ، على الرغم من أنني أشك في أنه من المرجح أن يكون hexbin قصيرًا ل binning سداسية ، الذي يصف الخطوة الأساسية في إعداد البيانات للعرض.)

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()   


وكان السؤال الأولي ... كيفية تحويل القيم مبعثر لقيم الشبكة ، أليس كذلك؟ لا يحسب histogram2d التكرار لكل خلية ، ومع ذلك ، إذا كان لديك بيانات أخرى لكل خلية من التردد فقط ، فستحتاج إلى بعض العمل الإضافي للقيام به.

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

نعم هنا يصبح أكثر صعوبة ولكن أكثر متعة. بعض المكتبات (آسف):

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

pyplot هو محرك الرسومات الخاص بي اليوم ، cm هو مجموعة من الخرائط الملونة مع بعض خيار initeresting. وردم للحسابات ، و griddata لإرفاق قيم بشبكة ثابتة.

آخر واحد مهم خاصة لأن تواتر xy نقاط ليست موزعة بالتساوي في بياناتي. أولاً ، لنبدأ ببعض الحدود الملائمة لبياناتي وحجم الشبكة العشوائية.

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

في بياناتي ، هناك أكثر من 500 قيمة لهذه الشبكة في مجال الاهتمام العالي ؛ بينما في المنطقة ذات الفائدة المنخفضة ، يوجد بحد أقصى 200 قيمة في الشبكة الإجمالية ؛ بين حدود الرسم من x_min و x_max هناك أقل من ذلك.

أنا أعرف شبكتي الآن. لكل زوج xx-yy ، أريد أن أحصل على لون.

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

لماذا هذا الشكل الغريب؟ scipy.griddata يريد شكل (n، D).

Griddata بحساب قيمة واحدة لكل نقطة في الشبكة ، بطريقة محددة مسبقًا. اخترت "أقرب" - سيتم ملء نقاط الشبكة فارغة مع القيم من أقرب الجيران. هذا يبدو كما لو أن المناطق ذات المعلومات الأقل تحتوي على خلايا أكبر (حتى لو لم تكن الحالة). يمكن للمرء أن يختار استقراء "خطي" ، ثم المناطق ذات المعلومات الأقل تبدو أقل حدة. مسألة الذوق ، حقا.

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])

والقفز ، نسلم إلى matplotlib لعرض المؤامرة

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-Shape ، ترى أن لدي الكثير من الحسابات أثناء البحث عن البقعة الحلوة ، في حين أن الأجزاء الأقل إثارة للاهتمام في كل مكان آخر لديها دقة أقل.


إذا كنت لا تريد سداسيات ، يمكنك استخدام الدالة histogram2d في numpy:

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()

هذا يجعل 50m50 heatmap. إذا كنت تريد ، على سبيل المثال ، 512 × 384 ، يمكنك وضع bins=(512, 384) في استدعاء histogram2d .

مثال:





histogram2d