各ポイントが近くのポイントの空間密度によって色付けされている散布図を作成したいと思います。
私は非常によく似た質問に出くわしました。これは、Rを使用したこの例を示しています。
matplotlibを使用してPythonで同様のことを達成するための最良の方法は何ですか?
各ポイントが近くのポイントの空間密度によって色付けされている散布図を作成したいと思います。
私は非常によく似た質問に出くわしました。これは、Rを使用したこの例を示しています。
matplotlibを使用してPythonで同様のことを達成するための最良の方法は何ですか?
回答:
@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()
plt.colorbar()
、またはより明示的にしたい場合は、実行cax = ax.scatter(...)
してからfig.colorbar(cax)
。単位が異なることに注意してください。この方法では、ポイントの確率分布関数を推定するため、値は0から1の間になります(通常、1にあまり近づきません)。ヒストグラムカウントに近いものに戻すことはできますが、少し手間がかかります(gaussian_kde
データから推定されたパラメーターを知る必要があります)。
また、ポイントの数によって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] )
受け入れ答え、使用してgaussian_kdeを()に多くの時間がかかります。私のマシンでは、100k行に約11分かかりました。ここでは、2つの代替方法(mpl-scatter-densityとdatashader)を追加し、指定された回答を同じデータセットと比較します。
以下では、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()
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()
ズームした画像は見栄えがします!
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='')
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)
5: density_scatter