WeChatMsg/app/Ui/contact/analysis/charts.py

530 lines
16 KiB
Python
Raw Normal View History

2023-01-31 20:43:40 +08:00
import os
2023-03-31 11:15:44 +08:00
2023-01-31 20:43:40 +08:00
import jieba
2023-03-31 11:15:44 +08:00
import pandas as pd
import xmltodict
2023-01-31 20:43:40 +08:00
from pyecharts import options as opts
2023-03-31 11:15:44 +08:00
from pyecharts.charts import Pie, WordCloud, Calendar, Bar, Line, Timeline, Grid
2023-01-31 20:43:40 +08:00
from ....DataBase import data
2023-03-31 11:15:44 +08:00
# from app.DataBase import data
2023-01-31 20:43:40 +08:00
data.mkdir(os.path.abspath('.') + '/data/聊天统计')
Type = {
'1': '文字',
'3': '图片',
'43': '视频',
'-1879048185': '微信运动排行榜',
'5': '',
'47': '表情包',
'268445456': '撤回消息',
'34': '语音',
'419430449': '转账',
'50': '语音电话',
'100001': '领取红包',
'10000': '消息已发出,但被对方拒收了。',
'822083633': '回复消息',
'922746929': '拍一拍',
'1090519089': '文件',
'318767153': '付款成功',
'436207665': '发红包',
'49': '分享链接'
}
2023-04-05 13:02:25 +08:00
charts_width = 800
charts_height = 450
wordcloud_width = 780
2023-04-24 11:04:08 +08:00
wordcloud_height = 720
2023-01-31 20:43:40 +08:00
def send_recv_rate(username):
send_num = data.send_nums(username)
recv_num = data.recv_nums(username)
total_num = send_num + recv_num
print(send_num, recv_num)
c = (
2023-04-05 13:02:25 +08:00
Pie(init_opts=opts.InitOpts(
2023-04-24 11:04:08 +08:00
# bg_color='rgb(240,240,240)',
2023-04-05 13:02:25 +08:00
width=f"{charts_width}px",
height=f"{charts_height}px")
)
2023-01-31 20:43:40 +08:00
.add(
"",
[
('发送', send_num), ('接收', recv_num)
],
center=["40%", "50%"],
)
.set_global_opts(
2023-03-31 11:15:44 +08:00
title_opts=opts.TitleOpts(title=f"信息发送接收", subtitle=f"总计:{total_num}条消息", pos_bottom="0%"),
2023-01-31 20:43:40 +08:00
legend_opts=opts.LegendOpts(type_="scroll", pos_left="80%", orient="vertical"),
)
.set_series_opts(
label_opts=opts.LabelOpts(formatter="{b}:{d}%"),
)
.render("./data/聊天统计/send_recv_rate.html")
)
def msg_type_rate(username):
type_data = data.msg_type_num(username)
type_data = sorted(type_data, key=lambda x: x[1], reverse=True)
data1 = type_data[:4]
data2 = sum(map(lambda x: x[1], type_data[4:]))
print(type_data)
new_data = []
for t in data1:
try:
new_data.append((Type[str(t[0])], t[1]))
except:
new_data.append(('未知类型', t[1]))
new_data.append(('其他', data2))
c = (
2023-04-05 00:01:06 +08:00
Pie(init_opts=opts.InitOpts(width=f"{charts_width}px", height=f"{charts_height}px"))
2023-01-31 20:43:40 +08:00
.add(
"",
new_data
,
center=["40%", "50%"],
)
.set_global_opts(
title_opts=opts.TitleOpts(title=f"消息类型占比", pos_bottom="0%"),
legend_opts=opts.LegendOpts(type_="scroll", pos_left="80%", orient="vertical"),
)
.set_series_opts(
label_opts=opts.LabelOpts(formatter="{b}:{d}%"),
)
.render("./data/聊天统计/msg_type_rate.html")
)
def message_word_cloud(username):
text = data.get_text(username)
total_msg_len = len(text)
word_list = jieba.cut(text)
# word = " ".join(word_list)
# print(word)
stopwords = set()
content = [line.strip() for line in open('./app/data/stopwords.txt', 'r', encoding='utf-8').readlines()]
stopwords.update(content)
wordcount = {}
for word in jieba.cut(text):
if len(word) > 1 and word not in stopwords:
wordcount[word] = wordcount.get(word, 0) + 1
text_data = sorted(wordcount.items(), key=lambda x: x[1], reverse=True)
if len(text_data) > 100:
text_data = text_data[:100]
2023-03-06 00:39:40 +08:00
# print(text_data)
2023-01-31 20:43:40 +08:00
(
2023-04-05 00:01:06 +08:00
WordCloud(init_opts=opts.InitOpts(width=f"{wordcloud_width}px", height=f"{wordcloud_height}px"))
2023-01-31 20:43:40 +08:00
.add(series_name="聊天文字", data_pair=text_data, word_size_range=[20, 100])
.set_global_opts(
title_opts=opts.TitleOpts(
title=f"词云图", subtitle=f"总计{total_msg_len}",
title_textstyle_opts=opts.TextStyleOpts(font_size=23)
),
tooltip_opts=opts.TooltipOpts(is_show=True),
2023-03-31 11:15:44 +08:00
legend_opts=opts.LegendOpts(is_show=False)
2023-01-31 20:43:40 +08:00
)
.render("./data/聊天统计/wordcloud.html")
)
def calendar_chart(username):
2023-03-31 11:15:44 +08:00
msg_data = data.get_msg_by_days(username, year='2022')
2023-04-05 00:01:06 +08:00
if not msg_data:
return False
2023-01-31 20:43:40 +08:00
min_ = min(map(lambda x: x[1], msg_data))
max_ = max(map(lambda x: x[1], msg_data))
c = (
2023-04-05 00:01:06 +08:00
Calendar(init_opts=opts.InitOpts(width=f"{charts_width}px", height=f"{charts_height}px"))
2023-01-31 20:43:40 +08:00
.add(
"",
msg_data,
calendar_opts=opts.CalendarOpts(range_="2022")
)
.set_global_opts(
title_opts=opts.TitleOpts(title="2022年聊天情况"),
visualmap_opts=opts.VisualMapOpts(
max_=max_,
min_=min_,
orient="horizontal",
# is_piecewise=True,
# pos_top="200px",
pos_bottom="0px",
pos_left="0px",
),
2023-03-31 11:15:44 +08:00
legend_opts=opts.LegendOpts(is_show=False)
2023-01-31 20:43:40 +08:00
)
.render("./data/聊天统计/calendar.html")
)
def month_num(username):
"""
每月聊天条数
"""
msg_data = data.get_msg_by_month(username, year='2022')
y_data = list(map(lambda x: x[1], msg_data))
x_axis = list(map(lambda x: x[0], msg_data))
c = (
2023-04-05 00:01:06 +08:00
Bar(init_opts=opts.InitOpts(width=f"{charts_width}px", height=f"{charts_height}px"))
2023-01-31 20:43:40 +08:00
.add_xaxis(x_axis)
.add_yaxis("消息数量", y_data)
.set_global_opts(
2023-04-05 00:01:06 +08:00
title_opts=opts.TitleOpts(title="逐月统计", subtitle=None),
2023-01-31 20:43:40 +08:00
datazoom_opts=opts.DataZoomOpts(),
toolbox_opts=opts.ToolboxOpts(),
)
.render("./data/聊天统计/month_num.html")
)
2023-03-31 11:15:44 +08:00
def chat_session(username):
msg_data = data.get_msg_by_hour(username)
x_axis = list(map(lambda x: x[0], msg_data))
y_data = list(map(lambda x: x[1], msg_data))
# print(x_axis)
# print(y_data)
# max_ = max(y_data)
c = (
2023-04-05 00:01:06 +08:00
Line(init_opts=opts.InitOpts(width=f"{charts_width}px", height=f"{charts_height}px"))
2023-03-31 11:15:44 +08:00
.add_xaxis(xaxis_data=x_axis)
.add_yaxis(
series_name="聊天频率",
y_axis=y_data,
markpoint_opts=opts.MarkPointOpts(
data=[
opts.MarkPointItem(type_="max", name="最大值"),
opts.MarkPointItem(type_="min", name="最小值", value=int(10)),
]
),
markline_opts=opts.MarkLineOpts(
data=[opts.MarkLineItem(type_="average", name="平均值")]
),
)
.set_global_opts(
title_opts=opts.TitleOpts(title="聊天时段", subtitle=None),
# datazoom_opts=opts.DataZoomOpts(),
# toolbox_opts=opts.ToolboxOpts(),
)
.set_series_opts(
label_opts=opts.LabelOpts(
is_show=False
)
)
.render("./data/聊天统计/chat_session.html")
)
def sport(username):
sports = data.get_sport()
ranks = []
steps = []
date = []
for sport in sports:
try:
timestamp, content, t = sport
rank_data = xmltodict.parse(content)
sub_data = rank_data['msg']['appmsg']['hardwareinfo']['messagenodeinfo']
# print(sub_data)
my_rank = sub_data['rankinfo']['rank']['rankdisplay']
my_steps = int(sub_data['rankinfo']['score']['scoredisplay'])
# print(f'rank: {my_rank},steps: {my_steps}')
rank_view = rank_data['msg']['appmsg']['hardwareinfo']['rankview']['rankinfolist']['rankinfo']
for userinfo in rank_view:
username0 = userinfo['username']
if username0 == username:
rank_ta = int(userinfo['rank']['rankdisplay'])
steps_ta = int(userinfo['score']['scoredisplay'])
ranks.append(rank_ta)
steps.append(steps_ta)
date.append(t)
except:
continue
2023-11-01 23:38:58 +08:00
try:
# todo 可能没有运动信息
df = pd.DataFrame({'ranks': ranks, 'score': steps, 'date': date}, index=date)
months = pd.date_range(date[0], date[-1], freq='M')
except:
months = []
2023-04-05 00:01:06 +08:00
tl = Timeline(init_opts=opts.InitOpts(width=f"{charts_width}px", height=f"{charts_height}px"))
2023-03-31 11:15:44 +08:00
tl.add_schema(is_auto_play=True)
for i in range(len(months) - 1):
da = df[(months[i + 1].strftime("%Y-%m-%d") >= df['date']) & (df['date'] > months[i].strftime("%Y-%m-%d"))]
bar = (
2023-04-05 00:01:06 +08:00
Bar(init_opts=opts.InitOpts(width=f"{charts_width}px", height=f"{charts_height}px"))
2023-03-31 11:15:44 +08:00
.add_xaxis(list(da['date']))
.add_yaxis(
"步数",
list(da['score']),
yaxis_index=1,
color="#d14a61",
)
.extend_axis(
yaxis=opts.AxisOpts(
name="步数",
type_="value",
# grid_index=0,
# min_=0,
# max_=250,
position="right",
axisline_opts=opts.AxisLineOpts(
linestyle_opts=opts.LineStyleOpts(color="#d14a61")
),
# axislabel_opts=opts.LabelOpts(formatter="{value} ml"),
)
)
.extend_axis(
yaxis=opts.AxisOpts(
type_="value",
name="排名",
# min_=0,
# max_=25,
position="left",
is_inverse=True,
is_show=False,
# interval=True,
# grid_index=1,
axisline_opts=opts.AxisLineOpts(
linestyle_opts=opts.LineStyleOpts(color="#675bba")
),
# axislabel_opts=opts.LabelOpts(formatter="{value} °C"),
splitline_opts=opts.SplitLineOpts(
is_show=True, linestyle_opts=opts.LineStyleOpts(opacity=1)
),
)
)
.set_global_opts(
2023-04-05 00:01:06 +08:00
title_opts=opts.TitleOpts(
title="{}".format(months[i + 1].strftime("%Y-%m")),
),
2023-03-31 11:15:44 +08:00
# legend_opts=opts.LegendOpts(is_show=False),
yaxis_opts=opts.AxisOpts(is_inverse=True),
# xaxis_opts=opts.AxisOpts(type_='time')
2023-03-31 11:15:44 +08:00
)
.set_series_opts(
label_opts=opts.LabelOpts(
is_show=False
)
)
)
# init_opts = opts.InitOpts(width="400px", height="235px")
line = (
2023-04-05 00:01:06 +08:00
Line(init_opts=opts.InitOpts(width=f"{charts_width}px", height=f"{charts_height}px"))
2023-03-31 11:15:44 +08:00
.add_xaxis(list(da['date']))
.add_yaxis(
"排名",
list(da['ranks']),
yaxis_index=0,
color="#675bba",
# label_opts=opts.LabelOpts(is_show=False),
)
.set_global_opts(
yaxis_opts=opts.AxisOpts(is_inverse=True),
# xaxis_opts=opts.AxisOpts(type_='time')
2023-03-31 11:15:44 +08:00
)
.set_series_opts(
label_opts=opts.LabelOpts(
is_show=False
)
)
)
bar.overlap(line)
grid = Grid()
2023-04-05 00:01:06 +08:00
grid.add(bar, opts.GridOpts(pos_left="5%", pos_right="11%"), is_control_axis_index=True)
2023-03-31 11:15:44 +08:00
# grid.render("grid_multi_yaxis.html")
tl.add(grid, "{}".format(months[i].strftime("%Y-%m")))
tl.render("./data/聊天统计/sports.html")
return {
username: {
'ranks': ranks,
'score': steps,
'date': date,
}
}
def chat_start_endTime(username):
start_time = data.get_msg_start_time(username)
end_time = data.get_msg_end_time(username)
year = start_time[:4]
month = start_time[5:7]
day = start_time[8:10]
hour = start_time[11:13]
minute = start_time[14:16]
second = start_time[17:]
html = '''
<html>
<head>
<meta charset="UTF-8">
<title>聊天时间</title>
<style>
/* 倒计时开始 */
.gn_box {
2023-04-05 00:01:06 +08:00
padding: 0px 0px;
margin-bottom:0px;
2023-03-31 11:15:44 +08:00
text-align: center;
background-color: #fff;
}
#t_d{
color: #982585;
font-size: 18px;
}
#t_h{
color: #8f79c1;
font-size: 18px;
}
#t_m{
color: #65b4b5;
font-size: 18px;
}
#t_s{
color: #83caa3;
font-size: 18px;
}
#text{
color: #E80017;
font-size: 18px;
}
</style>
<!--倒计时开始-->
</head>
<body>
<div class="gn_box">
<h1>
<font color="#E80017"></font><font color="#D1002E">一次</font><font color="#BA0045">聊天</font><font
color="#A3005C">发生</font><font color="#8C0073"></font>
<font color="#75008A">%s</font><font color="#5E00A1">-</font><font color="#4700B8">%s</font><font
color="#3000CF"> %s</font><font color="#1900E6">:%s</font><font color="#0200FD">:%s</font>
</h1>
<center>
<div id="CountMsg" class="HotDate">
<span id="text">距今已有</span>
<span id="t_d">626 </span>
<span id="t_h">6 </span>
<span id="t_m">26 </span>
<span id="t_s">26 </span>
</div>
</center>
</div>
<!--倒计时结束-->
<script type="text/javascript"> function getRTime() {
var EndTime = new Date('%s');
var NowTime = new Date();
var t = NowTime.getTime()-EndTime.getTime();
var d = Math.floor(t / 1000 / 60 / 60 / 24);
var h = Math.floor(t / 1000 / 60 / 60 %% 24);
var m = Math.floor(t / 1000 / 60 %% 60);
var s = Math.floor(t / 1000 %% 60);
document.getElementById("t_d").innerHTML = d + "";
document.getElementById("t_h").innerHTML = h + "";
document.getElementById("t_m").innerHTML = m + "";
document.getElementById("t_s").innerHTML = s + "";
}
setInterval(getRTime, 1000);
</script>
</body>
</html>
''' % (year, month + '-' + day, hour, minute, second, start_time)
print(year, month, day, hour, minute, second)
with open('./data/聊天统计/time.html', 'w', encoding='utf-8') as f:
f.write(html)
def title(username):
conRemark = data.get_conRemark(username)
avatar = data.get_avator(username)
html = '''
<html>
<head>
<meta charset="UTF-8">
<title>聊天时间</title>
<style>
/* 倒计时开始 */
.gn_box {
2023-04-05 00:01:06 +08:00
padding: 0px 0px;
margin-bottom: 0px;
2023-03-31 11:15:44 +08:00
text-align: center;
background-color: #fff;
}
#t_d{
color: #982585;
font-size: 18px;
}
#t_h{
color: #8f79c1;
font-size: 18px;
}
#t_m{
color: #65b4b5;
font-size: 18px;
}
#t_s{
color: #83caa3;
font-size: 18px;
}
#text{
color: #E80017;
font-size: 18px;
}
#conRemark{
color: #A3005C;
font-size: 28px;
}
#table {
2023-04-05 00:01:06 +08:00
width: 600px; height: 100px;//可随意
2023-03-31 11:15:44 +08:00
position: absolute; left: 0; top: 0; right: 0; bottom: 0;
margin: auto; /* 有了这个就自动居中了 */
}
</style>
<!--倒计时开始-->
</head>
<body>
<div class="gn_box">
<table align="center" style="margin:0px auto;">
<tr valign="middle">
<td valign="middle">
<table>
<tr>
<td>
2023-04-05 00:01:06 +08:00
<img src="../../../%s" height="40" width="40"
2023-03-31 11:15:44 +08:00
alt="Avatar"/>
</td>
</tr>
</table>
</td>
<td align="center" valign="middle">
<table>
<tr>
<td>
<font id="conRemark">%s</font>
</td>
</tr>
</table>
</td>
</tr>
</table>
<div>
<span>
</span>
<span></span>
</div>
</div>
</body>
</html>
''' % (avatar, conRemark)
print('头像地址', avatar)
with open('./data/聊天统计/title.html', 'w', encoding='utf-8') as f:
f.write(html)
2023-01-31 20:43:40 +08:00
if __name__ == '__main__':
2023-03-31 11:15:44 +08:00
# send_recv_rate('wxid_wt2vsktnu4z022')
sport('wxid_wt2vsktnu4z022')