Python散点图如何将默认标记替换为自定义SVG天气图标?
错误原因
你使用parse_path返回的是第三方svg解析库(通常为svgpathtools)的Path对象,不属于Matplotlib原生支持的marker参数格式,且该自定义对象不可哈希,无法被Matplotlib内部缓存机制调用,因此抛出不可哈希类型报错。
解决方案
方案1:转换为Matplotlib原生Path作为自定义marker
需要先将SVG路径解析为Matplotlib支持的matplotlib.path.Path对象,同时对路径坐标做归一化处理,避免标记尺寸异常:
import matplotlib.pyplot as plt from matplotlib.path import Path import numpy as np # 引入专门的转换库替代原svgpathtools的parse_path from svgpath2mpl import parse_path # 你的SVG路径字符串 svg_path_str = """M 350.04,161.95 C 350.04,161.95 391.76,120.24 391.76,120.24M 120.24,391.76 C 120.24,391.76 161.96,350.04 161.96,350.04M 389.00,256.00 C 389.00,256.00 448.00,256.00 448.00,256.00M 64.00,256.00 C 64.00,256.00 123.00,256.00 123.00,256.00M 350.04,350.04 C 350.04,350.04 391.76,391.76 391.76,391.76M 120.24,120.24 C 120.24,120.24 161.96,161.95 161.96,161.95M 256.00,389.00 C 256.00,389.00 256.00,447.99 256.00,447.99M 256.00,64.00 C 256.00,64.00 256.00,123.00 256.00,123.00M 157.56,216.68M 150.90,242.12 C 150.31,246.60 150.00,251.26 150.00,256.00 150.00,256.01 150.00,256.02 150.00,256.02 150.00,314.57 197.46,362.02 256.00,362.02 314.54,362.02 362.00,314.57 362.00,256.02 362.00,197.48 314.54,150.02 256.00,150.02 220.35,150.02 188.80,167.63 169.59,194.62M 276.00,170.00 C 217.46,170.00 170.01,217.46 170.01,276.00 170.01,300.17 178.09,322.45 191.71,340.28 209.54,353.90 231.82,361.99 255.99,361.99 314.53,361.99 361.99,314.53 361.99,255.99 361.99,231.83 353.90,209.55 340.29,191.72 322.52,178.10 300.28,170.00 276.16,170.00 276.11,170.00 276.05,170.00 276.00,170.00 276.00,170.00 276.00,170.00 276.00,170.00 Z""" clear_marker = parse_path(svg_path_str) # 坐标归一化,将路径缩放到(-1,1)区间适配marker尺寸 clear_marker.vertices -= clear_marker.vertices.mean(axis=0) max_extent = np.max(np.abs(clear_marker.vertices)) clear_marker.vertices /= max_extent # 测试绘图 x = np.random.rand(10) y = np.random.rand(10) plt.plot(x, y, marker=clear_marker, linestyle='', markersize=20) plt.show()
注:使用该方案需要先安装svgpath2mpl库,可直接完成SVG路径到Matplotlib Path的转换,避免手动解析的繁琐。
方案2:直接加载SVG文件作为标记(更适合多天气图标场景)
如果你有多个不同的天气SVG图标,更推荐使用AnnotationBbox直接将SVG作为图像贴到散点位置,适配性更高,不需要处理路径转换逻辑:
import io import matplotlib.pyplot as plt from matplotlib.offsetbox import OffsetImage, AnnotationBbox import cairosvg from PIL import Image import numpy as np # SVG转可用图像的工具函数 def svg_to_image(svg_path, size=30): png_data = cairosvg.svg2png(url=svg_path, output_width=size, output_height=size) return Image.open(io.BytesIO(png_data)) # 示例:加载晴天图标,给对应天气的点加标记 sun_icon = svg_to_image("sun.svg", size=40) imagebox = OffsetImage(sun_icon, zoom=1) x = np.random.rand(10) y = np.random.rand(10) fig, ax = plt.subplots() ax.scatter(x, y, alpha=0) # 先绘制透明散点占位 # 给每个点添加对应天气图标 for xi, yi in zip(x, y): ab = AnnotationBbox(imagebox, (xi, yi), frameon=False) ax.add_artist(ab) plt.show()
注:使用该方案需要先安装cairosvg、pillow库完成SVG到图像的转换。
内容的提问来源于stack exchange,提问作者Somnus
相关产品推荐
相关产品推荐

