Pandas绘图X轴显示UTC而非EDT时区问题求助
解决Matplotlib时间轴时区显示问题(Apple Health心率数据)
我正在为生活日志制作每日心率记录图表,使用Python处理Apple Health导出的数据,代码如下:
period = datetime.today().date() - timedelta(days=1) archive = zipfile.ZipFile("/Users/steven/Downloads/export.zip", "r") df = pd.read_xml( archive.open("apple_health_export/export.xml"), xpath="//Record", attrs_only=True, parse_dates=["creationDate", "startDate", "endDate"], ) d1 = df[ (df["endDate"].dt.date == period) & (df["type"] == "HKQuantityTypeIdentifierHeartRate") ] d1["value"] = [pd.to_numeric(x) for x in d1["value"]] plt.style.use("ggplot") plt.rcParams["font.family"] = "PT Sans" d1.sort_values(by="endDate").plot( x="endDate", y="value", xlabel="Time", ylabel="Heart Rate (BPM)", title="Heart Rate, Intraday", ).xaxis.set_major_formatter(mdates.DateFormatter("%-I:%M %p")) plt.tight_layout() plt.savefig( f"/Users/steven/Library/Mobile Documents/com~apple~CloudDocs/Web/gloriouslyawkwardlife.github.io/images/{period}-heartrateintraday.png", format="PNG", )
目前遇到的问题是:图表X轴显示UTC时区时间,而非EDT(GMT-4)时区,尽管原始数据的endDate字段是EDT时区。尝试用df['endDate']=df['endDate'].dt.tz_convert(pytz.timezone('America/New_York'))显式转换时区,但未解决问题。去掉X轴格式化代码后时区显示正确,但时间格式不符合需求,求解决方案。
解决方案
问题根源在于mdates.DateFormatter默认不会识别datetime对象的时区信息,直接采用UTC时间格式化。以下两种方法可解决:
方法1:为DateFormatter指定时区
显式告诉格式化器使用EDT时区解析时间:
import pytz from matplotlib.dates import DateFormatter # 确保数据的endDate已转换为EDT时区 d1['endDate'] = d1['endDate'].dt.tz_convert(pytz.timezone('America/New_York')) # 绘图并配置带时区的格式化器 ax = d1.sort_values(by="endDate").plot( x="endDate", y="value", xlabel="Time", ylabel="Heart Rate (BPM)", title="Heart Rate, Intraday", ) # 创建格式化器时传入时区参数 formatter = DateFormatter("%-I:%M %p", tz=pytz.timezone('America/New_York')) ax.xaxis.set_major_formatter(formatter) # 后续保存代码不变 plt.tight_layout() plt.savefig( f"/Users/steven/Library/Mobile Documents/com~apple~CloudDocs/Web/gloriouslyawkwardlife.github.io/images/{period}-heartrateintraday.png", format="PNG", )
方法2:转换为本地时区的无时区datetime
将带时区的datetime转换为EDT本地时间后移除时区信息,直接用naive时间格式化:
import pytz # 转换为EDT时区并移除时区标记 d1['endDate_local'] = d1['endDate'].dt.tz_convert(pytz.timezone('America/New_York')).dt.tz_localize(None) # 使用本地时间列绘图并格式化 ax = d1.sort_values(by="endDate_local").plot( x="endDate_local", y="value", xlabel="Time", ylabel="Heart Rate (BPM)", title="Heart Rate, Intraday", ) ax.xaxis.set_major_formatter(mdates.DateFormatter("%-I:%M %p")) # 后续保存代码不变 plt.tight_layout() plt.savefig( f"/Users/steven/Library/Mobile Documents/com~apple~CloudDocs/Web/gloriouslyawkwardlife.github.io/images/{period}-heartrateintraday.png", format="PNG", )
关键说明
pd.read_xml解析的endDate若包含时区,会生成带时区的datetime64[ns, tz]类型,DateFormatter默认忽略时区信息,需手动指定或转换为本地时间。- 方法1保留时区元数据,适合需后续时区操作的场景;方法2更简洁,仅用于本地时间显示。
内容的提问来源于stack exchange,提问作者Steven Buehler
相关产品推荐
相关产品推荐

