You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Matplotlib习惯追踪:如何在X轴绘制隐藏式统计折线?

解决Matplotlib习惯追踪折线的误显示问题

我完全get到你的痛点——那条汇总每日完成习惯数的折线,在当天没有完成任何习惯时,不该停留在Y=0(也就是"Retainer"对应的位置),这很容易让人误以为你完成了这个习惯对吧?而且你不想改动Matplotlib的自动缓冲设置,只想让无完成数据的折线部分藏起来,别在X轴上方显示。

问题根源

原来的代码里,当当天没有完成任何习惯时,completed列表对应的数值是0,而你的Y轴刻度0正好对应"Retainer",所以折线会落在这个位置,造成误解。我们需要把这些无完成的点的Y值设置到Y轴可见范围之外,这样它们就会自动被隐藏,不会出现在图里。

解决方案

修改计算每日完成总数的逻辑:当当天完成数为0时,把Y值设为-1(这个值低于Y轴的最小可见刻度0),有完成数时保持原来的总数。这样Matplotlib的自动缓冲不会影响这个设置,因为这些点在视图范围外,不会被显示出来。

下面是修改后的完整代码:

import matplotlib.pyplot as plt
import calendar
import datetime
import atexit

def main():
    global trackers
    activities = ["Retainer","Steps Goal","Drink Water","6+ Hours Sleep","<=2 Sodas","Study","Leave Campus","Clean","Mike","Paint","Phone Call","Saw Friends","UAS"]
    trackers = []
    completed = []
    days_in_month = calendar.monthrange(int(str(datetime.datetime.now())[0:4]),int(str(datetime.datetime.now())[5:7]))[1]
    current_day = int(str(datetime.datetime.now())[8:11])
    
    # 读取trackers.txt数据
    with open("trackers.txt","r") as file:
        data = file.readlines()
    for i in range(len(data)):
        data[i] = data[i].rstrip("\n").rstrip(",").rstrip("")
        trackers.append(data[i].split(","))
    for b in range(len(trackers[-1])):
        trackers[-1][b] = int(trackers[-1][b])
    print("Trackers Loaded")
    
    plt.switch_backend('TkAgg')
    
    # 修正:计算每日完成数,0完成时设为-1
    for i in range(days_in_month):
        total_completed = 0
        for b in range(len(trackers)):
            total_completed += int(trackers[b][i])  # 确保是整数相加
        # 无完成时设为-1,否则保留总数
        completed.append(total_completed if total_completed > 0 else -1)
    
    plt.plot(tuple([i for i in range(days_in_month)]), tuple(completed),c = "k")
    plt.axvline(x=current_day - 1, c="#ccf3ff", linewidth = 30, zorder = -1)
    plt.grid()
    plt.title("Habit Tracker")
    plt.yticks([i for i in range(len(trackers))],tuple(activities))
    plt.xticks([i for i in range(days_in_month)],[i for i in range(1,days_in_month + 1)])
    
    # 绘制每个习惯的完成标记
    for i in range(len(trackers)):
        for b in range(days_in_month):
            if trackers[i][b] == 1:
                plt.plot(b,i,"rs", markersize = 8)
            else:
                plt.plot(b,i,"s", color = "#d2d2d2", markersize = 8)
    
    mng = plt.get_current_fig_manager()
    mng.window.state('zoomed')
    plt.show()
    return

@atexit.register
def exit():
    with open("trackers.txt","w") as file:
        for i in range(len(trackers)):
            for b in range(len(trackers[i])):
                file.write(str(trackers[i][b]) + ",")
            file.write("\n")
    print("Trackers Saved")

if __name__ == "__main__":
    main()

配套的trackers.txt内容(确保末尾有空行)

0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,

额外优化说明

我还顺手做了两个小优化:

  • 用with语句处理文件读写,更安全也更符合Python最佳实践
  • 在计算total_completed时显式转换为整数,避免潜在的类型问题

这样修改后,没有完成任何习惯的日子,折线会跑到X轴下方(Y=-1),不在你的视图范围内,不会被显示出来;有完成数的日子,折线会正常显示在对应的完成数量高度,完全符合你的需求,而且不需要修改Matplotlib的自动缓冲设置。

内容的提问来源于stack exchange,提问作者Conrad Selig

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:51:14