pyecharts可视化实例一

2022-05-19  本文已影响0人  Radiance_sty

背景:初期的报表都是通过邮件发的表格数据,没有经过排序和处理,所以稍加修改,同时数据都做了脱敏处理。

一、前期处理

  1. 确定可视化图像
    首先根据需求选择合适的可视化图像,报表要求对数据按客户和仓库两个维度进行统计,然后分析数量、重量及占比,同时还需要表格,那么可以使用饼图+表格的形式完成。

  2. 数据处理
    原始数据格式如下,现需要以客户和仓库两个维度对票数和重量进行统计,然后根据票数和重量进行排序。

考虑到每天都会有表格过来,同时文件的命名方式已经确定(日期+其他),那么可以读取每天的日期来读取当天的文件,然后再进行处理,部分参考代码如下:

# 对数据进行聚合操作 - 仓库/客户(总票数/总重量)
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位及后面的客户修改为其他客户。

二、可视化

  1. 玫瑰图
    由于使用饼图或者环形图会使得后面的数据集中在一块,显得不美观,所以这里使用了玫瑰图,同时加上了图形组件,部分代码参考如下:
# 环形图配置、图形组件配置
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

可视化结果如下图所示:

  1. 表格
    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
  1. 组合图像
    目前可视化的结果都已经出来了,接下来通过分页组件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 框架,具体操作和实例可以参考 官方手册 官方实例

注:实际做可视化报表的时候会遇上很多问题,如数据的处理、颜色的选取、位置的调整、字体的选择(这方面可能会涉及侵权)等等,后续更新会有说明。

上一篇 下一篇

猜你喜欢

热点阅读