matplotlib-scalebar是一个Python库,用于在matplotlib图形中添加比例尺。它允许用户指定比例尺的大小、位置、字体和颜色,以及比例尺的单位。该库支持不同的比例尺单位,例如米、英尺、英寸等。matplotlib-scalebar安装命令如下:
pip install matplotlib-scalebar
比例尺是一种用于描述图上线段长度与实际相应线段长度之间关系的方法。其基本公式为:比例尺 = 图上距离 / 实际距离。比例尺的表示方法可以分为三种:
matplotlib-scalebar仅适用于线段式比例尺的绘制。因为在matplotlib中,我们可以通过文字绘制函数直接在图上添加数字式或文字式的比例尺。
本文所有代码见:Python-Study-Notes
# jupyter notebook环境去除warning
import warnings
warnings.filterwarnings("ignore")
import matplotlib_scalebar
# 打印matplotlib_scalebar版本
print("matplotlib_scalebar version",matplotlib_scalebar.__version__)
import matplotlib as plt
print("matplotlob version",plt.__version__)
matplotlib_scalebar version 0.8.1
matplotlob version 3.5.3
以下代码展示了一个matplotlib-scalebar的使用示例,matplotlib-scalebar提供ScaleBar类来创建预设比例尺:
ScaleBar(dx= 0.08, units= "cm", length_fraction=0.5)
其中dx,units和length_fraction都是基本参数,dx表示图中每个横向像素坐标实际代表0.08cm的长度,units表示使用cm厘米作为基准单位,length_fraction=0.5表示预设比例尺长度占实际绘图区域横向总长度的比例为50%。
预设比例尺的含义为:matplotlib_scalebar.scalebar会根据我们预置的比例尺参数图,挑选合适规格的标准比例尺来表示。如下所示:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cbook as cbook
from matplotlib_scalebar.scalebar import ScaleBar
# 载入自带图片数据,并将图片宽高都修改为256
with cbook.get_sample_data("s1045.ima.gz") as dfile:
im = np.frombuffer(dfile.read(), np.uint16).reshape((256, 256))
fig, ax = plt.subplots()
ax.axis("off")
# 绘图
ax.imshow(im, cmap="gray")
# 创建一个比例尺对象
scalebar = ScaleBar(dx= 0.08, units= "cm", length_fraction=0.5)
# 添加比例尺
ax.add_artist(scalebar)
plt.show()
如上图所示,比例尺由一根横线和横线下的文字标识组成。该比例尺表示图中横向方向上,横线的长度等于实际1dm(分米)。以文中matplotlib-scalebar绘图代码为例说明计算该比例尺的步骤:
256*0.08*0.5
,也就是10.24cm,共占横向128个像素。256*0.5*1/1.024
,也就是125个像素。在matplotlib-scalebar,对于米制单位,预设比例尺数值规格为:
[1, 2, 5, 10, 15, 20, 25, 50, 75, 100, 125, 150, 200, 500, 750]
预设比例尺单位规格为:
{'m': 1.0,
'Ym': 1e+24,
'Zm': 1e+21,
'Em': 1e+18,
'Pm': 1000000000000000.0,
'Tm': 1000000000000.0,
'Gm': 1000000000.0,
'Mm': 1000000.0,
'km': 1000.0,
'dm': 0.1,
'cm': 0.01,
'mm': 0.001,
'µm': 1e-06,
'um': 1e-06,
'nm': 1e-09,
'pm': 1e-12,
'fm': 1e-15,
'am': 1e-18,
'zm': 1e-21,
'ym': 1e-24}
matplotlib-scalebar关于比例尺的计算详细函数见matplotlib_scalebar/dimension.py的draw函数。
按照以上比例尺的计算步骤,如果dx= 0.01, units= “m”, length_fraction=1。那么实际应该使用预设数值规格为2,单位规格为m,占横向200个像素的比例尺。如下所示:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cbook as cbook
from matplotlib_scalebar.scalebar import ScaleBar
# 载入matplotlib自带图片数据,并将图片宽高都修改为256
with cbook.get_sample_data("s1045.ima.gz") as dfile:
im = np.frombuffer(dfile.read(), np.uint16).reshape((256, 256))
fig, ax = plt.subplots()
ax.axis("off")
# 绘图
ax.imshow(im, cmap="gray")
# 创建一个比例尺对象
scalebar = ScaleBar(dx= 0.01, units= "m", length_fraction=1)
# 添加比例尺
ax.add_artist(scalebar)
plt.show()
在前面展示的是表示横向方向长度的比例尺,如果想创建表示纵向方向的比例尺,则在初始ScaleBar类时设置rotation="vertical"即可。要注意纵向比例尺是根据图像高度来计算的,如下代码所示:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cbook as cbook
from matplotlib_scalebar.scalebar import ScaleBar
# 载入自带图片数据,并将图片宽改为512,高改为128,可以对比不设置rotation="vertical"时的效果
with cbook.get_sample_data("s1045.ima.gz") as dfile:
im = np.frombuffer(dfile.read(), np.uint16).reshape((128, 512))
fig, ax = plt.subplots()
ax.axis("off")
# 绘图
ax.imshow(im, cmap="gray")
# 创建一个比例尺对象
scalebar = ScaleBar(dx=0.01,
units="m",
length_fraction=1,
rotation="vertical",
scale_loc="right",
border_pad=1,
pad=0.5)
# 添加比例尺
ax.add_artist(scalebar)
plt.show()
ScaleBar类构造函数的参数如下所示:
dx (float): x轴的长度,以当前绘图单位表示。
units (str, optional): 标尺的单位。默认为"m"。
dimension (str, optional): 标尺的属性维度。默认为"si-length"。
label (str or None, optional): 标尺的标签文字。默认为None。
length_fraction (float, optional): 标尺的长度与总长度的比例。默认为None。
height_fraction (float, optional): 标尺的高度与总高度的比例。默认为None,该参数已经废除,使用width_fraction替代。
width_fraction (float, optional): 标尺的宽度与总宽度的比例。默认为None。
location (tuple or None, optional): 标尺的位置。默认为None。
pad (tuple or None, optional): 内边距。默认为None。
border_pad (tuple or None, optional): 外边距。默认为None。
sep (tuple or None, optional): 标签文字与标尺之间的间隔。默认为None。
frameon (bool or None, optional): 是否显示标尺背景框。默认为None。
color (str or tuple or None, optional): 标尺的颜色。默认为None。
box_color (str or tuple or None, optional): 标尺线框的颜色。默认为None。
box_alpha (float or None, optional): 标尺线框的透明度。默认为None。
scale_loc (str or None, optional): 标尺放置的位置。默认为None。
label_loc (str or None, optional): 标签文字放置的位置。默认为None。
font_properties (str or None, optional): 字体样式。默认为None。
label_formatter (str or None, optional): 标签文字格式化函数。默认为None,该参数已经废除,使用scale_formatter替代。
scale_formatter (str or None, optional): 标尺刻度格式化函数。默认为None。
fixed_value (float or None, optional): 固定的标尺值。默认为None。
fixed_units (str or None, optional): 固定的标尺单位。默认为None。
animated (bool, optional): 是否以动画的形式进行显示。默认为False。
rotation (float or None, optional): 标签文字的旋转角度。默认为None。
bbox_to_anchor (str or tuple or None, optional): 标签文字的位置基准。默认为None,一些matplotlib_scalebar版本可能不支持该参数。
bbox_transform (str or None, optional): 标签文字的变换函数。默认为None,一些matplotlib_scalebar版本可能不支持该参数。
ScaleBar一些主要参数决定了比例尺的展示效果,下图展示了ScaleBar主要参数的作用域:
值得注意的是,ScaleBar提供了两种计算比例尺规格的方式:
接下来,对ScaleBar的主要参数进行介绍。
dx为必须输入参数,表示一个像素点代表的实际大小。units表示单位,dimension表示单位属性(所属单位制),可选的长度单位参数如下表所示:
dimension | units |
---|---|
si-length | km, m, cm, um |
imperial-length | in, ft, yd, mi |
si-length-reciprocal | 1/m, 1/cm |
angle | deg |
如果使用GeoPandas绘制地图的比例尺则需要根据坐标系的类型来确定dx,具体如何在GeoPandas中确定dx见:Python绘制数据地图3-GeoPandas使用要点。
将比例尺的标识改为imperial-length英制长度的示例代码如下:
# 载入matplotlib自带图片数据,并将图片宽高都修改为256
with cbook.get_sample_data("s1045.ima.gz") as dfile:
im = np.frombuffer(dfile.read(), np.uint16).reshape((256, 256))
fig, ax = plt.subplots()
ax.axis("off")
ax.imshow(im, cmap="gray")
scalebar = ScaleBar(dx=0.0315, units="in", dimension="imperial-length", length_fraction=0.25)
ax.add_artist(scalebar)
label设置标尺的标签文字。label_loc设置标签文字相对于比例尺的位置,可选值有: bottom, top, left, right, none(不显示标签文字)。 scale_loc设置比例尺标注值相对于比例尺的位置,可选值有: bottom, top, left, right, none(不显示标注文字)。示例代码如下:
# 载入matplotlib自带图片数据,并将图片宽高都修改为256
with cbook.get_sample_data("s1045.ima.gz") as dfile:
im = np.frombuffer(dfile.read(), np.uint16).reshape((256, 256))
fig, ax = plt.subplots()
ax.axis("off")
ax.imshow(im, cmap="gray")
scalebar = ScaleBar(dx= 0.08, units= "cm", length_fraction=0.25,
label="scale bar",label_loc="left", scale_loc="top")
ax.add_artist(scalebar)
length_fraction设置比例尺相对于图形的长度,如果不指定值,在代码内部会以为0.2(20%)赋值。width_fraction设置比例尺相对于图形的宽度,如果不指定值,在代码内部会以为0.01(1%)赋值。本文在1.1节提到过,在这种情况下比例尺标注值只能取以下数字确定的:1、2、5、10、15等。如果需要特定的值,需要指定fixed_value和fixed_units。示例代码如下:
# 载入自带图片数据,并将图片宽高都修改为256
with cbook.get_sample_data("s1045.ima.gz") as dfile:
im = np.frombuffer(dfile.read(), np.uint16).reshape((256, 256))
fig, ax = plt.subplots()
ax.axis("off")
# 绘图
ax.imshow(im, cmap="gray")
# 创建一个比例尺对象
scalebar = ScaleBar(dx= 0.08, units= "cm", length_fraction=0.25, width_fraction=0.05)
# 添加比例尺
ax.add_artist(scalebar)
plt.show()
示例代码如下:
# 载入自带图片数据,并将图片宽高都修改为256
with cbook.get_sample_data("s1045.ima.gz") as dfile:
im = np.frombuffer(dfile.read(), np.uint16).reshape((256, 256))
fig, ax = plt.subplots()
ax.axis("off")
# 绘图
ax.imshow(im, cmap="gray")
# 创建一个比例尺对象
# 如果将frameon设置为False,对于当前背景为黑色的图片需要修改标尺颜色以更好可视化效果。
scalebar = ScaleBar(dx= 0.08, units= "cm", length_fraction=0.25,
location="upper left", pad = 0.1, border_pad=0.5,
sep=2, frameon=True)
# 添加比例尺
ax.add_artist(scalebar)
plt.show()
matplotlib-scalebar通过color参数设置标尺及标注文字的颜色,通过box_color和box_alpha设置背景框的颜色和透明度。示例代码如下:
# 载入自带图片数据,并将图片宽高都修改为256
with cbook.get_sample_data("s1045.ima.gz") as dfile:
im = np.frombuffer(dfile.read(), np.uint16).reshape((256, 256))
fig, ax = plt.subplots()
ax.axis("off")
# 绘图
ax.imshow(im, cmap="gray")
# 创建一个比例尺对象
scalebar = ScaleBar(dx= 0.08, units= "cm", length_fraction=0.25,
color="white", box_color = "blue", box_alpha=0.7)
# 添加比例尺
ax.add_artist(scalebar)
plt.show()
font_properties设置标签文本的字体属性,具体使用见matplotlib的FontProperties。
scale_formatter调用类似lambda value, unit: f"{value} {unit}"
这类自定义函数来自定义比例尺的标注值,默认为none。
示例代码如下:
# 载入自带图片数据,并将图片宽高都修改为256
with cbook.get_sample_data("s1045.ima.gz") as dfile:
im = np.frombuffer(dfile.read(), np.uint16).reshape((256, 256))
fig, ax = plt.subplots()
ax.axis("off")
# 绘图
ax.imshow(im, cmap="gray")
# 创建一个比例尺对象
scalebar1 = ScaleBar(dx= 0.08, units= "cm", length_fraction=0.25,
scale_formatter = lambda value, unit: f"scalebar")
scalebar2 = ScaleBar(dx= 0.08, units= "cm", length_fraction=0.25, location='center left',
scale_formatter = lambda value, unit: f"value: {value}/{unit}")
scalebar3 = ScaleBar(dx= 0.08, units= "cm", length_fraction=0.25, location='center',
font_properties={'style':'italic','weight':'bold','size':12})
# 添加比例尺
ax.add_artist(scalebar1)
ax.add_artist(scalebar2)
ax.add_artist(scalebar3)
plt.show()
fixed_value和fixed_units用于自定义比例尺标注值,当fixed_value默认为none表示根据dx自动确定比例尺的标注值。比例尺的长度会根据dx和这两个参数而自动调整。示例代码如下:
# 载入自带图片数据,并将图片宽高都修改为256
with cbook.get_sample_data("s1045.ima.gz") as dfile:
im = np.frombuffer(dfile.read(), np.uint16).reshape((256, 256))
fig, ax = plt.subplots()
ax.axis("off")
# 绘图
ax.imshow(im, cmap="gray")
# 创建一个比例尺对象
scalebar = ScaleBar(dx= 0.08, units= "cm", length_fraction=0.25,
fixed_value=0.5, fixed_units= "cm")
# 添加比例尺
ax.add_artist(scalebar)
plt.show()
rotation表示是基于x轴还是基于y轴创建比例尺。rotation可取horizontal或vertical。如果调整rotation,可能需要调整scale_loc和label_loc以实现合理的比例尺布局。如果改变rotation的值后,比例尺标注值显示有问题,可以尝试升级matplotlib版本解决。rotation默认为None,表示使用matplotlib的默认值。如下:
# 载入自带图片数据,并将图片宽高都修改为256
with cbook.get_sample_data("s1045.ima.gz") as dfile:
im = np.frombuffer(dfile.read(), np.uint16).reshape((256, 256))
fig, ax = plt.subplots()
ax.axis("off")
ax.imshow(im, cmap="gray")
scalebar = ScaleBar(
0.08,
"cm",
length_fraction=0.25,
rotation="vertical",
scale_loc="right",
border_pad=1,
pad=0.1,
)
ax.add_artist(scalebar)
plywood-gallery-matplotlib-scalebar提供了一个交互式matplotlib-scalebar的绘图实例,每个实例给出了不同图例参数详细的绘制代码,非常推荐学习和使用。绘图实例内容如下:
总体绘图效果如下:
以下代码展示不同绘图实例的效果。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib_scalebar.scalebar import ScaleBar
import matplotlib.image as mpimg
# 添加比例尺代码
def imshow_bar(im, scalebar,ax):
ax.axis("off")
ax.imshow(im)
ax.add_artist(scalebar)
fig, _ = plt.subplots(figsize=(14, 14))
# 调整子图间距
plt.subplots_adjust(wspace=0.05, hspace=0.05)
# 图1
ax = plt.subplot(441)
img = mpimg.imread("image/orange.png")
scalebar = ScaleBar(0.3, "mm", scale_formatter=lambda value, unit: f"{value/5} limo")
imshow_bar(img, scalebar,ax=ax)
# 图2
ax = plt.subplot(442)
img = mpimg.imread("image/orange.png")
scalebar = ScaleBar(0.3, "mm", border_pad=1)
imshow_bar(img, scalebar,ax=ax)
# 图3
ax = plt.subplot(443)
img = mpimg.imread("image/green.png")
scalebar = ScaleBar(0.3, "mm", pad=1)
imshow_bar(img, scalebar,ax=ax)
# 图4
ax = plt.subplot(444)
img = mpimg.imread("image/green.png")
scalebar = ScaleBar(1, "px", dimension="pixel-length", length_fraction=0.3)
imshow_bar(img, scalebar,ax=ax)
# 图5
ax = plt.subplot(445)
img = mpimg.imread("image/yellow.png")
scalebar = ScaleBar(0.03 / 2.54, "in", dimension="imperial-length", length_fraction=0.3)
imshow_bar(img, scalebar,ax=ax)
# 图6
ax = plt.subplot(4,4,6)
img = mpimg.imread("image/yellow.png")
scalebar = ScaleBar(0.3, "mm", height_fraction=0.05)
imshow_bar(img, scalebar,ax=ax)
# 图7
ax = plt.subplot(4,4,7)
img = mpimg.imread("image/purple.png")
scalebar = ScaleBar(0.3, "mm", rotation="vertical")
imshow_bar(img, scalebar,ax=ax)
# 图8
ax = plt.subplot(4,4,8)
img = mpimg.imread("image/purple.png")
scalebar = ScaleBar(0.3, "mm", color="blue", scale_loc="right")
imshow_bar(img, scalebar,ax=ax)
# 图9
ax = plt.subplot(4,4,9)
img = mpimg.imread("image/red.png")
scalebar = ScaleBar(0.3, "mm", box_color="skyblue", box_alpha=0.3)
imshow_bar(img, scalebar,ax=ax)
# 图10
ax = plt.subplot(4,4,10)
img = mpimg.imread("image/red.png")
scalebar = ScaleBar(0.3, "mm", label="Lemon", label_loc="right")
imshow_bar(img, scalebar,ax=ax)
# 图11
ax = plt.subplot(4,4,11)
img = mpimg.imread("image/zoom1.png")
scalebar = ScaleBar(0.3 / 5, "mm", sep=10)
imshow_bar(img, scalebar,ax=ax)
# 图12
ax = plt.subplot(4,4,12)
img = mpimg.imread("image/zoom2.png")
scalebar = ScaleBar(0.3 / 100, "mm", label="Lemon", label_loc="bottom")
imshow_bar(img, scalebar,ax=ax)
# 图13
ax = plt.subplot(4,4,13)
img = mpimg.imread("image/zoom3.png")
scalebar = ScaleBar(0.3 / 10000, "mm", length_fraction=1, font_properties="serif")
imshow_bar(img, scalebar,ax=ax)
# 图14
ax = plt.subplot(4,4,14)
img = mpimg.imread("image/zoom4.png")
scalebar = ScaleBar(0.3 / 10000000, "mm", frameon=False, label="Lemon")
imshow_bar(img, scalebar,ax=ax)
# 图15
ax = plt.subplot(4,4,15)
img = mpimg.imread("image/zoom4.png")
scalebar = ScaleBar(0.3 / 10000000, "mm", fixed_units="mm", fixed_value=1e-6, font_properties="monospace", location="lower left")
imshow_bar(img, scalebar,ax=ax)
# 图16
ax = plt.subplot(4,4,16)
img = mpimg.imread("image/zoom4.png")
scalebar = ScaleBar(0.3 / 10000000, "mm", fixed_units="pm", fixed_value=1000, location="upper left")
imshow_bar(img, scalebar,ax=ax)
# 保存图片
plt.savefig("res.jpg",dpi=300)
plt.show()