如何将Matplotlib图表X轴设置为非均匀刻度以优化低区间数据展示
Matplotlib X轴刻度比例调整问题
我用Matplotlib绘图时遇到个问题:想放大X轴0-500区间的刻度比例,让1000-3000区间的显示宽度和0-500区间一致,以此更清晰展示0-500区间的数据。期望的刻度点为[0,100,200,300,400,500,2000,3000],尝试了以下代码但未达到预期效果:
fig, ax = plt.subplots() x = [0, 100,200, 300, 400, 500, 1000, 2000, 3000] ax.xaxis.set_ticks(range(len(x))) ax.xaxis.set_ticklabels(x) plt.plot(df_run_curves_rhc_60["Iteration"],df_run_curves_rhc_60["Fitness"], label="RHC", color="blue") plt.plot(df_run_curves_sa_60["Iteration"],df_run_curves_sa_60["Fitness"], label="SA", color="orange") plt.plot(df_run_curves_ga_60["Iteration"],df_run_curves_ga_60["Fitness"], label="GA", color="green") plt.plot(df_run_curves_mimic_60["Iteration"],df_run_curves_mimic_60["Fitness"], label="MIMIC", color="yellow") plt.title("Flip Flop Fitness vs iterations - Size 60 - Max Attempts 200") plt.xlabel("Iterations") plt.ylabel("Fitness Score") plt.legend() plt.show()
图表情况说明
- 原图表:X轴按线性刻度分布,0-500区间占比极小,该区间数据展示模糊
- 代码生成的图表:X轴刻度被强制均匀排列,但实际对应迭代值的间隔差异极大,导致曲线形态失真
解决方案:实现非线性X轴缩放
你的需求本质是自定义X轴的刻度比例,通过将原始X值映射到均匀分布的刻度位置即可实现,以下提供两种可行方法:
方法1:手动映射X值(简单直接)
import matplotlib.pyplot as plt # 定义目标刻度点和对应的均匀位置 target_ticks = [0, 100, 200, 300, 400, 500, 2000, 3000] tick_positions = range(len(target_ticks)) # 编写映射函数,处理原始X值到刻度位置的转换(含线性插值) def map_x(x_val): for i in range(len(target_ticks)-1): if target_ticks[i] <= x_val <= target_ticks[i+1]: ratio = (x_val - target_ticks[i]) / (target_ticks[i+1] - target_ticks[i]) return tick_positions[i] + ratio * (tick_positions[i+1] - tick_positions[i]) # 处理超出刻度范围的情况 if x_val > target_ticks[-1]: ratio = (x_val - target_ticks[-1])/(target_ticks[-1]-target_ticks[-2]) return tick_positions[-1] + ratio*(tick_positions[-1]-tick_positions[-2]) return tick_positions[0] fig, ax = plt.subplots() # 对每条曲线的X值做映射后绘图 ax.plot([map_x(x) for x in df_run_curves_rhc_60["Iteration"]], df_run_curves_rhc_60["Fitness"], label="RHC", color="blue") ax.plot([map_x(x) for x in df_run_curves_sa_60["Iteration"]], df_run_curves_sa_60["Fitness"], label="SA", color="orange") ax.plot([map_x(x) for x in df_run_curves_ga_60["Iteration"]], df_run_curves_ga_60["Fitness"], label="GA", color="green") ax.plot([map_x(x) for x in df_run_curves_mimic_60["Iteration"]], df_run_curves_mimic_60["Fitness"], label="MIMIC", color="yellow") # 设置X轴刻度和标签 ax.set_xticks(tick_positions) ax.set_xticklabels(target_ticks) plt.title("Flip Flop Fitness vs iterations - Size 60 - Max Attempts 200") plt.xlabel("Iterations") plt.ylabel("Fitness Score") plt.legend() plt.show()
方法2:使用Matplotlib自定义缩放类(更规范)
通过自定义Transform实现可复用的非线性缩放:
import matplotlib.pyplot as plt from matplotlib.scale import FuncScale from matplotlib.transforms import Transform class CustomXTransform(Transform): input_dims = 1 output_dims = 1 is_separable = True def __init__(self, target_ticks): super().__init__() self.target_ticks = target_ticks self.tick_positions = range(len(target_ticks)) def transform_non_affine(self, x): result = [] for x_val in x: found = False for i in range(len(self.target_ticks)-1): if self.target_ticks[i] <= x_val <= self.target_ticks[i+1]: ratio = (x_val - self.target_ticks[i]) / (self.target_ticks[i+1] - self.target_ticks[i]) result.append(self.tick_positions[i] + ratio * (self.tick_positions[i+1] - self.tick_positions[i])) found = True break if not found: if x_val > self.target_ticks[-1]: ratio = (x_val - self.target_ticks[-1])/(self.target_ticks[-1]-self.target_ticks[-2]) result.append(self.tick_positions[-1] + ratio*(self.tick_positions[-1]-self.tick_positions[-2])) else: result.append(self.tick_positions[0]) return result def inverted(self): # 实现反向转换,支持图表交互功能 class InvertedCustomXTransform(Transform): def __init__(self, parent): super().__init__() self.parent = parent def transform_non_affine(self, pos): result = [] for p in pos: found = False for i in range(len(self.parent.tick_positions)-1): if self.parent.tick_positions[i] <= p <= self.parent.tick_positions[i+1]: ratio = (p - self.parent.tick_positions[i]) / (self.parent.tick_positions[i+1] - self.parent.tick_positions[i]) result.append(self.parent.target_ticks[i] + ratio*(self.parent.target_ticks[i+1]-self.parent.target_ticks[i])) found = True break if not found: if p > self.parent.tick_positions[-1]: ratio = (p - self.parent.tick_positions[-1])/(self.parent.tick_positions[-1]-self.parent.tick_positions[-2]) result.append(self.parent.target_ticks[-1] + ratio*(self.parent.target_ticks[-1]-self.parent.target_ticks[-2])) else: result.append(self.parent.target_ticks[0]) return result def inverted(self): return self.parent return InvertedCustomXTransform(self) # 注册自定义缩放类型 FuncScale.register_custom_scale('custom_x', CustomXTransform) fig, ax = plt.subplots() # 应用自定义X轴缩放 ax.set_xscale('custom_x', target_ticks=[0,100,200,300,400,500,2000,3000]) # 直接使用原始X值绘图即可 ax.plot(df_run_curves_rhc_60["Iteration"],df_run_curves_rhc_60["Fitness"], label="RHC", color="blue") ax.plot(df_run_curves_sa_60["Iteration"],df_run_curves_sa_60["Fitness"], label="SA", color="orange") ax.plot(df_run_curves_ga_60["Iteration"],df_run_curves_ga_60["Fitness"], label="GA", color="green") ax.plot(df_run_curves_mimic_60["Iteration"],df_run_curves_mimic_60["Fitness"], label="MIMIC", color="yellow") plt.title("Flip Flop Fitness vs iterations - Size 60 - Max Attempts 200") plt.xlabel("Iterations") plt.ylabel("Fitness Score") plt.legend() plt.show()
内容的提问来源于stack exchange,提问作者Dennis Cafiero
相关产品推荐
相关产品推荐

