程序员用Python给了女友一个七夕惊喜!

Python爬虫与数据挖掘

共 10583字,需浏览 22分钟

 · 2021-08-16

点击上方“Python爬虫与数据挖掘”,进行关注

回复“书籍”即可获赠Python从入门到进阶共10本电子书

烽火连三月,家书抵万金。

hi,大家好,我是朱小五

七夕(各种节日、纪念日)又快到啦,程序员(怎么会不是单身呢)又要想招来哄女友啦?

想必大家都知道各种各样的代码式浪漫,比如定制的二维码,让女友扫码后进入一个定制的 h5 页面,那么这个页面里可以放的内容是——

这个是空的,只是展示一下

回忆,是经典的选项。该如何呈现回忆呢?

不难想到可以用 js 来实现各种动画效果,直接 copy 各种库组合组合是不错,但亲力亲为还是需要经过精心设计,操作起来有一定的难度。

这里给大家提供一个简单的点子,用 python 来制作酷炫的动态条形图,展示你们在一起的历程吧!

例子如下:

一、动态条形图

首先,不妨猜想一下这个是如何实现的。动画即是一帧一帧静态画面的连续播放,所以我们只需要将每一天都画一次图,再拼成 GIF 即可。

如下为第一天和最后一天的条形图:

再来看一下用于画图的每日数据,假设2020年1月1日为起始日期,1月20日为当天(即发布供检阅的)日期,故要对这些数据画20次图(别怕,兄dei)。

进入代码环节:先按需求读取数据(读表最爱的 pandas 库又出现啦)。为了便于处理日期,将 excel 中的日期一列的值转为字符串格式,再利用 datatime 将起始日期设为时间戳格式。

import pandas as pd
import datetime

