pyecharts可视化实例一
2022-05-19 本文已影响0人
Radiance_sty
背景:初期的报表都是通过邮件发的表格数据,没有经过排序和处理,所以稍加修改,同时数据都做了脱敏处理。
一、前期处理
-
确定可视化图像
首先根据需求选择合适的可视化图像,报表要求对数据按客户和仓库两个维度进行统计,然后分析数量、重量及占比,同时还需要表格,那么可以使用饼图+表格的形式完成。 -
数据处理
原始数据格式如下,现需要以客户和仓库两个维度对票数和重量进行统计,然后根据票数和重量进行排序。
考虑到每天都会有表格过来,同时文件的命名方式已经确定(日期+其他),那么可以读取每天的日期来读取当天的文件,然后再进行处理,部分参考代码如下:
# 对数据进行聚合操作 - 仓库/客户(总票数/总重量)
def create_dt(dt, t, v, r=5):
# 对数据进行聚合操作
dt_ = dt.groupby(t)[v].agg([(v, "sum")])
dt_ = dt_.sort_values(by=v, ascending=False).reset_index()
# 待考虑:仓库数大于 r, 默认设置为5
if t == "仓库":
if v == "总重量":
dt_[v] = np.round(dt_[v], 2)
return dt_
# 客户 - 将排名第 r 位之后的客户统计为 "其他客户",并对其求和
else:
dt_.iloc[r:] = "其他客户", np.sum(dt_.iloc[r:, 1])
dt_.drop_duplicates(subset=[t], keep='first', inplace=True)
dt_ = dt_.sort_values(by=v, ascending=False)
if v == "总重量":
dt_[v] = np.round(dt_[v], 2)
return dt_
经过处理后的数据如下图所示。
注:数据处理的时候可以选定只保留前几位的客户,其余修改为其他客户。如只需看前5位客户的占比,那么就把第6位及后面的客户修改为其他客户。
二、可视化
- 玫瑰图
由于使用饼图或者环形图会使得后面的数据集中在一块,显得不美观,所以这里使用了玫瑰图,同时加上了图形组件,部分代码参考如下:
# 环形图配置、图形组件配置
def pie_unit(dt, col_0, col_1, num):
x = dt[col_0].values.tolist()
y = dt[col_1].values.tolist()
# 汇总计算,整数不变,小数则保留2位小数点
y_sum = np.sum(y)
y_sum = [y_sum if y_sum - int(y_sum) == 0 else np.round(y_sum, 2)]
fmt, fmt_t, sub_title = None, None, None
if col_1 == "总票数":
if col_0 == "仓库":
fmt = "{abg|}仓库: {b}{abg|}\n{hr|}\n {abg|}总票数: {c}票 \t{abg|}占比: {d}%{abg|}"
else:
fmt = "{abg|}客户: {b}{abg|}\n{hr|}\n {abg|}总票数: {c}票 \t{abg|}占比: {d}%{abg|}"
fmt_t = "{b}: {c}票 ({d}%)"
sub_title = "\t\t\t总票数: {} 票".format(y_sum[0])
elif col_1 == "总重量":
if col_0 == "仓库":
fmt = "{abg|}仓库: {b}{abg|}\n{hr|}\n {abg|}总重量: {c}KG \t{abg|}占比: {d}%{abg|}"
else:
fmt = "{abg|}客户: {b}{abg|}\n{hr|}\n {abg|}总重量: {c}KG \t{abg|}占比: {d}%{abg|}"
fmt_t = "{b}: {c}KG ({d}%)"
sub_title = "\t\t\t总重量: {} KG".format(y_sum[0])
# 饼图初始化,设置页面大小及主题
c = (Pie(init_opts=opts.InitOpts(width="1200px", height="600px", theme=ThemeType.VINTAGE))
.add(
"",
[list(z) for z in zip(x, y)],
radius=["30%", "55%"], # 设置为环形图-内外环大小
center=["42%", "55%"], # 饼图中心位置调整,默认为 ["50%", "50%"]
rosetype="area", # 玫瑰图
label_opts=opts.LabelOpts(
font_size=16, position="outside", # 字体大小、位置
formatter=fmt, # 标签格式
background_color="#eee", border_color="#aaa", # 底层图形颜色
border_width=1, border_radius=4, interval=0,
# 富文本设置
rich={
"abg": {
"backgroundColor": "#e3e3e3",
"width": "0%",
"align": "center",
"height": 24,
"borderRadius": [1, 1, 0, 0]},
"hr": {
"borderColor": "#aaa",
"width": "100%",
"borderWidth": 0.5,
"height": 0},
"per": {
"color": "#eee",
"backgroundColor": "#334455",
"padding": [2, 4],
"borderRadius": 2,
"height": 24},
},
),
)
# 设置标签不重叠,最小角度20°(即实际角度小于20°的部分用20°表示,百分比小但是在饼图上显示较大)
.set_series_opts(avoidLabelOverlap=True, minAngle=20)
# 全局设置-标题/副标题
.set_global_opts(
title_opts=opts.TitleOpts(title=title_index(num) + col_0 + "—" + col_1 + "饼图", pos_left="0%", pos_top="2%",
title_textstyle_opts=opts.TextStyleOpts(font_size=25, font_family="SimSun",
font_weight="bolder"),
subtitle=sub_title,
subtitle_textstyle_opts=opts.TextStyleOpts(font_size=20, font_family="SimSun",
color="#000", font_weight="bold")
),
# 全局设置-颜色图例(滚动,位置、字体)
legend_opts=opts.LegendOpts(type_="plain", pos_right="2%", pos_top="10%", orient="vertical",
item_gap=10, item_width=25, item_height=20, legend_icon="roundRect",
textstyle_opts=opts.TextStyleOpts(font_size=16, font_family="SimSun",
font_weight="bold")),
tooltip_opts=opts.TooltipOpts(textstyle_opts=opts.TextStyleOpts(font_size=20, font_family="SimSun",
font_weight="bolder"),
formatter=fmt_t),
# 图形组件设置
graphic_opts=[
# 图形组件设置
opts.GraphicGroup(
# 设置图形组件样式
graphic_item=opts.GraphicItem(rotation=JsCode("Math.PI / 4"),
bounding="raw", right=90, bottom=90, z=100),
# 设置底层图形信息
children=[
opts.GraphicRect(
graphic_item=opts.GraphicItem(left="center", top="center", z=100),
graphic_shape_opts=opts.GraphicShapeOpts(width=400, height=60),
graphic_basicstyle_opts=opts.GraphicBasicStyleOpts(fill="rgba(0,0,0,0.2)"),
),
# 设置字体信息
opts.GraphicText(
graphic_item=opts.GraphicItem(left="center", top="center", z=100),
graphic_textstyle_opts=opts.GraphicTextStyleOpts(
text="Powered by Far IE",
font="bolder 25px SimSun",
graphic_basicstyle_opts=opts.GraphicBasicStyleOpts(fill="#fff")),
),
],
)
],
))
return c
可视化结果如下图所示:
- 表格
pyecharts也提供了表格组件,部分代码参考如下:
# 表格配置-仓库/客户(总票数/总重量)
def table_warehouse(dt, x, y):
# 增加新的一列:求该列每行的占比,转化为百分比并保留2位小数点
per = 100 * dt[y].div(dt[y].sum(axis=0)) #
dt["占比"] = ["{}%".format(round(i, 2)) for i in per]
dt_ = pd.Series({x: "汇总", y: round(dt[y].sum(), 2), "占比": "100.00%"})
dt = dt.append(dt_, ignore_index=True)
# 修改列名
ind_1, ind_2 = None, None
if y == "总票数":
ind_1 = "总票数(票)"
ind_2 = "各{}{}占比(%)".format(x, y)
elif y == "总重量":
ind_1 = "总重量(KG)"
ind_2 = "各{}{}占比(%)".format(x, y)
dt = dt.rename(columns={y: ind_1, "占比": ind_2})
# 提取新的列名
cols = dt.columns.tolist()
headers = [cols[0]]
headers.extend(dt[cols[0]].values.tolist())
rows_0 = [cols[1]]
rows_0.extend(dt[cols[1]].values.tolist())
rows_1 = [cols[2]]
rows_1.extend(dt[cols[2]].values.tolist())
rows = [rows_0, rows_1]
table = Table()
table.add(headers, rows)
table.set_global_opts()
return table
- 组合图像
目前可视化的结果都已经出来了,接下来通过分页组件Grid和顺序多图Page将几个图形结合起来,生成一个可视化图像,部分代码参考如下:
# 建立分页,将各个图添加到每个页面当中
page = Page(page_title="{} daily report".format(file_date))
# 前四个图:仓库/客户——票数/重量
k = 0
for col in col_list:
k += 1
i, j = col[0], col[1]
dt = df[[i, j]]
dt_new = create_dt(dt, i, j) # 对数据进行聚合
grid = Grid(init_opts=opts.InitOpts(width="1000px", height="500px", theme=ThemeType.VINTAGE, bg_color="#fff"))
pie = pie_unit(dt_new, i, j, k)
grid.add(pie, grid_opts=opts.GridOpts())
table = table_warehouse(dt_new, i, j)
page.add(grid)
page.add(table)
# 第五个图:各仓库漏扫数据
if flat[0] == 0:
grid0 = Grid(
init_opts=opts.InitOpts(width="1000px", height="100px", theme=ThemeType.VINTAGE, bg_color="#fff"))
m_dt = pd.DataFrame(columns=['A'])
table_ = table_missing(m_dt)
grid0.add(table_, grid_opts=opts.GridOpts())
page.add(grid0)
elif flat[0] == 1:
grid0 = Grid(
init_opts=opts.InitOpts(width="1000px", height="500px", theme=ThemeType.VINTAGE, bg_color="#fff"))
m_dt = missing_dt(df[cols_2], cols_2)
pie_ = pie_unit1(m_dt)
table_0 = table_missing(m_dt)
grid0.add(pie_, grid_opts=opts.GridOpts())
page.add(grid0)
page.add(table_0)
# 第六个图-偷渡客户数据(表格)
if s[0] == 0:
grid1 = Grid(
init_opts=opts.InitOpts(width="1000px", height="100px", theme=ThemeType.VINTAGE, bg_color="#fff"))
lq = table_smuggle(dt_smuggle)
grid1.add(lq, grid_opts=opts.GridOpts())
page.add(grid1)
elif s[0] == 1:
table_1 = table_smuggle(dt_smuggle)
# save as html
page.render(html_path)
print("Daily report done!")
最后完整的报表如下图所示:
pyecharts生成的报表优点是可以交互,图表简洁,还可以集成Flask、Django 等主流 Web 框架,具体操作和实例可以参考 官方手册 和 官方实例 。
注:实际做可视化报表的时候会遇上很多问题,如数据的处理、颜色的选取、位置的调整、字体的选择(这方面可能会涉及侵权)等等,后续更新会有说明。