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
猜你喜欢
- 本文列出了HTML4标签的默认样式列表,对网页设计者来说这个应该很有用。原文来自:W3C (http://www.w3.org/TR/CSS
- js模拟随机抽奖程序代码!相关文章推荐:随机6+1选号码摇奖程序 <html><title>模拟抽奖-asp之家&l
- HMAC 算法可用于验证在应用程序之间传递或存储在潜在易受攻击位置的信息的完整性。基本思想是生成与共享密钥组合的实际数据的加密散列。然后,可
- 使用python进行基本的图像操作与处理前言:与早期计算机视觉领域多数程序都是由 C/C++ 写就的情形不同。随着计算机硬件速度越来越快,研
- PyQt5访问系统剪切板QClipboard类介绍QClipboard类提供了对系统剪切板的访问,可以在应用程序之间复制和粘贴数据,它的操作
- 一段查看ASP文件源码的ASP程序,需要的朋友可以试试!<% SUB PrintLine (ByVal
- 01、正则表达式学习正则表达式操作字符串,re模块是用C语言写的没匹配速度非常快,其中compile函数根据一个模式字符串和可选的标志参数生
- 随着因特网的发展,在网络环境中,数据库应用渐渐向操作简单、功能实用的方向发展。本文介绍如何利用ASP技术实现对数据库进行在线维护的方法,并给
- 本文实例讲述了python实现生成Word、docx文件的方法。分享给大家供大家参考,具体如下:http://python-docx.rea
- 抛出的异常信息:异常详细信息: System.ArgumentOutOfRangeException: “ddlTotalCostDisco
- 概述Python是个非常受欢迎的编程语言,随着近些年机器学习、云计算等技术的发展,Python的职位需求越来越高。下面我收集了10个Pyth
- 创建项目和应用django-admin startproject zqxt_views(项目名)cd zqxt_viewspython ma
- 聚合函数 count,max,min,avg,sum... select count (*) from T_Employee select
- print() 函数使用以 % 开头的转换说明符对各种类型的数据进行格式化输出。转换说明符(Conversion Specifier)只是一
- 在 Go 语言中,struct 是一种常见的数据类型,它可以用来表示复杂的数据结构。在 struct 中,我们可以定义多个字段,每个字段可以
- 写了一个练手的爬虫...在输出的时候出现了让人很不愉♂悦的问题像这样:令人十分难受啊!#--------------------------
- 现在需要将course分组,然后选择出每一组里面的最大值和最小值,并保留下来实现下面数据结果:直接使用groupby函数,不能直接达到此效果
- 本人曾经用过的备份方式有:mysqldump、mysqlhotcopy、BACKUP TABLE 、SELECT INTO OUTFILE,
- 刚刚解决了这个问题,现在记录下来问题描述当使用lambda层加入自定义的函数后,训练没有bug,载入保存模型则显示Nonetype has
- 用于逐行分析文本的代码示例fileIN = open(sys.argv[1], "r")line = fileIN.re