Matplotlib绘图出现异常水平线,求解决方法
修复Matplotlib折线图中的异常水平线问题
使用Matplotlib绘制三条分属不同expedice的折线时,图表出现了异常的水平线,原代码如下:
import pandas as pd import matplotlib.pylab as plt df = pd.read_csv("balici_naskladnovaci.csv") df = df.sort_values(by = "interval start") df["interval start"] = pd.to_datetime(df["interval start"]) # balici fig, ax = plt.subplots() ax.plot( df[df["expedice"] == "liberec"]["interval start"].astype(str), df[df["expedice"] == "liberec"]["balici"], color="red", label="Liberec", ) ax.plot( df[df["expedice"] == "jablonec"]["interval start"].astype(str), df[df["expedice"] == "jablonec"]["balici"], color="blue", label="Jablonec", ) ax.plot( df[df["expedice"] == "lipa"]["interval start"].astype(str), df[df["expedice"] == "lipa"]["balici"], color="green", label="Lípa", ) ax.set_ylabel("Počet baličů", color="black", fontsize=14) plt.title("Balici napric expedicemi") plt.tight_layout() fig.legend() plt.show()
问题原因
异常水平线的根源是将datetime类型的x轴数据强制转换成了字符串。不同expedice对应的时间点可能不完整,当把时间转为字符串后,Matplotlib会将所有字符串按顺序作为x轴刻度,但每个子集的时间序列只包含部分刻度,缺失的位置会被自动填充并强制连接,从而出现横跨图表的无效水平线。
修复方案
方案1:直接使用datetime类型作为x轴
去掉astype(str)转换,让Matplotlib直接处理datetime类型的数据,这样每个折线只会在自身存在的时间点上绘制,不会出现无效连接:
import pandas as pd import matplotlib.pylab as plt df = pd.read_csv("balici_naskladnovaci.csv") df = df.sort_values(by = "interval start") df["interval start"] = pd.to_datetime(df["interval start"]) # balici fig, ax = plt.subplots() # 移除astype(str),直接传入datetime列作为x轴 ax.plot( df[df["expedice"] == "liberec"]["interval start"], df[df["expedice"] == "liberec"]["balici"], color="red", label="Liberec", ) ax.plot( df[df["expedice"] == "jablonec"]["interval start"], df[df["expedice"] == "jablonec"]["balici"], color="blue", label="Jablonec", ) ax.plot( df[df["expedice"] == "lipa"]["interval start"], df[df["expedice"] == "lipa"]["balici"], color="green", label="Lípa", ) ax.set_ylabel("Počet baličů", color="black", fontsize=14) plt.title("Balici napric expedicemi") plt.xticks(rotation=45) # 可选:旋转x轴标签避免重叠 plt.tight_layout() fig.legend() plt.show()
方案2:用pivot_table重构数据,简化绘图逻辑
将长格式数据转为宽格式,让每个expedice作为单独的列,这样可以一次性绘制所有折线,同时从根源避免子集时间不匹配的问题:
import pandas as pd import matplotlib.pylab as plt df = pd.read_csv("balici_naskladnovaci.csv") df["interval start"] = pd.to_datetime(df["interval start"]) df = df.sort_values(by="interval start") # 将数据重构为宽格式:时间作为索引,expedice作为列 pivot_df = df.pivot_table( index="interval start", columns="expedice", values="balici", aggfunc="first" # 若同一时间点有多个值,可根据需求调整聚合方式 ) fig, ax = plt.subplots() # 一次性绘制所有折线 pivot_df.plot(ax=ax, color=["red", "blue", "green"]) ax.set_ylabel("Počet baličů", color="black", fontsize=14) plt.title("Balici napric expedicemi") plt.xticks(rotation=45) plt.tight_layout() plt.show()
内容的提问来源于stack exchange,提问作者vojtam
相关产品推荐
相关产品推荐

