如何在Matplotlib中创建多平行线自定义线型以划分地质剖面?
问题描述
我正在绘制用于划分两个地质剖面的图表,希望使用三条平行虚线作为划分标识。但不清楚如何在Matplotlib中创建由多条线组成的线型,目前通过偏移三组数组的方式实现该效果,虽然呈现效果尚可,但编程过程繁琐,且在部分图表中线型对齐效果很差。请问是否存在由多条线构成的自定义线型方案?
当前实现代码:
import numpy as np import matplotlib.pyplot as plt fs = 12 # 补充原代码缺失的字体大小定义 Pd=np.array([17.5,22.5,27.5,27.5,42.5,47.5,47.5,52.5,52.5,37.5,32.5,47.5,32.5,0,22.5,0]) Px=np.array([23.6685,23.681,23.6935,23.706,23.7185,23.731,23.7435,23.756,23.7685,23.781,23.7935,23.806,23.8185,23.831,23.8435,23.856]) Pd1=np.array([23.5,28.5,28.5,43.5,49.5,49.5,54.5,54.5,38.5,34.5,49.5,32.5,3,25.5,0]) Px1=np.array([23.681,23.6919,23.7044,23.7169,23.7294,23.7419,23.7544,23.7701,23.7826,23.7935,23.806,23.8201,23.831,23.8435,23.8576]) Pd2=np.array([21.5,26.5,26.5,41.5,45.5,45.5,50.5,50.5,35.5,29.5,45.5,32.5,-3,19.5,0]) Px2=np.array([23.681,23.6951,23.7076,23.7201,23.7326,23.7451,23.7576,23.7669,23.7794,23.7935,23.806,23.8169,23.831,23.8435,23.8544]) fig,ax=plt.subplots() fig.set_size_inches(8,5) ax.plot(Px,Pd,linestyle=(0,(10,5)),color='dimgray') ax.plot(Px1,Pd1,linestyle=(0,(10,5)),color='dimgray') ax.plot(Px2,Pd2,linestyle=(0,(10,5)),color='dimgray') ax.xaxis.set_ticks_position('top') ax.set_ylim(150,0) ax.set_xlim(23.88,23.7125) ax.set_xlabel(u'Latitude \N{DEGREE SIGN}N',fontsize=fs) ax.xaxis.set_label_position('top') ax.set_ylabel('Depth (m)') plt.show()
解决方案
方法1:使用路径效果(Path Effects)生成平行多线
无需手动偏移数组,仅绘制一条基础线,通过patheffects添加偏移的平行路径,自动保证线型完全对齐,代码更简洁:
import numpy as np import matplotlib.pyplot as plt import matplotlib.patheffects as path_effects fs = 12 Pd=np.array([17.5,22.5,27.5,27.5,42.5,47.5,47.5,52.5,52.5,37.5,32.5,47.5,32.5,0,22.5,0]) Px=np.array([23.6685,23.681,23.6935,23.706,23.7185,23.731,23.7435,23.756,23.7685,23.781,23.7935,23.806,23.8185,23.831,23.8435,23.856]) fig,ax=plt.subplots() fig.set_size_inches(8,5) # 绘制基础虚线,添加路径效果生成两条平行偏移线 line = ax.plot(Px, Pd, linestyle=(0,(10,5)), color='dimgray')[0] # 设置像素偏移量(可根据需求调整) offsets = [3, -3] for offset in offsets: line.set_path_effects([ path_effects.Stroke(offset=(offset, 0), foreground='dimgray'), path_effects.Normal() # 保留原线条 ]) ax.xaxis.set_ticks_position('top') ax.set_ylim(150,0) ax.set_xlim(23.88,23.7125) ax.set_xlabel(u'Latitude \N{DEGREE SIGN}N',fontsize=fs) ax.xaxis.set_label_position('top') ax.set_ylabel('Depth (m)') plt.show()
若需基于数据坐标偏移,可通过ax.transData将数据域偏移量转换为像素偏移。
方法2:使用LineCollection批量绘制平行线条
将三条线的坐标打包成集合,统一设置线型,确保所有线条的虚线样式完全同步,避免手动偏移时的对齐问题:
import numpy as np import matplotlib.pyplot as plt from matplotlib.collections import LineCollection fs = 12 Pd=np.array([17.5,22.5,27.5,27.5,42.5,47.5,47.5,52.5,52.5,37.5,32.5,47.5,32.5,0,22.5,0]) Px=np.array([23.6685,23.681,23.6935,23.706,23.7185,23.731,23.7435,23.756,23.7685,23.781,23.7935,23.806,23.8185,23.831,23.8435,23.856]) # 定义数据坐标偏移量(按需调整) x_offsets = [0, 0.002, -0.002] # 生成三条线的坐标集合 lines = [] for offset in x_offsets: lines.append(np.column_stack((Px + offset, Pd))) fig,ax=plt.subplots() fig.set_size_inches(8,5) # 创建LineCollection,统一设置线型和颜色 lc = LineCollection(lines, linestyle=(0,(10,5)), color='dimgray') ax.add_collection(lc) ax.xaxis.set_ticks_position('top') ax.set_ylim(150,0) ax.set_xlim(23.88,23.7125) ax.set_xlabel(u'Latitude \N{DEGREE SIGN}N',fontsize=fs) ax.xaxis.set_label_position('top') ax.set_ylabel('Depth (m)') plt.show()
方法3:改进手动偏移的对齐问题
若坚持使用多数组偏移方式,可通过统一计算偏移量、同步线型相位解决对齐问题:
import numpy as np import matplotlib.pyplot as plt fs = 12 Pd=np.array([17.5,22.5,27.5,27.5,42.5,47.5,47.5,52.5,52.5,37.5,32.5,47.5,32.5,0,22.5,0]) Px=np.array([23.6685,23.681,23.6935,23.706,23.7185,23.731,23.7435,23.756,23.7685,23.781,23.7935,23.806,23.8185,23.831,23.8435,23.856]) # 统一计算偏移量,避免手动输入误差 offset = 0.002 Px1 = Px + offset Px2 = Px - offset Pd1 = Pd Pd2 = Pd fig,ax=plt.subplots() fig.set_size_inches(8,5) # 使用相同的线型定义,确保虚线相位一致 dash_style = (0, (10,5)) ax.plot(Px,Pd,linestyle=dash_style,color='dimgray') ax.plot(Px1,Pd1,linestyle=dash_style,color='dimgray') ax.plot(Px2,Pd2,linestyle=dash_style,color='dimgray') ax.xaxis.set_ticks_position('top') ax.set_ylim(150,0) ax.set_xlim(23.88,23.7125) ax.set_xlabel(u'Latitude \N{DEGREE SIGN}N',fontsize=fs) ax.xaxis.set_label_position('top') ax.set_ylabel('Depth (m)') plt.show()
内容的提问来源于stack exchange,提问作者BrianM
相关产品推荐
相关产品推荐

