Matplotlib ilə visualization
Matplotlib ilə visualization
Əvvəlki iki fəsildə data-nı pandas ilə yükləməyi, təmizləməyi və formalaşdırmağı öyrəndik. İndi ona baxmaq vaxtıdır. Visualization analizin sonunda hesabatı bəzəyən addım deyil, analizin özüdür: cədvəldə görünməyən outlier, iki dəyişən arasındakı qeyri-xətti əlaqə, mövsümi pattern — bunlar əvvəlcə qrafikdə görünür, sonra ədədlə təsdiqlənir. Yaxşı qrafik encoding məsələsidir: data-nın hansı xassəsi mövqeyə, hansı rəngə, hansı ölçüyə çevrilir. Matplotlib bu encoding-i tam nəzarətdə saxlayan aşağı səviyyəli alətdir və Python ekosistemindəki demək olar bütün digər kitabxanalar onun üzərində qurulub. Bu fəsil Matplotlib-in modelini və ən çox lazım olan qrafik növlərini, sonda isə Seaborn-u yüksək səviyyəli qat kimi təqdim edir.
İki interface: plt və ax
Matplotlib-in iki üslubu var və ikisini qarışdırmaq başlanğıcda ən çox çaşdıran şeydir. MATLAB-style interface plt modulu üzərindən işləyir və state machine-dir: "cari figure" və "cari axes" anlayışı var, hər plt.plot çağırışı cari axes-ə çəkir.
plt.figure()
plt.plot(x, np.sin(x))
plt.xlabel("x")
plt.title("sin")
Object-oriented interface isə figure və axes obyektlərini açıq saxlayır və metodları birbaşa onlara çağırır:
fig, ax = plt.subplots()
ax.plot(x, np.sin(x))
ax.set(xlabel="x", title="sin")
Figure kətandır, bütün qrafikin konteyneri; Axes onun içində bir koordinat sistemi, yəni bir "qrafik". Tək və tez qrafik üçün plt üslubu kifayətdir. Bir neçə subplot, təkrar istifadə olunan funksiyalar və ya qrafik üzərində dəqiq nəzarət lazım olanda object-oriented üslub seçin: hansı axes-ə çəkdiyiniz həmişə açıq olur. Metod adları fərqlənir (plt.xlabel → ax.set_xlabel), amma ax.set bir çağırışla bir neçə xassəni qurur. Faylı fig.savefig("plot.png", dpi=150) ilə saxlayırsınız; uzantı formatı müəyyən edir (png, pdf, svg), dpi isə raster formatlarda keyfiyyəti. Məqalə və slayd üçün vektorlu pdf/svg, veb üçün png uyğundur.
Line və scatter plot-lar
Line plot davamlı dəyişənin bir ölçü üzrə necə dəyişdiyini göstərir və ən çox vaxt data-sı üçün istifadə olunur. color (ad, hex, və ya RGB tuple), linestyle (-, --, :, -.) və linewidth əsas parametrlərdir; ax.set_xlim/set_ylim və ya ax.axis("tight") oxların aralığını idarə edir; ax.set(xlim=..., ylim=..., xlabel=..., ylabel=..., title=...) hamısını bir yerdə yığır. Oxlara ad və vahid yazmağı heç vaxt atlamayın; adsız ox oxucudan daha çox sizin özünüzü çaşdıracaq.
Scatter plot iki dəyişənin əlaqəsini göstərir və iki yolu var. ax.plot(x, y, "o") hər nöqtəni eyni marker ilə çəkir, sürətlidir və nöqtələr bir-birinə bənzəyəndə bəs edir. ax.scatter isə hər nöqtənin ölçüsünü və rəngini ayrıca təyin etməyə imkan verir, yəni iki əlavə dəyişəni encode edir:
ax.scatter(df.height, df.weight, c=df.age, s=df.income / 500,
cmap="viridis", alpha=0.5)
fig.colorbar(ax.collections[0], label="age")
Qiymət budur: scatter hər nöqtəni ayrıca render etdiyi üçün on minlərlə nöqtədə plot-dan nəzərəçarpacaq dərəcədə yavaşdır. Böyük data-da ya plot istifadə edin, ya aşağıda baxacağımız 2D histogram-a keçin.
Səhvləri göstərmək
Ölçmənin qeyri-müəyyənliyi olmayan qrafik yarımçıqdır. Diskret nöqtələr üçün errorbar hər nöqtəyə ±σ xətti əlavə edir: ax.errorbar(x, y, yerr=dy, fmt="o", ecolor="gray", capsize=3). Davamlı proqnoz (məsələn, Gaussian process və ya regression əyrisi) üçün isə fill_between iki əyri arasını rəngləyir:
ax.plot(x, y_pred, "-", color="C0")
ax.fill_between(x, y_pred - 2*std, y_pred + 2*std, color="C0", alpha=0.2)
Şəffaf zolaq göz üçün intuitiv "etibarlılıq koridoru"dur və nöqtələrdən daha çox danışır.
Sıxlıq və contour plot-lar
Üç ölçülü funksiya z = f(x, y) iki ölçülü səthdə üç yolla göstərilir. contour bərabər səviyyə xətlərini çəkir (xəritədəki hündürlük xətləri kimi); contourf səviyyələr arasını rənglə doldurur; imshow isə grid-i birbaşa şəkil kimi göstərir. imshow üçün origin="lower" (default şəkil koordinatı yuxarıdan başlayır) və extent=[xmin, xmax, ymin, ymax] (əks halda ox piksel nömrələrini göstərir) parametrlərini unutmayın. Hər üçündə rəng kəmiyyəti encode etdiyi üçün colorbar məcburidir: fig.colorbar(im). Colorbar-sız rəng xəritəsi oxucuya "burası qırmızıdır" deməkdən çox şey demir.
Histogram və binning
Histogram tək dəyişənin paylanmasını göstərir və analizin ilk addımıdır. ax.hist(data, bins=30, density=True, alpha=0.5, histtype="stepfilled") ən çox işlənən formadır: bins sayı paylanmanın formasını ciddi dəyişir, bir neçə dəyər sınayın; density=True sahəni 1-ə normallaşdırır və fərqli ölçülü nümunələri müqayisə etməyə imkan verir; alpha üst-üstə düşən bir neçə histogram-ı oxunan edir. Yalnız sayları, qrafiksiz istəyirsinizsə, np.histogram eyni işi görür.
İki dəyişənin birgə paylanması üçün scatter nöqtələr sıxlaşanda faydasız olur. hist2d düzbucaqlı, hexbin altıbucaqlı bin-lərlə sıxlığı rəngə çevirir və yüz minlərlə nöqtəni bir anda render edir. Hamar alternativ kernel density estimation-dır: hər nöqtənin üzərinə kiçik Gaussian qoyub cəmləyir; scipy.stats.gaussian_kde bunu hesablayır, nəticəni imshow və ya contourf ilə göstərirsiniz. KDE-nin bandwidth parametri histogram-ın bin eni kimi formaya təsir edir.
Legend və colorbar-ı tənzimləmək
Legend hansı xəttin nə olduğunu deyir və ax.legend() label= verilmiş hər elementi avtomatik toplayır. loc="upper left", frameon=False, ncol=2 tez-tez lazım olan parametrlərdir. Legend-ə hansı elementlərin düşəcəyini idarə etməyin iki yolu var: label-i olmayan elementlər avtomatik çıxarılır, yaxud ax.legend(lines[:2], ["a", "b"]) ilə açıq siyahı verirsiniz. Bir axes-də iki legend lazım olanda (məsələn, biri xətlər, biri marker-lər üçün) ikinci legend çağırışı birincini silir; birincini ax.add_artist(leg1) ilə əl ilə qaytarırsınız.
Rəng və ya ölçü ilə kəmiyyət encode edəndə legend əvəzinə həmin ölçü üçün sütunlar çəkib label vermək kifayətdir: boş scatter-lər ax.scatter([], [], s=size, label=f"{size} km²") ilə yaradılır və legend onları göstərir. Bu, xəritə tipli qrafiklərdə ölçü şkalasını izah etməyin standart yoludur.
Colormap seçimi estetika deyil, düzgünlük məsələsidir. Üç ailə var:
| Ailə | Nümunə | Nə vaxt |
|---|---|---|
| sequential | viridis, Blues | sıralı kəmiyyət (temperatur, sıxlıq) |
| divergent | RdBu, PuOr | mənalı mərkəzi olan kəmiyyət (fərq, korrelyasiya) |
| qualitative | tab10, Set2 | sırasız kateqoriya |
Köhnə default jet pisdir, çünki parlaqlığı monoton deyil: orta dəyərlərdə parlaq sarı zolaq yaradır və olmayan sərhədlər göstərir; qara-ağ çapda tamamilə yöndəmsizdir. viridis kimi perceptually uniform xəritələrdə bərabər data fərqi bərabər görünən fərq verir. Rəng limitlərini vmin/vmax və ya im.set_clim(-1, 1) ilə təyin edin ki, bir neçə outlier bütün şkalanı sıxmasın; extend="both" colorbar-ın uclarında ox çəkib dəyərlərin kəsildiyini bildirir. Diskret səviyyələr üçün plt.get_cmap("Blues", 6) altı pilləli xəritə verir.
Bir neçə subplot
Müqayisə bir figure-də bir neçə axes tələb edir. fig.add_axes([left, bottom, width, height]) axes-i figure koordinatlarında (0–1) əl ilə yerləşdirir və inset üçün lazımdır. plt.subplot(2, 3, i) grid-də i-ci yeri seçir (nömrə 1-dən başlayır). Ən çox istifadə olunan isə hamısını bir dəfəyə yaradan plt.subplots-dur:
fig, axes = plt.subplots(2, 3, figsize=(10, 6), sharex=True, sharey=True)
for i, ax in enumerate(axes.flat):
ax.plot(x, np.sin(x + i))
ax.text(0.05, 0.9, f"shift={i}", transform=ax.transAxes)
sharex/sharey ox aralıqlarını bağlayır və daxili tick label-ləri silir, bu həm yer qazandırır, həm də müqayisəni dürüst edir. Qeyri-bərabər grid üçün GridSpec var: gs = fig.add_gridspec(2, 2), sonra fig.add_subplot(gs[0, :]) üst sıranı tam enində götürür. Scatter-in kənarında marginal histogram-lar bu yolla çəkilir.
Mətn, annotation və tick-lər
ax.text(x, y, "label") mətni yerləşdirir və burada transform anlayışı önəmlidir: ax.transData (default) data koordinatlarıdır, ax.transAxes axes-in 0–1 koordinatlarıdır, fig.transFigure isə figure-ün. Yuxarıdakı nümunədəki transform=ax.transAxes mətni data aralığından asılı olmayaraq sol üst küncdə saxlayır. annotate mətni oxla birləşdirir: ax.annotate("peak", xy=(x0, y0), xytext=(x0+1, y0+5), arrowprops=dict(arrowstyle="->")). Qrafikdəki bir hadisəni izah etmək üçün bu, legend-dən daha güclüdür.
Hər oxun tick-lərini iki obyekt idarə edir: locator harada tick olacağını, formatter necə yazılacağını. ax.xaxis.set_major_locator(plt.MaxNLocator(4)) tick sayını azaldır (sıx subplot-larda vacibdir); plt.NullLocator() tick-ləri tamamilə gizlədir (şəkillər üçün); plt.MultipleLocator(np.pi/2) π-nin qatlarında qoyur, plt.FuncFormatter isə onları π/2 kimi yazmağa imkan verir. Minor tick-lər və log oxlar (ax.set_xscale("log")) eyni mexanizmlə işləyir.
Matplotlib-i özünüzə uyğunlaşdırmaq
Hər qrafikdə eyni on parametri yazmaq əvəzinə rcParams vasitəsilə default-ları dəyişin: plt.rc("axes", grid=True, facecolor="#f5f5f5"), plt.rc("lines", linewidth=2). Hazır stylesheet-lər (plt.style.use("seaborn-v0_8-whitegrid"), "ggplot", "dark_background") bütün dəsti bir dəfəyə dəyişir, with plt.style.context(...) isə yalnız bir blok üçün. Komanda daxilində vahid görünüş üçün öz .mplstyle faylınızı yazıb paylaşa bilərsiniz.
Qısa qeyd: mpl_toolkits.mplot3d ilə ax = fig.add_subplot(projection="3d") 3D xətlər, scatter və səth çəkir, amma 3D qrafik kağızda demək olar həmişə pis oxunur; iki ölçüyə yığa bilirsinizsə (contour, kiçik subplot-lar), yığın. Coğrafi data üçün Matplotlib üzərində qurulan cartopy kimi kitabxanalar proyeksiya, sahil xətləri və sərhədləri əlavə edir; Matplotlib-i bildikdən sonra onları öyrənmək bir saatlıq işdir.
Seaborn: yüksək səviyyəli qat
Matplotlib hər şeyə nəzarət verir, amma statistik qrafikləri sıfırdan yığmaq zəhmətlidir. Seaborn Matplotlib-in üstündə DataFrame ilə birbaşa işləyən yüksək səviyyəli funksiyalar təqdim edir:
import seaborn as sns
sns.pairplot(iris, hue="species") # bütün cütlər
sns.histplot(data=tips, x="total_bill", hue="sex", kde=True)
sns.catplot(data=tips, x="day", y="total_bill", kind="box")
sns.jointplot(data=tips, x="total_bill", y="tip", kind="hex")
Pair plot dataset-in bütün ədədi sütun cütlərini bir grid-də göstərir və exploration-ın ilk beş dəqiqəsi üçün ən yaxşı alətdir. Faceted histogram (FacetGrid və ya displot(col=...)) bir qrafiki kateqoriya üzrə kiçik panellərə bölür. Categorical plot-lar (box, violin, strip) kateqoriyalar üzrə paylanmaları müqayisə edir. Joint distribution iki dəyişənin birgə və marginal paylanmasını bir yerdə göstərir. Qayda: exploration üçün Seaborn, çap üçün dəqiq tənzimləmə lazım olanda Matplotlib. Seaborn funksiyaları Matplotlib axes qaytarır, yəni ikisini qarışdırmaq olur: Seaborn ilə çəkin, Matplotlib ilə cilalayın.
Dürüst qrafik prinsipləri
Qrafik inandırıcıdır, və bu, onu təhlükəli edir. Bir neçə prinsip:
- Sıfır nöqtəsi. Bar chart-da y oxu sıfırdan başlamalıdır, çünki hündürlük kəmiyyəti encode edir; 10% fərqi 300% kimi göstərən kəsilmiş ox yalandır. Line plot-da kəsmək olar, amma aydın göstərin.
- Nəyi encode etdiyinizi seçin. Mövqe ən dəqiq oxunan kanaldır, sonra uzunluq, sonra rəng, ən sonda sahə. Ən vacib dəyişəni mövqeyə verin.
- Vahidlər və label-lər. Hər oxda ad və vahid, hər rəng şkalasında colorbar, hər çoxxətli qrafikdə legend.
- Görünən şeyi azaldın. Chart junk — 3D effekt, qradient, lazımsız grid — siqnalı boğur. Hər element bir məlumat daşımırsa, silin.
- Bir qrafik, bir mesaj. Qrafik bir suala cavab verməlidir. Dörd sual varsa, dörd subplot çəkin.
Tapşırıqlar
- Bir ilin gündəlik satış data-sını (əvvəlki fəsildəki time series bəs edər) object-oriented interface ilə çəkin: xam dəyərlər açıq rəngdə, 30 günlük rolling ortalama tünd xətlə, ən yüksək günü
annotateilə işarələyin, oxlara vahid yazın vəpdfkimi saxlayın. - Təsadüfi 100 000 nöqtəli iki ölçülü Gaussian qarışığı yaradın. Eyni data-nı
scatter,hist2d,hexbinvə KDE ilə 2×2 subplot grid-də göstərin; hər birinin render vaxtını ölçün və hansının hansı ölçüdə uyğun olduğunu yazın. - Korrelyasiya matrisini
imshowilə üç colormap-lə çəkin:jet,viridisvəRdBu(limitlər-1-dən1-ə). Hər birində hansı məlumatın itdiyini və ya yanlış vurğulandığını izah edin, sonra Seaborn-unheatmapfunksiyası ilə eyni qrafiki çəkib fərqi müqayisə edin.