ShuoLIU的个人博客分享 http://blog.sciencenet.cn/u/ShuoLIU

博文

python画点线图: 常规文本的字体设置和数学模式的公式字体修改

已有 6457 次阅读 2022-4-14 08:42 |个人分类:python|系统分类:科研笔记

在模型结果和实验数据的比较时, 经常需要画一些点线图, 并输出成eps等格式的矢量图.

由于坐标轴或者图例中经常会有比较复杂的数学表达式, 一般的画图工具难以处理, 而python的绘图库Matplotlib支持和Latex形式相同的公式输入方式, 用$$将公式括起来就可以, 因此最终决定使用python进行绘图. 


使用工具:Pycharm Community Edition 

Python版本:3.6 


首先, 我们先给一个从文本文件中读取数据画图的例子, 文件名称为data, 文本数据如下, 数据之间用tab分隔:

xsqrt(x)x^2
00.000.00
0.10.320.01
0.20.450.04
0.30.550.09
0.40.630.16
0.50.710.25
0.60.770.36
0.70.840.49
0.80.890.64
0.90.950.81
11.001.00


# 画点线图, 以y=sqrt(x)和y=x^2为例, 数据点从文本文件中读取

import pandas as pd
import matplotlib.pyplot as plt

# 读取数据, 分隔符为tab
data1 = pd.read_csv('data', sep="  ")

# 定义横纵坐标的名称
plt.xlabel('x')
plt.ylabel('y')

# 定义横纵坐标的取值范围
plt.xlim(0, 1)
plt.ylim(0, 1)

# 读取数据画点线图
plt.plot(data1['x'], data1['x'], color='black')
plt.scatter(data1['x'], data1['sqrt(x)'], color='red')
plt.scatter(data1['x'], data1['x^2'], color='blue')

# 设置图例名称和位置
# 'y = x'为常规文本, r'$y = \sqrt{x}$' 和 r'$y = x^2$']为数学模式下的文本
plt.legend(['linear: y = x', r'$root$ $square: y = \sqrt{x}$', r'$squared: y = x^2$'], loc='upper left')
plt.savefig('xy.eps', format='eps')

plt.show()


输出的图像如下:

xy.png

可见用python画出来的点线图, 使用默认字体, 常规文本为整体, 数学模式下的文本为斜体, 整体显示效果已经不错. 但由于习惯原因, 还是想用Times New Roman字体, 因此添加下列代码, 查看可用字体:

# 显示当前字体组
print(plt.rcParams["font.family"])

['sans-serif']


# 列出该字体组下的可使用字体
print(plt.rcParams['font.sans-serif'])

['DejaVu Sans', 'Bitstream Vera Sans', 'Computer Modern Sans Serif', 'Lucida Grande', 'Verdana', 'Geneva', 'Lucid', 'Arial', 'Helvetica', 'Avant Garde', 'sans-serif']


可见默认的字体组里是没有Times New Roman的. 通过在网上查找得知, 'serif'字体组里有Times New Roman, 输出看一下:

# 列出该字体组下的可使用字体
print(plt.rcParams['font.serif'])

['DejaVu Serif', 'Bitstream Vera Serif', 'Computer Modern Roman', 'New Century Schoolbook', 'Century Schoolbook L', 'Utopia', 'ITC Bookman', 'Bookman', 'Nimbus Roman No9 L', 'Times New Roman', 'Times', 'Palatino', 'Charter', 'serif']


果然有, 然后就可以执行字体设置更换字体了:

# 设置字体为Times New Roman
plt.rcParams['font.family'] = ['serif']
plt.rcParams['font.serif'] = ['Times New Roman'] + plt.rcParams['font.serif']

不要问我第二行为什么用了自增操作, 不用的话字体无法设置成功, 会退回到默认字体. 

或者

# 设置字体为Times New Roman
plt.rcParams['font.family'] = ['serif']
plt.rcParams['font.sans-serif'] = ['Times New Roman']

不要问我第二行为什么和第一行不对应, 对应的话字体也无法设置成功, 会退回到默认字体. 


