matplotlibで密度で色分けされた散布図を作成するにはどうすればよいですか?


82

各ポイントが近くのポイントの空間密度によって色付けされている散布図を作成したいと思います。

私は非常によく似た質問に出くわしました。これは、Rを使用したこの例を示しています。

R散布図:シンボルの色は重なり合う点の数を表します

matplotlibを使用してPythonで同様のことを達成するための最良の方法は何ですか?


4
こんにちは!あなたが質問を書き直したり、文脈を与えたりしなかったためか、自分でそのことをしようとしたことを示さなかったためか、人々はあなたに反対票を投じてきました。質問を(リンクだけでなく)自給自足になるように編集することを検討してください。今後の質問については、投稿する前に試してみてください。
askewchan 2013年

回答:


157

@askewchanが提案したことに加えて、hist2dまたはhexbinそのように、リンクした質問で受け入れられた回答が使用するのと同じ方法を使用できます。

あなたがそれをしたい場合:

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
賢い、特に「最も密度の高い」ものを上に
置く

5
@ Leszek-Ether呼び出しplt.colorbar()、またはより明示的にしたい場合は、実行cax = ax.scatter(...)してからfig.colorbar(cax)。単位が異なることに注意してください。この方法では、ポイントの確率分布関数を推定するため、値は0から1の間になります(通常、1にあまり近づきません)。ヒストグラムカウントに近いものに戻すことはできますが、少し手間がかかります(gaussian_kdeデータから推定されたパラメーターを知る必要があります)。
ジョーキントン2014年

1
非常に素晴らしい!Pythonで他のKDEをチェックアウトすることも役立ちます:jakevdp.github.io/blog/2013/12/01/kernel-density-estimationおよびscikit-learn.org/stable/modules/density.html私の場合scipy.stats 「KDEは時間がかかりすぎた
REMS

1
ガウスカーネルが(xy)で2回呼び出されるのはなぜですか?
Arjan Groen 2017

@ArjanGroen最初の呼び出しは新しいgaussian_kdeオブジェクトを作成し、2番目の呼び出しはポイントのセットで推定されたpdfを評価します(evaluateメソッドを呼び出すためのショートカット)。
qRTPCR 2017年

34

ヒストグラムを作成できます。

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


26

また、ポイントの数によってKDEの計算が遅くなりすぎる場合は、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] )


これは素晴らしいヒントです、ありがとう。私は100kポイントをプロットしていましたが、gaussian_kdeは非常に低速でした。
エマニュエル

2
警告、これがNaNを生成する場合があり、「bounds_error = False」であるため、サイレントであることに気付きました。cがNaNに設定されているポイントはプロットされません。これはgaussian_kdeの問題ではありません。
エマニュエル

この回答に感謝します。通常、データポイントが多数ある場合は、このようなヒートマップが必要です。この場合、KDEは非常に低速です。ただし、未解決の問題がまだあります。頻度を示すカラーバーを入れたい!これはエラーをスローします: 'AxesSubplot'オブジェクトには属性 'autoscale_None'がありません。私は"plt.colorbar(スキャット、AX =斧)"やった
あるVinod Kumar氏

@VinodKumarカラーバーをプロットする方法を見つけましたか?
ダニエル

1
@Danielはい、これは可能です。編集された回答を参照してください。次に、ヒストグラムを作成するときに「density = True」を設定する必要があります。そうしないと、カラーバーはビンのサイズによって異なります。@ Emanuel、確かに!すべてのポイントを確実にプロットするために、NaNをゼロに置き換えました(NaNはデータが少ないときに発生するため、0.0で十分です)
ギヨーム

4

10万を超えるデータポイントをプロットしますか?

受け入れ答え、使用してgaussian_kdeを()に多くの時間がかかります。私のマシンでは、100k行に約11分かかりました。ここでは、2つの代替方法(mpl-scatter-densitydatashader)を追加し、指定された回答を同じデータセットと比較します。

以下では、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-scatter-densityを使用する

そして、ズームインは非常に見栄えがします。 mpl-scatter-densityを拡大します

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-scatter-densityまたはdatashaderの場合ほど見栄えがよくありません。また、ビンの数を自分で決定する必要があります。

hist2d1000binsにズームイン

5: density_scatter

  • コードは答えのとおりですによってギヨーム
  • bins =(50,50)でこれを描画するのに0.073秒かかりました: density_scatter_50bins
  • bins =(1000,1000)でこれを描画するのに0.368秒かかりました: density_scatter_1000bins
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.