看过来
《pandas 教程》 持续更新中,提供建议、纠错、催更等加作者微信: gairuo123(备注:pandas教程)和关注公众号「盖若」ID: gairuo。跟作者学习,请进入 Python学习课程。欢迎关注作者出版的书籍:《深入浅出Pandas》 和 《Python之光》。
2022 年的三伏天,从初伏的7月16日,到末伏8月24日,持续共40天。这 40 天是一年当中暑气最盛,气温最高,天气最热的时节,实在让人难受。会写 Python 的我计划写一个三伏天日历,数着日子度过这些天。
三伏天发生在 7 月和 8 月,因此我们只要画出这两个月就可以了,然后在日历上对三伏天的日期加了橙色背景,今天加上黄色背景。
效果如下:
接下来,就让我们一起学习怎么制作吧!
总体思路呢是在 jupyter lab 上编写,利用 pandas 的 DataFrame style 对象的方法对表格样式进行调整。
Python 的内置库 calendar 可以生成 html 格式的月份日历,再用 pd.read_html() 读取数据。
import calendar
c = calendar.HTMLCalendar()
fm7 = c.formatmonth(2022, 7, withyear=False)
fm8 = c.formatmonth(2022, 8, withyear=False)
fm7
'''
'<table border="0" cellpadding="0" cellspacing="0"
class="month">\n<tr><th colspan="7"
class="month">July</th></tr>\n<tr>
<th class="mon">Mon</th><th class="tue">Tue</th>
<th class="wed">Wed</th><th class="thu">Thu</th>
<th class="fri">Fri</th><th class="sat">Sat</th>
<th class="sun">Sun</th></tr>\n<tr>
<td class="noday"> </td><td class="noday">
...
<td class="sat">30</td><td class="sun">31
</td></tr>\n</table>\n'
'''
以上 fm7、fm8 分别是七月和八月的 HTML 表格日历。默认 withyear 为真,则年份将会显示在表头,否则只显示月份,这里我们不需要显示年份,设置为 False。
可以在 jupyter lab 上查看一下 html 的效果:
from IPython.display import display, HTML
display(HTML(fm7))
接下来用 pd.read_html() 读取数据。将两个月份的 html 拼接起来,pd.read_html() 读取 html 得到的是一个 DataFrame 列表,用 pd.concat() 连接起来,再做一些缺失值填充格式转换工作。
df = (
pd.concat(pd.read_html(fm+fm8), axis=1)
.fillna(0)
.astype(int)
.replace(0, pd.NA)
)
输出结果为:
df
'''
July August
Mon Tue Wed Thu Fri Sat Sun Mon Tue Wed Thu Fri Sat Sun
0 <NA> <NA> <NA> <NA> 1 2 3 1 2 3 4 5 6 7
1 4 5 6 7 8 9 10 8 9 10 11 12 13 14
2 11 12 13 14 15 16 17 15 16 17 18 19 20 21
3 18 19 20 21 22 23 24 22 23 24 25 26 27 28
4 25 26 27 28 29 30 31 29 30 31 <NA> <NA> <NA> <NA>
'''
这样就得到了两个月份的日历表,接下来进行样式调整。
此步利用 pandas 的 DataFrame style 对象的方法对表格样式进行调整。由于要显示当天日期的背景色,先定义一个日期变量:
now = pd.Timestamp.now()
now
# Timestamp('2022-07-19 14:39:21.983747')
now.day # 日期数字
# 19
now.month_name() # 月份字符串
# 'July'
定义背景颜色的 css 样式变量:
orange = "background-color: orange"
yellow = "background-color: yellow"
none_ = "background-color: None"
定义几个匿名函数,用于表达添加背景色的逻辑:
july_func = lambda x: orange if x is not pd.NA and x>=16 else none_
august_func = lambda x: orange if x is not pd.NA and x<=24 else none_
today_func = lambda x: yellow if x is not pd.NA and x==now.day else none_
最后应用上边的匿名函数,applymap 可以对所有值一一判断并对单元格赋于 css 样式,它的 subset 参数可以将应用函数的范围锁定在指定的列下,列的第一层则是我们的月份名称。
代码如下:
(
df.style
.applymap(july_func, subset=['July'])
.applymap(august_func, subset=['August'])
.applymap(today_func, subset=now.month_name())
)
就得到了结果:
以上写法有点繁琐,我们可以将设置样式封装为一个函数:
def set_style(val, logic, color):
color = f"background-color: {color}"
if val is not pd.NA and eval(f'{val}{logic}'):
style = color
else:
style = "background-color: none"
return style
调用函数:
(
df.style
.applymap(set_style, logic='>=16', color='orange', subset=['July'])
.applymap(set_style, logic='<=24', color='orange', subset=['August'])
.applymap(set_style, logic=f'=={now.day}', color='yellow', subset=now.month_name())
)
这样就得到了最终效果。
(完)
更新时间:2024-08-18 16:01:25 标签:pandas python 可视化 日期