Python之Matplotlib文字与注释的使用方法
作者:ywsydwsbn 发布时间:2022-09-09 10:36:51
可视化对于大家来说确实是有关的,因为确实是直观的,每一组大数据如果可以用可视化进行展示的话可以让大家豁然开朗。但在另外一些场景中,辅之以少量的文字提示(textual cue)
和标签是必不可少的。虽然最基本的注释(annotation)
类型可能只是坐标轴标题与图标题,但注释可远远不止这些。让我们可视化一些数据,看看如何通过添加注释来更恰当地表达信息。
首先导入画图需要用到的一些函数:
import matplotlib.pyplot as plt
import matplotlib as mpl
plt.style.use('seaborn-whitegrid')
import numpy as np
import pandas as pd
1案例:节假日对美国出生率的影响
数据可以在 https://github.com/jakevdp/data-CDCbirths 下载,数据类型如下:
用清洗方法处理数据,然后画出结果。
日均出生人数统计图
births = pd.read_csv('births.csv')
quartiles = np.percentile(births['births'], [25, 50, 75])
mu, sig = quartiles[1], 0.74 * (quartiles[2] - quartiles[0])
births = births.query('(births > @mu - 5 * @sig) & (births < @mu + 5 * @sig)')
births['day'] = births['day'].astype(int)
births.index = pd.to_datetime(10000 * births.year + 100 * births.month + births.day, format='%Y%m%d')
births_by_date = births.pivot_table('births', [births.index.month, births.index.day])
births_by_date.index = [pd.datetime(2012, month, day) for (month, day) in births_by_date.index]
fig, ax = plt.subplots(figsize=(12, 4))
births_by_date.plot(ax=ax);
import matplotlib.pyplot as plt
import matplotlib as mpl
plt.style.use('seaborn-whitegrid')
import numpy as np
import pandas as pd
births = pd.read_csv('C:\\Users\\Y\\Desktop\\data-CDCbirths-master\\births.csv')
quartiles = np.percentile(births['births'], [25, 50, 75])
mu, sig = quartiles[1], 0.74 * (quartiles[2] - quartiles[0])
births = births.query('(births > @mu - 5 * @sig) & (births < @mu + 5 * @sig)')
births['day'] = births['day'].astype(int)
births.index = pd.to_datetime(10000 * births.year + 100 * births.month + births.day, format='%Y%m%d')
births_by_date = births.pivot_table('births', [births.index.month, births.index.day])
births_by_date.index = [pd.datetime(2012, month, day) for (month, day) in births_by_date.index]
fig, ax = plt.subplots(figsize=(12, 4))
births_by_date.plot(ax=ax);
plt.show()
为日均出生人数统计图添加注释
在用这样的图表达观点时,如果可以在图中增加一些注释,就更能吸引读者的注意了。可以通过 plt.text / ax.text
命令手动添加注释,它们可以在具体的 x / y 坐标点上放上文字
fig, ax = plt.subplots(figsize=(12, 4))
births_by_date.plot(ax=ax)
# 在图上增加文字标签
style = dict(size=10, color='gray')
ax.text('2012-1-1', 3950, "New Year's Day", **style)
ax.text('2012-7-4', 4250, "Independence Day", ha='center', **style)
ax.text('2012-9-4', 4850, "Labor Day", ha='center', **style)
ax.text('2012-10-31', 4600, "Halloween", ha='right', **style)
ax.text('2012-11-25', 4450, "Thanksgiving", ha='center', **style)
ax.text('2012-12-25', 3850, "Christmas ", ha='right', **style)
# 设置坐标轴标题
ax.set(title='USA births by day of year (1969-1988)',
ylabel='average daily births')
# 设置x轴刻度值,让月份居中显示
ax.xaxis.set_major_locator(mpl.dates.MonthLocator())
ax.xaxis.set_minor_locator(mpl.dates.MonthLocator(bymonthday=15))
ax.xaxis.set_major_formatter(plt.NullFormatter())
ax.xaxis.set_minor_formatter(mpl.dates.DateFormatter('%h'));
import matplotlib.pyplot as plt
import matplotlib as mpl
plt.style.use('seaborn-whitegrid')
import numpy as np
import pandas as pd
births = pd.read_csv('C:\\Users\\Y\\Desktop\\data-CDCbirths-master\\births.csv')
quartiles = np.percentile(births['births'], [25, 50, 75])
mu, sig = quartiles[1], 0.74 * (quartiles[2] - quartiles[0])
births = births.query('(births > @mu - 5 * @sig) & (births < @mu + 5 * @sig)')
births['day'] = births['day'].astype(int)
births.index = pd.to_datetime(10000 * births.year + 100 * births.month + births.day, format='%Y%m%d')
births_by_date = births.pivot_table('births', [births.index.month, births.index.day])
births_by_date.index = [pd.datetime(2012, month, day) for (month, day) in births_by_date.index]
fig, ax = plt.subplots(figsize=(12, 4))
births_by_date.plot(ax=ax)
# 在图上增加文字标签
style = dict(size=10, color='gray')
ax.text('2012-1-1', 3950, "New Year's Day", **style)
ax.text('2012-7-4', 4250, "Independence Day", ha='center', **style)
ax.text('2012-9-4', 4850, "Labor Day", ha='center', **style)
ax.text('2012-10-31', 4600, "Halloween", ha='right', **style)
ax.text('2012-11-25', 4450, "Thanksgiving", ha='center', **style)
ax.text('2012-12-25', 3850, "Christmas ", ha='right', **style)
# 设置坐标轴标题
ax.set(title='USA births by day of year (1969-1988)',
ylabel='average daily births')
# 设置x轴刻度值,让月份居中显示
ax.xaxis.set_major_locator(mpl.dates.MonthLocator())
ax.xaxis.set_minor_locator(mpl.dates.MonthLocator(bymonthday=15))
ax.xaxis.set_major_formatter(plt.NullFormatter())
ax.xaxis.set_minor_formatter(mpl.dates.DateFormatter('%h'));
plt.show()
ax.text
方法需要一个 x 轴坐标、一个 y 轴坐标、一个字符串和一些可选参数,比如文字的颜色、字号、风格、对齐方式以及其他文字属性。这里用了 ha='right'
与 ha='center'
,ha
是水平对齐方式(horizonal alignment
)的缩写。关于配置参数的更多信息,请参考plt.text()
与 mpl.text.Text()
的程序文档。
2坐标变换与文字位置
前面的示例将文字放在了目标数据的位置上。但有时候可能需要将文字放在与数据无关的位置上,比如坐标轴或者图形中。在 Matplotlib 中,我们通过调整坐标变换(transform)
来实现。
任何图形显示框架都需要一些变换坐标系的机制。例如,当一个位于 (x, y) = (1, 1)
位置的点需要以某种方式显示在图上特定的位置时,就需要用屏幕的像素来表示。用数学方法处理这种坐标系变换很简单,Matplotlib 有一组非常棒的工具可以实现类似功能(这些工具位于 matplotlib.transforms 子模块
中)。
虽然一般用户并不需要关心这些变换的细节,但是了解这些知识对在图上放置文字大有帮助。一共有三种解决这类问题的预定义变换方式。
ax.transData 以数据为基准的坐标变换。
ax.transAxes 以坐标轴为基准的坐标变换(以坐标轴维度为单位)。
fig.transFigure 以图形为基准的坐标变换(以图形维度为单位)。
默认情况下,上面的文字在各自的坐标系中都是左对齐的。这三个字符串开头的 . 字符基本就是对应的坐标位置。transData
坐标用 x 轴与 y 轴的标签作为数据坐标。transAxes
坐标以坐标轴(图中白色矩形)左下角的位置为原点,按坐标轴尺寸的比例呈现坐标。transFigure
坐标与之类似,不过是以图形(图中灰色矩形)左下角的位置为原点,按图形尺寸的比例呈现坐标。
对比 Matplotlib 的三种坐标系(1)
下面举一个例子,用三种变换方式将文字画在不同的位置:
fig, ax = plt.subplots(facecolor='lightgray')
ax.axis([0, 10, 0, 10])
# 虽然transform=ax.transData是默认值,但还是设置一下
ax.text(1, 5, ". Data: (1, 5)", transform=ax.transData)
ax.text(0.5, 0.1, ". Axes: (0.5, 0.1)", transform=ax.transAxes)
ax.text(0.2, 0.2, ". Figure: (0.2, 0.2)", transform=fig.transFigure);
import matplotlib.pyplot as plt
import matplotlib as mpl
plt.style.use('seaborn-whitegrid')
import numpy as np
import pandas as pd
births = pd.read_csv('C:\\Users\\Y\\Desktop\\data-CDCbirths-master\\births.csv')
quartiles = np.percentile(births['births'], [25, 50, 75])
mu, sig = quartiles[1], 0.74 * (quartiles[2] - quartiles[0])
births = births.query('(births > @mu - 5 * @sig) & (births < @mu + 5 * @sig)')
births['day'] = births['day'].astype(int)
births.index = pd.to_datetime(10000 * births.year + 100 * births.month + births.day, format='%Y%m%d')
births_by_date = births.pivot_table('births', [births.index.month, births.index.day])
births_by_date.index = [pd.datetime(2012, month, day) for (month, day) in births_by_date.index]
fig, ax = plt.subplots(facecolor='lightgray')
ax.axis([0, 10, 0, 10])
# 虽然transform=ax.transData是默认值,但还是设置一下
ax.text(1, 5, ". Data: (1, 5)", transform=ax.transData)
ax.text(0.5, 0.1, ". Axes: (0.5, 0.1)", transform=ax.transAxes)
ax.text(0.2, 0.2, ". Figure: (0.2, 0.2)", transform=fig.transFigure);
plt.show()
对比 Matplotlib 的三种坐标系(2)
需要注意的是,假如你改变了坐标轴上下限,那么只有 transData 坐标会受影响,其他坐标系都不变
ax.set_xlim(0, 2)
ax.set_ylim(-6, 6)
fig
import matplotlib.pyplot as plt
import matplotlib as mpl
plt.style.use('seaborn-whitegrid')
import numpy as np
import pandas as pd
births = pd.read_csv('C:\\Users\\Y\\Desktop\\data-CDCbirths-master\\births.csv')
quartiles = np.percentile(births['births'], [25, 50, 75])
mu, sig = quartiles[1], 0.74 * (quartiles[2] - quartiles[0])
births = births.query('(births > @mu - 5 * @sig) & (births < @mu + 5 * @sig)')
births['day'] = births['day'].astype(int)
births.index = pd.to_datetime(10000 * births.year + 100 * births.month + births.day, format='%Y%m%d')
births_by_date = births.pivot_table('births', [births.index.month, births.index.day])
births_by_date.index = [pd.datetime(2012, month, day) for (month, day) in births_by_date.index]
fig, ax = plt.subplots(facecolor='lightgray')
ax.axis([0, 10, 0, 10])
# 虽然transform=ax.transData是默认值,但还是设置一下
ax.text(1, 5, ". Data: (1, 5)", transform=ax.transData)
ax.text(0.5, 0.1, ". Axes: (0.5, 0.1)", transform=ax.transAxes)
ax.text(0.2, 0.2, ". Figure: (0.2, 0.2)", transform=fig.transFigure);
ax.set_xlim(0, 2)
ax.set_ylim(-6, 6)
fig
plt.show()
如果你改变了坐标轴上下限,那么就可以更清晰地看到刚刚所说的变化。
3箭头与注释
除了刻度线和文字,简单的箭头也是一种有用的注释标签。
在 Matplotlib 里面画箭头通常比你想象的要困难。虽然有一个 plt.arrow()
函数可以实现这个功能,但是我不推荐使用它,因为它创建出的箭头是 SVG 向量图
对象,会随着图形分辨率的变化而改变,最终的结果可能完全不是用户想要的。我要推荐的是 plt.annotate()
函数。这个函数既可以创建文字,也可以创建箭头,而且它创建的箭头能够进行非常灵活的配置。
图形注释
下面用 annotate 的一些配置选项来演示
fig, ax = plt.subplots()
x = np.linspace(0, 20, 1000)
ax.plot(x, np.cos(x))
ax.axis('equal')
ax.annotate('local maximum', xy=(6.28, 1), xytext=(10, 4),arrowprops=dict(facecolor='black', shrink=0.05))
ax.annotate('local minimum', xy=(5 * np.pi, -1), xytext=(2, -6),arrowprops=dict(arrowstyle="->",
connectionstyle="angle3,angleA=0,angleB=-90"));
import matplotlib.pyplot as plt
import matplotlib as mpl
plt.style.use('seaborn-whitegrid')
import numpy as np
import pandas as pd
births = pd.read_csv('C:\\Users\\Y\\Desktop\\data-CDCbirths-master\\births.csv')
quartiles = np.percentile(births['births'], [25, 50, 75])
mu, sig = quartiles[1], 0.74 * (quartiles[2] - quartiles[0])
births = births.query('(births > @mu - 5 * @sig) & (births < @mu + 5 * @sig)')
births['day'] = births['day'].astype(int)
births.index = pd.to_datetime(10000 * births.year + 100 * births.month + births.day, format='%Y%m%d')
births_by_date = births.pivot_table('births', [births.index.month, births.index.day])
births_by_date.index = [pd.datetime(2012, month, day) for (month, day) in births_by_date.index]
fig, ax = plt.subplots()
x = np.linspace(0, 20, 1000)
ax.plot(x, np.cos(x))
ax.axis('equal')
ax.annotate('local maximum', xy=(6.28, 1), xytext=(10, 4),arrowprops=dict(facecolor='black', shrink=0.05))
ax.annotate('local minimum', xy=(5 * np.pi, -1), xytext=(2, -6),arrowprops=dict(arrowstyle="->",connectionstyle="angle3,angleA=0,angleB=-90"));
plt.show()
箭头的风格是通过 arrowprops 字典控制的,里面有许多可用的选项。由于这些选项在Matplotlib 的官方文档中都有非常详细的介绍,我就不再赘述,仅做一点儿功能演示。
带注释的日均出生人数
让我们用前面的美国出生人数图来演示一些箭头注释
fig, ax = plt.subplots(figsize=(12, 4))
births_by_date.plot(ax=ax)
# 在图上增加箭头标签
ax.annotate("New Year's Day", xy=('2012-1-1', 4100), xycoords='data',xytext=(50, -30), textcoords='offset points',arrowprops=dict(arrowstyle="->",connectionstyle="arc3,rad=-0.2"))
ax.annotate("Independence Day", xy=('2012-7-4', 4250),xycoords='data',bbox=dict(boxstyle="round", fc="none", ec="gray"),xytext=(10, -40), textcoords='offset points', ha='center', arrowprops=dict(arrowstyle="->"))
ax.annotate('Labor Day', xy=('2012-9-4', 4850), xycoords='data', ha='center', xytext=(0, -20), textcoords='offset points')
ax.annotate('', xy=('2012-9-1', 4850), xytext=('2012-9-7', 4850), xycoords='data', textcoords='data', arrowprops={'arrowstyle': '|-|,widthA=0.2,widthB=0.2', })
ax.annotate('Halloween', xy=('2012-10-31', 4600), xycoords='data', xytext=(-80, -40), textcoords='offset points', arrowprops=dict(arrowstyle="fancy", fc="0.6", ec="none", connectionstyle="angle3,angleA=0,angleB=-90"))
ax.annotate('Thanksgiving', xy=('2012-11-25', 4500), xycoords='data', xytext=(-120, -60), textcoords='offset points', bbox=dict(boxstyle="round4,pad=.5", fc="0.9"), arrowprops=dict(arrowstyle="->", connectionstyle="angle,angleA=0,angleB=80,rad=20"))
ax.annotate('Christmas', xy=('2012-12-25', 3850), xycoords='data', xytext=(-30, 0), textcoords='offset points', size=13, ha='right', va="center", bbox=dict(boxstyle="round", alpha=0.1), arrowprops=dict(arrowstyle="wedge,tail_width=0.5", alpha=0.1));
# 设置坐标轴标题
ax.set(title='USA births by day of year (1969-1988)', ylabel='average daily births')
# 设置x轴刻度值,让月份居中显示
ax.xaxis.set_major_locator(mpl.dates.MonthLocator())
ax.xaxis.set_minor_locator(mpl.dates.MonthLocator(bymonthday=15))
ax.xaxis.set_major_formatter(plt.NullFormatter())
ax.xaxis.set_minor_formatter(mpl.dates.DateFormatter('%h'));
ax.set_ylim(3600, 5400);
import matplotlib.pyplot as plt
import matplotlib as mpl
plt.style.use('seaborn-whitegrid')
import numpy as np
import pandas as pd
births = pd.read_csv('C:\\Users\\Y\\Desktop\\data-CDCbirths-master\\births.csv')
quartiles = np.percentile(births['births'], [25, 50, 75])
mu, sig = quartiles[1], 0.74 * (quartiles[2] - quartiles[0])
births = births.query('(births > @mu - 5 * @sig) & (births < @mu + 5 * @sig)')
births['day'] = births['day'].astype(int)
births.index = pd.to_datetime(10000 * births.year + 100 * births.month + births.day, format='%Y%m%d')
births_by_date = births.pivot_table('births', [births.index.month, births.index.day])
births_by_date.index = [pd.datetime(2012, month, day) for (month, day) in births_by_date.index]
fig, ax = plt.subplots(figsize=(12, 4))
births_by_date.plot(ax=ax)
# 在图上增加箭头标签
ax.annotate("New Year's Day", xy=('2012-1-1', 4100), xycoords='data',
xytext=(50, -30), textcoords='offset points',
arrowprops=dict(arrowstyle="->",
connectionstyle="arc3,rad=-0.2"))
ax.annotate("Independence Day", xy=('2012-7-4', 4250), xycoords='data',
bbox=dict(boxstyle="round", fc="none", ec="gray"),
xytext=(10, -40), textcoords='offset points', ha='center',
arrowprops=dict(arrowstyle="->"))
ax.annotate('Labor Day', xy=('2012-9-4', 4850), xycoords='data', ha='center',
xytext=(0, -20), textcoords='offset points')
ax.annotate('', xy=('2012-9-1', 4850), xytext=('2012-9-7', 4850),
xycoords='data', textcoords='data',
arrowprops={'arrowstyle': '|-|,widthA=0.2,widthB=0.2', })
ax.annotate('Halloween', xy=('2012-10-31', 4600), xycoords='data',
xytext=(-80, -40), textcoords='offset points',
arrowprops=dict(arrowstyle="fancy",
fc="0.6", ec="none",
connectionstyle="angle3,angleA=0,angleB=-90"))
ax.annotate('Thanksgiving', xy=('2012-11-25', 4500), xycoords='data',
xytext=(-120, -60), textcoords='offset points',
bbox=dict(boxstyle="round4,pad=.5", fc="0.9"),
arrowprops=dict(arrowstyle="->",
connectionstyle="angle,angleA=0,angleB=80,rad=20"))
ax.annotate('Christmas', xy=('2012-12-25', 3850), xycoords='data',xytext=(-30, 0), textcoords='offset points',size=13, ha='right', va="center",bbox=dict(boxstyle="round", alpha=0.1),arrowprops=dict(arrowstyle="wedge,tail_width=0.5", alpha=0.1));
# 设置坐标轴标题
ax.set(title='USA births by day of year (1969-1988)',ylabel='average daily births')
# 设置x轴刻度值,让月份居中显示
ax.xaxis.set_major_locator(mpl.dates.MonthLocator())
ax.xaxis.set_minor_locator(mpl.dates.MonthLocator(bymonthday=15))
ax.xaxis.set_major_formatter(plt.NullFormatter())
ax.xaxis.set_minor_formatter(mpl.dates.DateFormatter('%h'));
ax.set_ylim(3600, 5400);
plt.show()
你可能已经注意到了,箭头和文本框的配置功能非常细致,这样你就可以创建自己想要的箭头风格了。不过,功能太过细致往往也就意味着操作起来比较复杂,如果真要做一个产品级的图形,可能得耗费大量的时间。最后我想说一句,前面适用的混合风格并不是数据可视化的最佳实践,仅仅是为演示一些功能而已。
来源:https://blog.csdn.net/ywsydwsbn/article/details/106771594


