程序员用python给了女友一个七夕惊喜!
七夕(各种节日、纪念日)又快到啦,程序员(怎么会不是单身呢)又要想招来哄女友啦?
想必大家都知道各种各样的代码式浪漫,比如定制的二维码,让女友扫码后进入一个定制的 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(1, 1.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 函数时所需的参数是天数 date
。interval
参数为绘制每张图的时间间隔,用于在 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(1, 1.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;
width: 370px;
height: 220px;
position: relative;
z-index: 1;
}
.show_txt{ /*显示文字*/
margin:0 auto;
background-color: azure;
width: 370px;
height: 200px;
position: relative;
text-align: center;
padding-top: 10px;
z-index: 1;
}
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中与逐行打印文字同步显示,大家还需根据实际内容对代码进行调整,以达到最佳效果哦!
好了不想写了,快速部署的部分大家自己搜索资料吧... ...
四、部署站点到github
言归正传,Html 页面中更多的花样还有待各位发挥了,现在到最后环节——把页面 duang 上 github。
先注册登录最大同性交友网站 github(到底有几个最大同性交友…)的过程略过,创建一个新的仓库,用于存放 html 文件和图片。
创建后得到一个仓库地址。
准备上传我们的站点文件。
上传文件还需要先安装 git(安装地址:https://git-scm.com/downloads/),之后在安装目录下打开 git-bash.exe。
1、进入站点目录($ 符号后为输入的命令):
2、在该目录生成 git 管理:
3、输入 add *
添加目录下所有的文件,也可指定文件名或文件夹,添加文件夹的格式为 add dirname/
:
4、输入 git status
查看是否将所需文件添加进了缓冲区:
5、输入提交版本的注释(引号内为注释内容):
6、将本地仓库管理关联至 github(刚才得到的仓库地址):
7、上传文件:
最后一步上传时会相继弹出 github 账号密码输入框,输入后即可等待上传完成。
完成后回到 github,发现几个文件已经躺在仓库里了,再点击 Settings:
在 Gitub Pages 一栏中选择 master branch:
现在,你的站点可以通过这个链接来访问啦,把它丢进二维码里就大功告成了!可以用手机扫码看一下demo。
(如果想知道这种二维码是如何生成的,请看之前的文章)
事情往往不像看上去那样简单,尽管我们已经历尽重重步骤,但依然遗留了两个坑:gif 图片在页面中加载慢(通过工具压缩图片大小来解决),部分浏览器不支持 window.onload
(优化 js 脚本)。本文不再多赘述,大家自己去探索吧(咔咔)!另外,可以加的东西还有词云、动态字符画、抽奖转盘等等,如果各位有什么其他有趣的玩意儿可以加进页面中,还请给笔者提供更多点子!
五、部署站点到企鹅云
最近发现github有点抽风,之前部署的站点无法访问了!于是回家把站点迁到了企鹅云,果然国内服务器响应体验更佳,而且操作十分简便,让我们来看看怎么做吧。
首先进入企鹅云官网,在左上角的栏目中找到“对象储存”,进入页面后点击“立即使用”。
然后创建一个桶子,记得选“公有读私有写”,完全私有就不能通过外部访问啦。
把相关文件丢到桶子里。
返回桶子列表,在刚才创建的桶子右侧点击“配置管理”,开启静态网站后就可以通过访问节点的链接浏览站点了,是不是感觉比github page快多了哈哈。
再来扫扫试试吧!~
(如果想知道这种二维码是如何生成的,请看之前的文章)
以上就是我的分享内容,
希望能够帮助大家七夕哄好女朋友
— 【 THE END 】— 本公众号全部博文已整理成一个目录,请在公众号里回复「m」获取! 3T技术资源大放送!包括但不限于:Java、C/C++,Linux,Python,大数据,人工智能等等。在公众号内回复「1024」,即可免费获取!!