使用 Seaborn kdeplot 对数刻度
Log scales with Seaborn kdeplot
我正在尝试使用 Seaborn 的 kdeplot 制作一个漂亮的自由能表面(热图)。
我非常接近但无法想出改变颜色条比例的方法。颜色条比例很重要,因为它应该代表地图上不同坐标处的能量差异。我需要知道如何按 -(0.5961573)*log(x)
缩放颜色条的值,其中 x
是颜色条的值。然后我可能还需要从那里标准化颜色条,以便最大值为 0。
这是我目前拥有的:
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.pyplot as plt
import seaborn as sns
rs=[]
dihes=[]
with open(sys.argv[1], 'r') as f:
for line in f:
time,r,dihe = line.split()
rs.append(float(r))
dihes.append(float(dihe))
sns.set_style("white")
sns.kdeplot(rs, dihes, n_levels=25, cbar=True, cmap="Purples_d")
plt.show()
这让我:
数组 rs 和 dihes 是简单的一维数组。
任何关于如何缩放颜色条(z 轴)的建议都会非常有帮助!
一种方法是手动创建图表,然后直接修改标签。这涉及多行代码。您可能需要稍微调整一下格式,但像这样的操作应该会让您走上正轨。
以下内容改编自 and this answer.
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
import seaborn as sns
from scipy import stats
rs=[]
dihes=[]
with open(sys.argv[1], 'r') as f:
for line in f:
time,r,dihe = line.split()
rs.append(float(r))
dihes.append(float(dihe))
x = rs
y = dihes
kde = stats.gaussian_kde([x, y])
xx, yy = np.mgrid[min(x):max(x):(max(x)-min(x))/100, min(y):max(y):(max(y)-min(y))/100]
density = kde(np.c_[xx.flat, yy.flat].T).reshape(xx.shape)
sns.set_style("white")
fig, ax = plt.subplots()
cset = ax.contour(xx, yy, density, 25, cmap="Purples_r")
cb = fig.colorbar(cset)
cb.ax.set_yticklabels(map(lambda x: -0.5961573*np.log(float(x.get_text())),
cb.ax.get_yticklabels()))
派对有点晚了,但我最终将这个上下文管理器放在一起,它将绘制的密度值切换为对数刻度:
import contextlib
import seaborn as sns
@contextlib.contextmanager
def plot_kde_as_log(base=np.exp(1), support_threshold=1e-4):
"""Context manager to render density estimates on a logarithmic scale.
Usage:
with plot_kde_as_log():
sns.jointplot(x='x', y='y', data=df, kind='kde')
"""
old_stats = sns.distributions._has_statsmodels
old_univar = sns.distributions._scipy_univariate_kde
old_bivar = sns.distributions._scipy_bivariate_kde
sns.distributions._has_statsmodels = False
def log_clip_fn(v):
v = np.log(np.clip(v, support_threshold, np.inf))
v -= np.log(support_threshold)
v /= np.log(base)
return v
def new_univar(*args, **kwargs):
x, y = old_univar(*args, **kwargs)
y = log_clip_fn(y)
return x, y
def new_bivar(*args, **kwargs):
x, y, z = old_bivar(*args, **kwargs)
z = log_clip_fn(z)
return x, y, z
sns.distributions._scipy_univariate_kde = new_univar
sns.distributions._scipy_bivariate_kde = new_bivar
try:
yield
finally:
sns.distributions._has_statsmodels = old_stats
sns.distributions._scipy_univariate_kde = old_univar
sns.distributions._scipy_bivariate_kde = old_bivar
这种方法的好处是它保留了 sns.jointplot()
的所有样式和其他选项,而无需任何额外的努力。
我更新了 上下文管理器以使用较新版本的 seaborn
@contextlib.contextmanager
def plot_kde_as_log(base=np.exp(1), support_threshold=1e-4):
"""Context manager to render density estimates on a logarithmic scale.
Usage:
with plot_kde_as_log():
sns.jointplot(x='x', y='y', data=df, kind='kde')
"""
old_call = sns._statistics.KDE.__call__
def log_clip_fn(v):
v = np.log(np.clip(v, support_threshold, np.inf))
v -= np.log(support_threshold)
v /= np.log(base)
return v
def new_call(*args, **kwargs):
density, support = old_call(*args, **kwargs)
density = log_clip_fn(density)
return density, support
sns._statistics.KDE.__call__ = new_call
try:
yield
finally:
sns._statistics.KDE.__call__ = old_call
我正在尝试使用 Seaborn 的 kdeplot 制作一个漂亮的自由能表面(热图)。
我非常接近但无法想出改变颜色条比例的方法。颜色条比例很重要,因为它应该代表地图上不同坐标处的能量差异。我需要知道如何按 -(0.5961573)*log(x)
缩放颜色条的值,其中 x
是颜色条的值。然后我可能还需要从那里标准化颜色条,以便最大值为 0。
这是我目前拥有的:
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.pyplot as plt
import seaborn as sns
rs=[]
dihes=[]
with open(sys.argv[1], 'r') as f:
for line in f:
time,r,dihe = line.split()
rs.append(float(r))
dihes.append(float(dihe))
sns.set_style("white")
sns.kdeplot(rs, dihes, n_levels=25, cbar=True, cmap="Purples_d")
plt.show()
这让我:
数组 rs 和 dihes 是简单的一维数组。
任何关于如何缩放颜色条(z 轴)的建议都会非常有帮助!
一种方法是手动创建图表,然后直接修改标签。这涉及多行代码。您可能需要稍微调整一下格式,但像这样的操作应该会让您走上正轨。
以下内容改编自
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
import seaborn as sns
from scipy import stats
rs=[]
dihes=[]
with open(sys.argv[1], 'r') as f:
for line in f:
time,r,dihe = line.split()
rs.append(float(r))
dihes.append(float(dihe))
x = rs
y = dihes
kde = stats.gaussian_kde([x, y])
xx, yy = np.mgrid[min(x):max(x):(max(x)-min(x))/100, min(y):max(y):(max(y)-min(y))/100]
density = kde(np.c_[xx.flat, yy.flat].T).reshape(xx.shape)
sns.set_style("white")
fig, ax = plt.subplots()
cset = ax.contour(xx, yy, density, 25, cmap="Purples_r")
cb = fig.colorbar(cset)
cb.ax.set_yticklabels(map(lambda x: -0.5961573*np.log(float(x.get_text())),
cb.ax.get_yticklabels()))
派对有点晚了,但我最终将这个上下文管理器放在一起,它将绘制的密度值切换为对数刻度:
import contextlib
import seaborn as sns
@contextlib.contextmanager
def plot_kde_as_log(base=np.exp(1), support_threshold=1e-4):
"""Context manager to render density estimates on a logarithmic scale.
Usage:
with plot_kde_as_log():
sns.jointplot(x='x', y='y', data=df, kind='kde')
"""
old_stats = sns.distributions._has_statsmodels
old_univar = sns.distributions._scipy_univariate_kde
old_bivar = sns.distributions._scipy_bivariate_kde
sns.distributions._has_statsmodels = False
def log_clip_fn(v):
v = np.log(np.clip(v, support_threshold, np.inf))
v -= np.log(support_threshold)
v /= np.log(base)
return v
def new_univar(*args, **kwargs):
x, y = old_univar(*args, **kwargs)
y = log_clip_fn(y)
return x, y
def new_bivar(*args, **kwargs):
x, y, z = old_bivar(*args, **kwargs)
z = log_clip_fn(z)
return x, y, z
sns.distributions._scipy_univariate_kde = new_univar
sns.distributions._scipy_bivariate_kde = new_bivar
try:
yield
finally:
sns.distributions._has_statsmodels = old_stats
sns.distributions._scipy_univariate_kde = old_univar
sns.distributions._scipy_bivariate_kde = old_bivar
这种方法的好处是它保留了 sns.jointplot()
的所有样式和其他选项,而无需任何额外的努力。
我更新了
@contextlib.contextmanager
def plot_kde_as_log(base=np.exp(1), support_threshold=1e-4):
"""Context manager to render density estimates on a logarithmic scale.
Usage:
with plot_kde_as_log():
sns.jointplot(x='x', y='y', data=df, kind='kde')
"""
old_call = sns._statistics.KDE.__call__
def log_clip_fn(v):
v = np.log(np.clip(v, support_threshold, np.inf))
v -= np.log(support_threshold)
v /= np.log(base)
return v
def new_call(*args, **kwargs):
density, support = old_call(*args, **kwargs)
density = log_clip_fn(density)
return density, support
sns._statistics.KDE.__call__ = new_call
try:
yield
finally:
sns._statistics.KDE.__call__ = old_call