字体设置不成功的报错信息: findfont: Font family ['serif'] not found. Falling back to DejaVu Sans.


所以想要成功设置字体, 这两行代码非常重要, 我也是费了好长时间才从网上找到的, 心累.

xy.png

从新输出的图我们可以发现, 横纵坐标x, y和图例linear: y = x都变成了我们设置的字体, 但数学模式下的公式仍然是默认字体. 查看Matplotlib的官网教程得知, 原来数学模式的字体需要单独的设置. 此时一个比较严重的问题出现了,数学模式下支持的字体非常有限:

截图来源网址:https://matplotlib.org/3.5.0/tutorials/introductory/customizing.html 


从matplotlib官网的这个截图中可以看到,数学模式仅支持dejavu, Computer Modern, stix等很少量的字体. 那就只能勉强从这里边选. 网上说stix是和Times New Roman最接近的字体: 

# 设置数学模式下的字体格式
rc = {'font.family': 'serif', 'mathtext.fontset': 'stix'}
plt.rcParams.update(rc)

以上代码可将数学模式下的字体由默认的dejavu改成stix, 显示效果如下:

xy.png


只能说还凑合吧, 已经接近想要的公式字体效果了, 但还是不满意, 尤其是跟号的部分.


然后又在网上发现另外一种方法, 将数学模式下的公式设置成和常规文本一样的字体, 此时所有字体就都是Times New Roman了:

# 设置数学模式下的字体为常规字体格式
plt.rcParams['mathtext.default'] = 'regular'

xy.png


既然如此, 当然也可以在上述设置下, 根据需要将字体设置为斜体:

# 设置字体为斜体
font = {'style': 'italic'}
# 将字体设置应用到横坐标, 纵坐标, 和图例
plt.xlabel('x', font)
plt.ylabel('y', font)
plt.legend(['linear: y = x', r'$root$ $square: y = \sqrt{x}$', r'$squared: y = x^2$'], loc='upper left', prop=font)

xy.png

此时所有的字体都是Times New Roman的斜体了.


那假如想要图例中的'linear: y = x'是正体字, 另外两个保持斜体呢? 这个功能没想到却比较不容易实现, 因为图例的字体都是一起调的, 想要采用不同的格式确实麻烦. 但这个功能通过一些不那么直接的方法还是可以实现的, 我这里生成了两个不同的图例, 然后将它们一起显示, 从而达到了最终的效果. 注意图例边框是有不透明度的, 所以我们先生成后两个斜体图例部分并利用title加一行空白, 然后把去掉边框的正体图例部分叠上去:

# 斜体图例部分, title给空格值形成空白行
p2 = plt.scatter(data1['x'], data1['sqrt(x)'], color='red')
p3 = plt.scatter(data1['x'], data1['x^2'], color='blue')
l2 = plt.legend([p2, p3], [r'$root$ $square: y = \sqrt{x}$', r'$squared: y = x^2$'], loc='upper left', title=' ', prop={'style': 'italic'})
# 正体图例部分, 去掉边框
p1, = plt.plot(data1['x'], data1['x'], color='black')
l1 = plt.legend([p1], ['$linear: y = x$'], loc='upper left', frameon=False, prop={'style': 'normal'})
# 两部分图例叠加
plt.gca().add_artist(l2)

xy.png

至此终于实现所有想要的功能. 但最后这个多图例不同字体的功能实现方式实在不够直接, 建议不是强迫症患者, 能凑合就凑合吧, 其实全是正体或者全是斜体也很好看.



https://blog.sciencenet.cn/blog-3516722-1333829.html

上一篇:paraview处理CFD数据(1):速度矢量图
收藏 IP: 193.54.106.*| 热度|

1 谢钢

该博文允许注册用户评论 请点击登录 评论 (0 个评论)

数据加载中...
扫一扫,分享此博文

Archiver|手机版|科学网 ( 京ICP备07017567号-12 )

GMT+8, 2024-4-27 05:23

Powered by ScienceNet.cn

Copyright © 2007- 中国科学报社

返回顶部