这个示例使用随机生成的多个正态分布的数组和填充图案来绘制叠加到一起的阶梯形直方图的方法,以及把功能函数作为函数参数的方法。
在Matplotlib中可以用于填充到多边形中的图案用以下符号来表示:
hatches = [‘/’, ‘\\’, ‘|’, ‘-’, ‘+’, ‘x’, ‘o’, ‘O’, ‘.’, ‘*’],也可以使用这些符号的组合形式,如:
hatches = [‘//’, ‘\\’, ‘||’, ‘–’, ‘++’, ‘xx’, ‘oo’, ‘OO’, ‘…’, ‘**’]或
hatches = [‘/o’, ‘\|’, ‘|*’, ‘-\’, ‘+o’, ‘x*’, ‘o-’, ‘O|’, ‘O.’, ‘*-’]
同时也演示了在Python中,依据功能需要,编写实现功能需要的自定义函数的方法,以及使用try…catch和raise关键字进行异常处理的方法。
from functools import partial
import itertools
from cycler import cycler
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.ticker as mticker
def filled_hist(ax, edges, values, bottoms=None, orientation='v',
**kwargs):
"""
自定义函数,绘制一个阶梯形的直方图。 参数说明 ---------- ax : Axes 指定绘制图形所用的坐标系统对象 edges : array 一个长度为n+1的数组,指定所有箱体图形的左边界,以及最后一个箱体图形的右边界。 values : array 一个长度为n的数组,指定箱体图形的数量 bottoms : float or array, optional 一个长度为n的数组,指定箱体图的底部坐标,如果没有指定,则默认的底部坐标为0 orientation : {'v', 'h'} 指定直方图的绘制方向,v:表示垂直方向;h:表示水平方向 **kwargs 这是一个扩展样式关键字参数,用于指定传递给fill_between或fill_betweenx函数的样式参数。 Returns ------- ret : 图形集合 这个图形结合表示被添加到坐标系中的图形。 """
# 判断图形的绘制方向,如果参数值错误,则触发错误异常。
if orientation not in 'hv':
raise ValueError(f"orientation must be in {{'h', 'v'}} "
f"not {orientation}")
# 设定采用阶梯形的样式来绘制图形
kwargs.setdefault('step', 'post')
# 设定图形的填充区域的透明度
kwargs.setdefault('alpha', 0.4)
# 把左右边界的坐标数组转换为Numpy数组
edges = np.asarray(edges)
# 把顶部坐标值数组转换为Numpy数组
values = np.asarray(values)
# 如果边界数与阶梯数不匹配,则触发异常处理,报告参数值错误
if len(edges) - 1 != len(values):
raise ValueError(f'Must provide one more bin edge than value not: '
f'{len(edges)=} {len(values)=}')
# 初始化图形的底部作为为0
if bottoms is None:
bottoms = 0
# 修改底部坐标数组的形状,使之与阶梯值数组的形状一致。
bottoms = np.broadcast_to(bottoms, values.shape)
# 设置一个顶部与底部坐标值相同的点,确保与阶梯形数组边界数一致。
values = np.append(values, values[-1])
bottoms = np.append(bottoms, bottoms[-1])
# 如果参数是h,则沿着水平方向填充
if orientation == 'h':
return ax.fill_betweenx(edges, values, bottoms,
**kwargs)
# 如果参数是h,则沿着垂直方向填充
elif orientation == 'v':
return ax.fill_between(edges, values, bottoms,
**kwargs)
# 否则触发异常
else:
raise AssertionError("you should never be here")
def stack_hist(ax, stacked_data, sty_cycle, bottoms=None,
hist_func=None, labels=None,
plot_func=None, plot_kwargs=None):
"""
这个方法用来堆积阶梯形直方图。 参数 ---------- ax : axes.Axes 绘制图形用的坐标系对象 stacked_data : array or Mapping 一个形状如A(M,N)的数组或映射,第一维度上的值被用于迭代计算直方图的台阶 sty_cycle : Cycler or operable of dict 指定绘制图形的样式 bottoms : array, default: 0 初始化图形的底部坐标,默认值为0 hist_func : callable, optional 指定生成绘制图形数据的功能函数,可选 这个参数所指定的功能函数必须形如:n_vals, bin_edges = f(data),而且bin_edges数组的长度要比bin_vals数组的长度大1 labels : list of str, optional 一个列表数组,可选。用于指定每组图形集的图例标签 默认值为default set {n},n表示图形集的数量 如果stacked_data参数是一个映射类型的,并且labels参数为None,则使用stacked_data参数的key做为标签 如果stacked_data是一个映射,而且给labels参数指定了参数值,则只绘制labels参数中指定的与stacked_data键名匹配的图形集 plot_func : callable, optional 指定绘制图形的功能函数,可选,但是其函数的定义形式必须为: ret = plot_func(ax, edges, top, bottoms=bottoms, label=label, **kwargs) plot_kwargs : dict, optional、 一个字典类型的参数,用于指定绘制图形的样式,它会覆盖参数sty_cycle中的值。 Returns ------- arts : dict 返回一个基于图例标签的图形集字典 """
# 如果没有指定生成绘制图形数据的功能函数,则使用Numpy库中默认的直方图函数
if hist_func is None:
hist_func = np.histogram
# 如果没有指定绘制图形的函数,则使用本文件中定义的绘制图形的函数
if plot_func is None:
plot_func = filled_hist
# 如果没有设置图形样式,则使用默认的样式
if plot_kwargs is None:
plot_kwargs = {}
try:
# 获取图形数据集中键名的集合
l_keys = stacked_data.keys()
label_data = True
# 如果函数参数中没有指定图例标签,就使用数据集的键名来做为图例标签
if labels is None:
labels = l_keys
# 取不到图例标签时,进行异常处理
except AttributeError:
label_data = False
# 使用迭代器生成标签
if labels is None:
labels = itertools.repeat(None)
# 有图例标签的情况下,
if label_data:
# 从绘图数据集中取出标签和样式,并将标签和样式迭代的装入迭代器中,
loop_iter = enumerate((stacked_data[lab], lab, s)
for lab, s in zip(labels, sty_cycle))
else:
# 没有图例标签的情况下,把绘图数据集与标签集合,以及样式装入迭代器中
loop_iter = enumerate(zip(stacked_data, labels, sty_cycle))
# 把绘制的图形集合初始化为空集
arts = {}
# 迭代绘制图形用的数据集,依次取出数据、标签和样式绘制图形
for j, (data, label, sty) in loop_iter:
# 没有图例的标签的情况下,自己设置一个默认标签
if label is None:
label = f'dflt set {j}'
# 从样式数据中获取标签
label = sty.pop('label', label)
# 生成绘图数据,包括一个头部坐标数组和一个边界坐标值数组
vals, edges = hist_func(data)
# 如果没有图形的底部坐标,则把图形的底部坐标值初始化为0
if bottoms is None:
bottoms = np.zeros_like(vals)
# 把底部坐标值加上头部坐标值,形成新的头部坐标值。
top = bottoms + vals
# 更新绘图样式
sty.update(plot_kwargs)
# 绘制图形
ret = plot_func(ax, edges, top, bottoms=bottoms,
label=label, **sty)
# 更新底部坐标值
bottoms = top
# 把绘制的图形添加到图形集字典里
arts[label] = ret
# 绘制图例
ax.legend(fontsize=10)
return arts
# 生成等距的直方图边界数组,边界坐标值在-3~3之间,边界数为20
edges = np.linspace(-3, 3, 20, endpoint=True)
# 绑定生成直方图数据的函数。
hist_func = partial(np.histogram, bins=edges)
# 循环初始化图形的样式
# 初始化颜色
color_cycle = cycler(facecolor=plt.rcParams['axes.prop_cycle'][:4])
# 初始化图例标签
label_cycle = cycler(label=[f'set {n}' for n in range(4)])
# 初始图形填充样式
hatch_cycle = cycler(hatch=['/', '*', '+', '|'])
# 初始化一个固定的可重复的随机数生成器
np.random.seed(19680801)
# 随机生成4组正态分布的整数数据。
stack_data = np.random.randn(4, 12250)
# 把图例标签与4组数据绑定,生成一个字典类型的图形数据集。
dict_data = dict(zip((c['label'] for c in label_cycle), stack_data))
"""
# 获取绘图画板和坐标系对象
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(9, 4.5), tight_layout=True)
# 调用自定义方法stack_hist函数,绘制4组叠加到一起的阶梯形直方图,并用指定的符号来填充图形区域
arts = stack_hist(ax1, stack_data, color_cycle + label_cycle + hatch_cycle,
hist_func=hist_func)
# 绘制一个横向的阶梯形直方图,叠加的直方图之间的边界线使用白色线条
arts = stack_hist(ax2, stack_data, color_cycle,
hist_func=hist_func, plot_kwargs=dict(edgecolor='w', orientation='h'))
ax1.set_ylabel('counts')
ax1.set_xlabel('x')
ax2.set_xlabel('counts')
ax2.set_ylabel('x')
"""
# 获取绘图画板和坐标系对象
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(9, 4.5),
tight_layout=True, sharey=True)
# 调用自定义方法stack_hist函数,绘制4组叠加到一起的阶梯形直方图,并用指定的符号来填充图形区域
arts = stack_hist(ax1, dict_data, color_cycle + hatch_cycle,
hist_func=hist_func)
# 调用自定义方法stack_hist函数,叠加绘制标签指定的直方图集合
arts1 = stack_hist(ax2, dict_data, color_cycle + hatch_cycle,
hist_func=hist_func, labels=['set 0','set 3'])
# 设置定位器的最大刻度
ax1.xaxis.set_major_locator(mticker.MaxNLocator(5))
ax1.set_xlabel('counts')
ax1.set_ylabel('x')
ax2.set_ylabel('x')
# 显示绘图结果
plt.show()
以上就是“Python绘制图形—绘制带有图案的直方图”的全部内容,希望对你有所帮助。