大家好,我是云朵君!我们一起来看看这么精彩的可视化图表是如何绘制出来的。
首先定义出图中随机曲线的绘图函数。
# Some nice but random curves
def curve():
n = np.random.randint(1, 5)
centers = np.random.normal(0.0, 1.0, n)
widths = np.random.uniform(5.0, 50.0, n)
widths = 10 * widths / widths.sum()
scales = np.random.uniform(0.1, 1.0, n)
scales /= scales.sum()
X = np.zeros(500)
x = np.linspace(-3, 3, len(X))
for center, width, scale in zip(centers, widths, scales):
X = X + scale * np.exp(-(x - center) * (x - center) * width)
return X
将比较抽象的曲线函数可视化,更加直观。
np.random.seed(123)
# 获取曲线数据
Y = curve()
X = np.linspace(-3, 3, len(Y))
# 画布准备
fig = plt.figure(figsize=(10, 6),dpi=600)
# 设置画布
ax = plt.subplot(1, 1, 1, frameon=False, sharex=ax)
# 绘制曲线
ax.plot(X, 3 * Y, color="k",
linewidth=0.75, zorder=100)
plt.show()
由于该函数的随机性,每次运行都会给出不同的结果:
填充颜色、设置坐标轴及坐标轴标签。这里重点是颜色填充函数:Axes.fill_between()
Axes.fill_between(self, x, y1, y2=0, where=None,
interpolate=False, step=None,
*, data=None, **kwargs)
参数:
参数 y1
和 y2
可以是标量,表示给定y
值处的水平边界。只要 y1
给出, y2
默认为0。
ax1.fill_between(X, Y, color=color[0])
ax2.fill_between(X, Y, 1, color=color[1])
ax3.fill_between(X, Y, Y2, color=color[2])
一个常见的应用 fill_between
是置信带的指示。
当 fill_between
使用填充颜色填充某个区域时,这些颜色可能有点强,以至于宣兵夺主。我们希望淡化填充区域而突出主体。因此设置参数alpha
的值,以达到减淡颜色,使该区域半透明的目的。
y_err = X.std() * np.sqrt(1/len(X) + (X - X.mean())**2 / np.sum((X - X.mean())**2))
ax.fill_between(X, 3*Y - y_err, 3*Y + y_err,
alpha=0.2, color=cmap(0.3))
参数where
允许指定要填充的 x 范围。它是一个与x大小相同的布尔数组。
仅填充连续 True 序列的x范围。因此,相邻的 True 和 False 值之间的范围永远不会被填满。当数据点应该表示一个连续的量时,通常不希望出现这种情况。因此,建议设置 interpolate=True
,除非数据点的x距离足够细,使上述效果不明显。插值近似于实际的x位置,在那里 where 条件将改变,并扩展填充到那里。
ax1.fill_between(x01, y01, y02, where=(y01 > y02), color='C0', alpha=0.3)
ax1.fill_between(x01, y01, y02,where=(y01 < y02), color='C1', alpha=0.3)
ax2.fill_between(x01, y01, y02, where=(y01 > y02), color='C0', alpha=0.3,
interpolate=True)
ax2.fill_between(x01, y01, y02, where=(y01 <= y02), color='C1', alpha=0.3,
interpolate=True)
同样的选择机制可以应用于填满坐标轴的全部垂直高度。为了不受y极限的影响,我们添加了一个转换来解释数据坐标中的x值和坐标轴坐标中的y值。
下面的示例标记y数据高于给定阈值的区域。
threshold = 0.4
ax.axhline(threshold, color=cmap(0.2),
lw=2, alpha=0.7,linestyle='-.')
ax.fill_between(X, 0, 1, where= 3*Y > threshold,
color=cmap(0.5),
alpha=0.5,
transform=ax.get_xaxis_transform())
# 画布准备
cmap = mpl.cm.get_cmap("Spectral")
color = cmap(0)
ax.fill_between(X, 3 * Y, 0, color=color, zorder=100)
ax.yaxis.set_tick_params(tick1On=False)
ax.set_xlim(-3, 3)
ax.set_ylim(-1, 4)
ax.axvline(0.0, ls="--", lw=0.75, color="black", zorder=250)
ax.text(
0.0, 1.0,
"Value %d" % 1,
ha="left", va="top",
weight="bold", size=15,
transform=ax.transAxes,)
ax.yaxis.set_tick_params(labelleft=True)
ax.set_yticks(np.arange(1))
ax.set_yticklabels(["Serie %d" % i for i in range(1, 2)])
for tick in ax.yaxis.get_major_ticks():
tick.label.set_fontsize(15)
tick.label.set_verticalalignment("bottom") # 垂直对齐
plt.show()
zorder 用来控制绘图顺序,其值越大,画上去越晚,线条的叠加就是在上面的。对 plotting 方法的任何调用都可以显式地为该特定项的 zorder 设置值。许多创建可见对象的函数都接受 zorder
参数。或者可以在绘图后调用 set_order()
函数作用在创建的对象上。
接下来开始绘制开篇的这个图,我们发现每条曲线都部分地覆盖了其他曲线,因此为每条曲线设置适当的zorder是很重要的,这样渲染将独立于绘制顺序。
通过横向及纵向循环绘制多个图形,这里注意设置叠放次序参数zorder
,最下面的在最上面,然后依次叠放。
rows, cols = 3, 4
ax = None
for n in range(rows):
# 设置多子图
ax = plt.subplot(1, rows, n + 1, frameon=False, sharex=ax)
for i in range(cols):
Y = curve()
X = np.linspace(-3, 3, len(Y))
ax.plot(X, 3 * Y + i, color="k", linewidth=0.75, zorder=100 - i)
color = cmap(i / cols)
ax.fill_between(X, 3 * Y + i, i, color=color, zorder=100 - i)
最后多次循环,可以得到下图。
参考资料
Scientific Visualisation-Python & Matplotlib Python数据科学手册