df = pd.read_excel("数据.xlsx")
df['日期文本'] = df['日期'].apply(lambda x: str(x)[:10])
t = datetime.datetime(2020,1,1# 起始日期

选择 matplotlib 库进行绘图:先设置画布,返回模型和画图对象。接着不要忘记设置字体以避免中文显示异常。因为有3个项目需要区分上色,因此再创建一个颜色列表,可以自行百度喜欢的颜色代码。

import matplotlib.pyplot as plt

fig, ax = plt.subplots(figsize=(10,6)) # 画布
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'# 字体设为微软雅黑
colors = ['#ADD8E6''#DC143C''#FFC0CB'# 颜色列表

编写绘图函数:传入的参数是对于起始日期所经过的天数。通过 t + datetime.timedelta(days=date) 计算需要绘制的指定天数的日期,再利用 strftime("%Y-%m-%d") 将其还原为日期文本,然后通过该日期文本取出当天的数据存入新的 df_ 中。下一步即为通过 barh 方法绘制条形图,且每次画新图前需清空上一次的图像。

def draw(date):
    # 数据处理 ------
    current_date = (t + datetime.timedelta(days=date)).strftime("%Y-%m-%d")
    df_ = df[df['日期文本'].eq(current_date)]
    days = df_['天数']
    item = df_["项目"]
    # 绘制条形图 ------
    ax.clear() # 重绘
    # for i in range(1,len(itme.uni))
    ax.barh(item, days, color = colors)

如此之后,调用 draw(19) 来画出经过19天后,也就是第20天的图像,通过 plt.show() 临时查看一下。

和最终效果图还有一定的差距,多了坐标轴标签,少了系列标签、数据标注和右上角的滚动时间。继续完善 draw 函数:

for y, (x,name) in enumerate(zip(days.values,item.values)): # 系列标注
        ax.text(x, y, "%s" % x, size=12)
        if x > 1:
            ax.text(x-0.5, y, name, size=14, ha = 'right')
ax.text(11.01, current_date, transform = ax.transAxes, size= 20, ha='right'# 滚动时间
ax.get_xaxis().set_visible(False# 隐藏坐标轴
ax.get_yaxis().set_visible(False)

接下来就是用 for 循环画出20张图并通过 plt.savefig('xxx.png') 一一保存,再使用 imageio 库或其他图像工具来合成 gif 啦!

不不不,慢着慢着)如果真要这样做就太麻烦了,下面该祭出这次的主角了!

import matplotlib.animation as ani

matplotlib 库提供了动态绘图的模块,可以帮助我们更加轻松的制作 gif。只需传入模型、绘图函数、和一个 int 类型的列表即可,因此最初设计 draw 函数时所需的参数是天数 dateinterval 参数为绘制每张图的时间间隔,用于在 plt.show() 中检查效果。最终保存 gif 图像时可以通过 fps 参数设置帧数。

timeSlot = [x for x in range(0,20)] # 时间轴
animator = ani.FuncAnimation(fig, draw, frames=timeSlot ,interval = 100)
animator.save('test.gif',fps=10)

附完整代码:

import matplotlib.pyplot as plt
import matplotlib.animation as ani
import pandas as pd
import datetime

df = pd.read_excel("数据.xlsx")
df['日期文本'] = df['日期'].apply(lambda x: str(x)[:10])
t = datetime.datetime(2020,1,1# 起始日期
fig, ax = plt.subplots(figsize=(10,6)) # 画布
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'# 字体设为微软雅黑
timeSlot = [x for x in range(0,20)] # 时间轴
colors = ['#ADD8E6''#DC143C''#FFC0CB'# 颜色列表

def draw(date):
    print(date)
    # 数据处理 ------
    current_date = (t + datetime.timedelta(days=date)).strftime("%Y-%m-%d")
    df_ = df[df['日期文本'].eq(current_date)]
    days = df_['天数']
    item = df_["项目"]
    # 绘制条形图 ------
    ax.clear() # 重绘
    ax.barh(item, days, color = colors)
    for y, (x,name) in enumerate(zip(days.values,item.values)): # 系列标注
            ax.text(x, y, "%s" % x, size=12)
            if x > 1:
                ax.text(x-0.5, y, name, size=14, ha = 'right')
    ax.text(11.01, current_date, transform = ax.transAxes, size= 20, ha='right'# 滚动时间
    ax.get_xaxis().set_visible(False# 隐藏坐标轴
    ax.get_yaxis().set_visible(False)

# draw(19)
# plt.savefig('test.png')
animator = ani.FuncAnimation(fig, draw, frames=timeSlot ,interval = 100# interval时间间隔
plt.show()
# animator.save('test.gif',fps=10)

二、定制二维码

不解释!(看注释)直接上代码:

from MyQR import myqr # 需先安装MyQR库

def QR_myqr():
    myqr.run(
        'https://'# 二维码指向链接,或无格式文本(但不支持中文)
        version = 5# 大小1~40
        level='H'# 纠错级别
        picture = 'img.jpg'# 底图路径
        colorized = True# 彩色
        contrast = 1.0# 对比度
        brightness = 1.0# 亮度
        save_name = 'save.jpg'# 保存文件名
        save_dir = 'D:/' #保存目录
    )

三、编写静态html页面

如果需要通过二维码来访问你的网站,那就需要先将其部署到服务器,方法也是多种多样的,比如某企鹅云,个人用户有6个月的免费时常。我们在这里要介绍的是 github(其实是因为我公司的电脑不能上外网,测试的时候用不了企鹅云才用的 github,国内手机访问还是放在国内的服务器比较快,大概是的

嗯?就算你问上不了外网却能上 github 我也…大概是限制的网段没覆盖到吧哈哈

嗯?我在公司划水的事情暴露了吗)。

不过在那之前,先把本地的 html 写好吧!

通过开头的最终(不是最终的)效果图可以发现,gif 是首尾相接循环播放的,那最后一天的图像一下子闪过去就看不清楚了,可以修改一下传入的时间序列,把最后一幅图再画多几遍,就有停留的效果了。为了更好地展现效果,下面的图中所用数据的时间周期改为了从6月1日到8月25日(七夕),经过了86天,并增加了两条项目。

timeSlot = [x for x in range(0,86)]+[85]*15

直接放进 html 页面里,就单单一张图好像还缺了点什么,那就跟随动图的节奏在下方打印文字吧。首先设置两个 div 的样式,一个用于展示 gif,一个用于打印文字:

<head>
<style>
  .process_gif{  /*显示动态barh*/
            background-image:url("./process.gif");
            background-repeat: no-repeat;
            background-size: cover;
            margin:0 auto;
            width370px;
            height220px;
            position: relative;
   z-index1;
        }
  .show_txt{  /*显示文字*/
            margin:0 auto;
            background-color: azure;
   width370px;
            height200px;
            position: relative;
   text-align: center;
   padding-top10px;
   z-index1;
        }
</style>
</head>

然后在 body 里让它们显示出来:

<body>
 <div class="process_gif" id="process"></div> 
 <div class="show_txt" id="content_1"></div>
</body>

编写 js 脚本实现打印功能,在页面加载时就调用打印函数 typing,并且在动态图播放到最后一幅时,将其替换成静态图:

<script type="text/javascript">
 /// 显示文字功能 ----------------------------------
 let divTyping = document.getElementById('content_1'); //通过id获取div节点
 let a = 0;
 timer = 0;
 str = "我们已经相遇 20 天<br>告白后过了 13 天<br>First Kiss 至今 5 天";
 function typing () {
  if (a <= str.length) { # 从第一个字开始逐个打印
     divTyping.innerHTML = str.slice(0, a++) + '_';
   timer = setTimeout(typing, 50); # 设置打印时间间隔
  }
  else {
   divTyping.innerHTML = str; //结束打字,移除 _ 光标
     clearTimeout(timer);
  }
 }
 
 window.onload=function(){
   typing();
   setTimeout(function(){
             thisdiv = document.getElementById("process");
    thisdiv.style.backgroundImage = "url('./process_stop.png')"; # 将div背景图替换
        },2000); # 单位是毫秒,根据动态图的时长来设置
 }
</script>

来看一下,真的是真的.真.最终效果图:

注意: 动图的时长和帧数,以及动图在html中与逐行打印文字同步显示,大家还需根据实际内容对代码进行调整,以达到最佳效果哦!

好了不想写了,快速部署的部分大家自己搜索资料吧... ...

我一抡锤子就敲爆自己

------------------- End -------------------

往期精彩文章推荐:

欢迎大家点赞,留言,转发,转载,感谢大家的相伴与支持

想加入Python学习群请在后台回复【入群

万水千山总是情,点个【在看】行不行

/今日留言主题/

随便说一两句吧~~

浏览 38
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报