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)
<matplotlib_scalebar.scalebar.ScaleBar at 0x7fb634727850>
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)
<matplotlib_scalebar.scalebar.ScaleBar at 0x7fb6347f1fd0>
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)
<matplotlib_scalebar.scalebar.ScaleBar at 0x7fb63452f790>
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()