猜你喜欢
- 这篇博客将介绍如何通过OpenCV和Python使用模板匹配执行光学字符识别(OCR)。具体来说,将使用Python+OpenCV实现模板匹
- 下文要实现的可视化大屏内容:需要在地图上将我司船舶的轨迹展示出来。听起来很简单,一开始我也是这样想的。通过一些BI工具应该可以轻松实现,比如
- 前言大家都知道,Sublime Text 安装插件一般从 Package Control 中直接安装即可,当我安装 node js 插件时候
- 介绍KEY分区和HASH分区相似,但是KEY分区支持除text和BLOB之外的所有数据类型的分区,而HASH分区只支持数字分区,KEY分区不
- 周期置换密码参考教材:《现代密码学教程》P47 3.1.2加密解密过程周期置换密码是将明文p串按固定长度m分组.然后对每组中的子串按1,2&
- var long2="1988-0w-07";alert(long2.substring(0,4)+"----
- 我们在做网站的时候,网站后台系统一般都会用到web编辑器,今天笔者就给大家推荐一款百度UEditor编辑器。关于这款百度UEditor编辑器
- binlog介绍binlog,即二进制日志,它记录了数据库上的所有改变.改变数据库的SQL语句执行结束时,将在binlog的末尾写入一条记录
- 缓动,学名为Tween,缓冲移动的简称。要想页面内容切换起来舒服,就使用淡入淡出特效,要想让页面元素动起来自然,就要使用缓动效果。这两个混合
- 1、安装scikit-learn1.1Scikit-learn 依赖Python (>= 2.6 or >= 3.3),NumP
- 本次实验利用到了cv2中的createTrackbar和getTrackbarPos函数实现一个绘图板的功能,用户可以选择矩形或是画笔模式,
- 前篇我们稍微学习了Python中时间的获取,这次继续学习日期的时区转换,格式化等等。开发中常用的日期操作还有哪些?时区转换显示日期格式化秒数
- 为什么页面出现乱码?为什么数据库里出现乱码?为什么这些乱码的出现几率飘忽不定了?诸如此类的乱码问题困扰了很多WEB开发人员。假如不将这背后的
- python各类经纬度转换,具体代码如下所示:import mathimport urllibimport jsonx_pi = 3.141
- Dreamweaver出现乱码,大致为两种情况:一是没有标明主页制作所用的文字,这种情况下很简单就可以
- pycharm出现no module named xlwt问题首先声明,我是初学者,今天按照书上步骤,创建Excel文件,当我的xlwt安装
- 一、Python安装Window系统下,python的安装很简单。访问python.org/download,下载最新版本,安装过程与其他w
- 0.目录1.前言2.安装python3.使用pip下载、安装包3.1 安装Scrapy3.2 安装PyQt3.3 同时安装多个包3.4 pi
- MySQL数据库在升级到5.7版本后,和之前的版本有些不一样,没有data文件夹,我们都知道MySQL数据库文件是保存在data文件夹中的,
- return (1==1) ? "is easy" : "my god" //C#中的用法 其实,在