Python绘制多轴刻度雷达图的问题(Matplotlib实现)
多刻度雷达图刻度匹配问题修复
原本计划用VEDO生成复杂雷达图,后来参考Stack Overflow上的Matplotlib示例代码修改,目标实现各坐标轴带独立多刻度的雷达图,但运行后发现所有线条都只适配第一轴的刻度规则,无法对应各自轴的正确刻度位置。
原代码
import numpy as np import pylab as pl from matplotlib import pyplot as plt class Radar(object): def __init__(self, fig, titles, labels, rect=None): if rect is None: rect = [0.05, 0.05, 0.95, 0.95] self.n = len(titles) self.angles = np.arange(90, 90+360, 360.0/self.n) self.angles = [a % 360 for a in self.angles] self.axes = [fig.add_axes(rect, projection="polar", label="axes%d" % i) for i in range(self.n)] self.ax = self.axes[0] self.ax.set_thetagrids(self.angles, labels=titles, fontsize=14) for ax in self.axes[0:]: ax.patch.set_visible(False) ax.grid("off") ax.xaxis.set_visible(False) index = 0 for ax, angle, label in zip(self.axes, self.angles, labels): ax.set_rgrids(range(1, label.__len__()+1), angle=angle, labels=label) ax.spines["polar"].set_visible(True) ax.set_ylim(0, label.__len__()) index+=1 def plot(self, values, *args, **kw): angle = np.deg2rad(np.r_[self.angles, self.angles[0]]) values = np.r_[values, values[0]] self.ax.plot(angle, values, *args, **kw) fig = pl.figure(figsize=(6, 6)) titles = list("ABCDE") labels = [ list("abc"), list("12345"), list("uvwxy"), ["one", "two", "three", "four", "five"], list("jklmn") ] radar = Radar(fig, titles, labels) radar.plot([2,2,2,2,2], "-", lw=2, color="b", alpha=0.4, label="first") radar.plot([2.3, 2, 3, 3, 2],"-", lw=2, color="r", alpha=0.4, label="second") radar.plot([3, 4, 3, 4, 2], "-", lw=2, color="g", alpha=0.4, label="third") radar.ax.legend() plt.show()
问题根源
原代码存在两个核心问题:
- 所有绘图操作都在第一个轴(
self.ax = self.axes[0])上执行,而每个轴的ylim范围不同(比如第一轴是0-3,第二轴是0-5),导致其他轴的数值无法匹配自身刻度。 - 直接使用原始数值绘图,没有考虑不同轴的刻度数量差异,数值对应的径向位置在不同轴上不匹配。
修复后的代码
import numpy as np import pylab as pl from matplotlib import pyplot as plt class Radar(object): def __init__(self, fig, titles, labels, rect=None): if rect is None: rect = [0.05, 0.05, 0.95, 0.95] self.n = len(titles) self.angles = np.arange(90, 90+360, 360.0/self.n) self.angles = [a % 360 for a in self.angles] # 保存每个轴的刻度数量,用于后续归一化 self.label_lengths = [len(lbl) for lbl in labels] self.axes = [fig.add_axes(rect, projection="polar", label="axes%d" % i) for i in range(self.n)] self.ax = self.axes[0] self.ax.set_thetagrids(self.angles, labels=titles, fontsize=14) for ax in self.axes: ax.patch.set_visible(False) ax.grid("off") ax.xaxis.set_visible(False) for ax, angle, label, length in zip(self.axes, self.angles, labels, self.label_lengths): # 计算归一化后的刻度位置(0-1范围) grid_positions = [i/length for i in range(1, length+1)] ax.set_rgrids(grid_positions, angle=angle, labels=label) ax.spines["polar"].set_visible(True) ax.set_ylim(0, 1) # 统一所有轴的径向范围为0-1 def plot(self, values, *args, **kw): # 将每个数值归一化到对应轴的0-1范围 normalized_values = [val/self.label_lengths[i] for i, val in enumerate(values)] angle = np.deg2rad(np.r_[self.angles, self.angles[0]]) normalized_values = np.r_[normalized_values, normalized_values[0]] self.ax.plot(angle, normalized_values, *args, **kw) fig = pl.figure(figsize=(6, 6)) titles = list("ABCDE") labels = [ list("abc"), list("12345"), list("uvwxy"), ["one", "two", "three", "four", "five"], list("jklmn") ] radar = Radar(fig, titles, labels) # 传入的数值对应各轴的刻度索引(从1开始) radar.plot([2,2,2,2,2], "-", lw=2, color="b", alpha=0.4, label="first") radar.plot([2, 2, 3, 3, 2],"-", lw=2, color="r", alpha=0.4, label="second") radar.plot([3, 4, 3, 4, 2], "-", lw=2, color="g", alpha=0.4, label="third") radar.ax.legend() plt.show()
修复说明
- 统一径向范围:将所有轴的
ylim设置为0-1,避免不同轴的刻度范围冲突。 - 数值归一化:在绘图前,把每个轴的原始数值(对应刻度的索引)转换为相对于该轴刻度数量的比例,确保数值能匹配对应轴的刻度位置。
- 刻度位置调整:每个轴的径向刻度位置也按比例计算,保证刻度显示在正确的归一化位置上。
内容的提问来源于stack exchange,提问作者macchina001
相关产品推荐
相关产品推荐

