作为一个老年多动症患者,在学习的时候走思去刷刷朋友圈看看B站动态似乎很难避免。明明脑子里还在思考着眼前MOOC的内容,但手却情不自禁的点开网页打开了知乎 (。≖ˇェˇ≖。)
为了改掉自己的这个毛病,我找到了手机上的Forest APP。这是一个简单好用的计时APP,当自己在学习的时候设定一个45分钟的时钟,这样在手情不自禁打开知乎的时候就会想到那个倒计时的时钟,阻止自己在走神的路上越走越远(๑•̀ㅂ•́)و✧
这个APP的计时功能是很好用,但我不是很喜欢它的统计页面:
这样的统计界面虽然看起来很好看,但却过于简陋了,并没有提供我们过多的信息。不会使用Excel的我,只好尝试使用Python解决这一问题了ヽ(✿゚▽゚)ノ
import matplotlib.pyplot as plt
import json
import datetime
MOUTH = 3
FILENAME = 'DataOfMouth{}.json'.format(MOUTH)
这段代码是我们需要的库以及两个全局变量。
我们需要matplotlib库来画图,也需要json库来帮助我们保存数据。datetime让我们能方便的获得今天的时间,从而为我们的表格添加一些新内容。
由于我决定一次性绘制一个月的信息,所以我们指定一个变量MOUTH存储月份,我们想改变的时候也能快速的改变。我们在指定存储数据的文件时使用了format方法,在文件名中体现了月份信息。
3. 第一个函数:接受输入def StartAndReceiveInfo():
'用于获取数据输入,对数据的准确性进行判断。'
print('\n在输入数据前请确保您的数据是正确的,否则将产生不必要的后果. . . . . . \n')
date_temp = int(input('请输入今天的日期:'))
time_temp = int(input('请输入时长/分钟:'))
print('\n请检查输入数据 . . . . . .\n')
flag = int(input('若确定,请输入1;否则输入0:'))
assert flag == 1,'请重启程序,确保数据正确性。'
return date_temp,time_temp
这是我们的第一个函数。
其中的一些print()函数用来提醒自己输入数据时一定要准确。除了这些print()语句外,我们用了两个变量存储输入的日期和时长,例如APP上显示了今天的工作的时长是185分钟,那么我们就可以按照提示输入今天的信息和工作的时长。
之后我们又设置了一个强制的检查工作,要求用户检查一遍确认无误后输入1,再使用一个断言,保证在数据错误的时候能抛出Error、保证数据文件的正确性。
经过一些简单的检查,这个函数将返回获得的数据。
3. 第二个函数:初始化数据文件def Initialize():
'用于初始化记录。'
datas_dict = {}
keys = [key for key in range(1,32)]
values = [0 for _ in range(1,32)]
for i in range(0,31):
datas_dict[keys[i]] = values[i]
with open(FILENAME,'x') as f_obj:
f_obj.write(json.dumps(datas_dict))
如果我们第一次运行程序,或者换了一个月份,这些情况下我们实际上是没有数据文件的。我们需要进行一个简单的初始化。Python为我们提供了方便的散列表——字典类型。我们生成两个列表作为字典的键与值,其中,键自然是从1到31,对应了一个月的所有天数,而值在初始化的时候我们都设置为0。我们使用循环将这两个列表组合成字典。
之后,我们使用json库提供的dumps函数将字典转化为JSON文件格式,再写入到我们全局变量定义的路径的文件下。
4. 第三个函数:更新数据文件def SaveData(today,time):
'用于将单次输入的数据记录在文件中。'
try:
with open(FILENAME) as f_obj:
pass
except FileNotFoundError:
Initialize()
with open(FILENAME,'r') as f_obj:
datas_dict = json.loads(f_obj.read())
datas_dict[str(today)] = time
with open(FILENAME,'w') as f_obj:
f_obj.write(json.dumps(datas_dict))
return datas_dict
首先,我们用一个try-except语句来尝试打开全局变量指定的路径的文件,如果抛出错误,说明我们需要进行一步初始化。这个结构帮助我们快速完成工作。
之后,我们将JSON格式的数据文件打开,使用json库提供的loads函数将其中存储的JSON格式的字典转换为Python格式,然后将函数的输入——输入的日期和对应的时间写入到字典。由于进行了JSON格式的转化,此时的字典的键是str类型,为了成功更新数据,我们也要将输入的日期转化为str格式。
更新完成后,我们将其重新写入数据文件中,同时利用return语句将字典传给其它函数。
5. 最后一个函数:绘图这个函数看起来比较长,但其中涉及了matplotlib的基本用法,值得一读。我们将其分开展示:
def PlotChart(datas_dict):
'将数据绘制成图表。'
times_temp = list(datas_dict.values())
dates = list(datas_dict.keys())
times = [times_temp[i] / 60.0 for i in range(len(times_temp))]
all_time = sum(times)
max_time = max(times)
首先,我们将输入函数的字典分成两个列表,列表中分别包含了键与值,这是为绘图做准备。
同时,我们决定使用更加直观的小时表示时间,所以对值得列表用了除法。最后,我们使用sum()函数和max()函数来获得总的时间以及最大的时间,用来丰富图表信息。
plt.figure(figsize=(20,10))
plt.hlines(max_time, -1, 32,color='darkred',alpha=0.8,linestyle='-.')
plt.text(x=-0.8,y=max_time,s='MAX',color='darkred',alpha=5)
plt.hlines(8,-1,32,color='red',alpha=5,linestyle='-.')
plt.text(x=-0.5,y=8.3,s='8h',color='red',alpha=5)
plt.hlines(12,-1,32,color='red',alpha=5,linestyle='-.')
plt.text(x=-0.8,y=12.3,s='12h',color='red',alpha=5)
plt.plot(dates,times,color='deeppink',linestyle='--',marker='o',alpha=0.5)
for date,time in zip(dates,times):
plt.text(x=eval(date)-1.5,y=time+0.3,s='%.2f'%time,color='deeppink',alpha=1)
然后我们开始绘图:首先我们使用了figur函数创建了画布并在其中指定了画布大小,由于我们要展示一个月的数据,所以应该让画布尽量大一些。之后,我们要绘制一系列的水平线,使用hlines函数即可。我们分别在8、12以及最大时间处绘制了水平线,并指定了颜色参数color、透明度参数alpha以及线的形状参数linestyle。同时,我们也使用了text函数在水平线的附近标注了其含义。
完成这些用于丰富信息的工作之后,我们使用折线图绘制主要的内容:日期以及对应的工作时间,并且通过一个循环使用text函数来标记上对应的时间信息。为了使得标注的信息清楚,我们在指定其坐标是加上了一些值用来偏移、防止折现挡住文字。
其实,图表的主要部分是由上面的最后三行代码完成的,其它的只是一些信息的增添——不过这种可定制也是Python的乐趣。
now = datetime.date.today()
plt.hlines(datas_dict[str(now.day)]/60.0,-1,32,color='orange',alpha=2,linestyle='-.')
plt.text(x=-0.8,y=datas_dict[str(now.day)]/60.0,s='TODAY',color='orange',alpha=5)
plt.scatter(str(now.day),datas_dict[str(now.day)]/60.0,color='orange')
接下来,我们又绘制了一条水平线,是今天的工作时长。我们使用datetime库获得今天的日期:其中的date.totay()给我们返回今天的日期信息对象,而对象的day属性则返回了今天的日期。在进行文字标注后,我们使用用来绘制散点的scatter函数将折线上今天的时间点加重。
plt.xlabel('dates')
plt.ylabel('time')
plt.axis([-1,32,-1,16])
plt.title('YOU HAVE WORK {:.2f}HOURS IN MOUTH{}'.format(all_time,MOUTH))
plt.grid(True)
plt.savefig('ComeOn.png')
plt.show()
最后,我们指定横坐标与纵坐标的标签、限制坐标范围以及指定图表标签。我们之前求了总的时间,图表的标题展现了这个信息。为了美观,我们将图表设置了网格。
剩下的工作只需要将这个图表保存以便我们可以方便的查看,同时使用show函数展示图片,同时将画布释放。
6. 最后的代码if __name__ == "__main__":
today,time = StartAndReceiveInfo()
datas_dict = SaveData(today,time)
PlotChart(datas_dict)
我们的函数之间的串联很简单,只需要三行代码。最终代码如下:
import matplotlib.pyplot as plt
import json
import datetime
MOUTH = 3
FILENAME = 'DataOfMouth{}.json'.format(MOUTH)
def StartAndReceiveInfo():
'用于获取数据输入,对数据的准确性进行判断。'
print('\n在输入数据前请确保您的数据是正确的,否则将产生不必要的后果. . . . . . \n')
date_temp = int(input('请输入今天的日期:'))
time_temp = int(input('请输入时长/分钟:'))
print('\n请检查输入数据 . . . . . .\n')
flag = int(input('若确定,请输入1;否则输入0:'))
assert flag == 1,'请重启程序,确保数据正确性。'
return date_temp,time_temp
def Initialize():
'用于初始化记录。'
datas_dict = {}
keys = [key for key in range(1,32)]
values = [0 for _ in range(1,32)]
for i in range(0,31):
datas_dict[keys[i]] = values[i]
with open(FILENAME,'x') as f_obj:
f_obj.write(json.dumps(datas_dict))
def SaveData(today,time):
'用于将单次输入的数据记录在文件中。'
try:
with open(FILENAME) as f_obj:
pass
except FileNotFoundError:
Initialize()
with open(FILENAME,'r') as f_obj:
datas_dict = json.loads(f_obj.read())
datas_dict[str(today)] = time
with open(FILENAME,'w') as f_obj:
f_obj.write(json.dumps(datas_dict))
return datas_dict
def PlotChart(datas_dict):
'将数据绘制成图表。'
times_temp = list(datas_dict.values())
dates = list(datas_dict.keys())
times = [times_temp[i] / 60.0 for i in range(len(times_temp))]
all_time = sum(times)
max_time = max(times)
plt.figure(figsize=(20,10))
plt.hlines(max_time, -1, 32,color='darkred',alpha=0.8,linestyle='-.')
plt.text(x=-0.8,y=max_time,s='MAX',color='darkred',alpha=5)
plt.hlines(8,-1,32,color='red',alpha=5,linestyle='-.')
plt.text(x=-0.5,y=8.3,s='8h',color='red',alpha=5)
plt.hlines(12,-1,32,color='red',alpha=5,linestyle='-.')
plt.text(x=-0.8,y=12.3,s='12h',color='red',alpha=5)
plt.plot(dates,times,color='deeppink',linestyle='--',marker='o',alpha=0.5)
for date,time in zip(dates,times):
plt.text(x=eval(date)-1.5,y=time+0.3,s='%.2f'%time,color='deeppink',alpha=1)
now = datetime.date.today()
plt.hlines(datas_dict[str(now.day)]/60.0,-1,32,color='orange',alpha=2,linestyle='-.')
plt.text(x=-0.8,y=datas_dict[str(now.day)]/60.0,s='TODAY',color='orange',alpha=5)
plt.scatter(str(now.day),datas_dict[str(now.day)]/60.0,color='orange')
plt.xlabel('dates')
plt.ylabel('time')
plt.axis([-1,32,-1,16])
plt.title('YOU HAVE WORK {:.2f}HOURS IN MOUTH{}'.format(all_time,MOUTH))
plt.grid(True)
plt.savefig('ComeOn.png')
plt.show()
if __name__ == "__main__":
today,time = StartAndReceiveInfo()
datas_dict = SaveData(today,time)
PlotChart(datas_dict)
这样,在每天完成学习任务后,利用自己的计时APP获得一天的工作时间,我们可以打开这个程序,输入自己的信息,获得统计图表。第一次使用,图表可能有些单薄,但使用时间长一点之后,这个图表能很好的反映我们的学习情况,激励我们去多学一点时间。Python提供的更多功能也能帮我们完善这个图表: