pyecharts学习

210 阅读6分钟

主要利用pyecharts根据给定的近几年地区收入数据绘制动态可交互的排序图表,最终效果后续有展示

1. 基础图表生成

1.1 水平柱状图

for column_label in columns_list: # columns_list为[2002~2021]的时间
    # 对x_data进行排序
    cur_x_data, cur_y_labels, cur_data_index = sorted_data(x_data[column_label], y_labels)
    data_index.append(cur_data_index[:Basic.top_n].tolist()) # 用于后续折线图的一些准备

    x = cur_x_data[:Basic.top_n][::-1] # [::-1]用于列表逆序
    y = cur_y_labels[:Basic.top_n][::-1]
    min_data = int(np.min(x)) # VisualMapOpts中取值范围的准备
    max_data = int(np.max(x))
    bar = (
      Bar(init_opts=opts.InitOpts(theme=Basic.themes)) # 初始化主题
      .add_xaxis(y)
      .add_yaxis('地区生产总值', x, label_opts=opts.LabelOpts(position='right'))
      .reversal_axis() # 反转y轴
      .set_global_opts(
        xaxis_opts=opts.AxisOpts(name="生产总值",
          name_textstyle_opts=opts.TextStyleOpts(color=Basic.font_color),
          axislabel_opts=opts.LabelOpts(color=Basic.font_color)
        ),  # 修改坐标轴标签颜色
        yaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(is_show=True, color=Basic.font_color)),
        title_opts=opts.TitleOpts(
          title=f'{column_label}地区生产总值',
          subtitle='地区生产总值(当年价格)(亿元)',
          pos_left='50px',
          subtitle_textstyle_opts=opts.TextStyleOpts(color=Basic.font_color)
        ),
        tooltip_opts=opts.TooltipOpts( # 提示框
            is_show = True,
            trigger = "axis", #坐标轴触发,也可以是item数据项图形触发和none什么都不触发
            trigger_on = "mousemove|click", #触发条件,鼠标移动时触发或鼠标点击时触发
        ),
        toolbox_opts=opts.ToolboxOpts( # 工具栏
          is_show=False,
          pos_left='35%',
          pos_top=Basic.bar.get('nav_top_basic')
        ),
        legend_opts=opts.LegendOpts(is_show=False, pos_left='20%', pos_top=Basic.bar.get('nav_top_basic')), # 图例
        visualmap_opts=opts.VisualMapOpts( # 视觉映射配置项,改柱状图颜色
          is_calculable=True,
          dimension=0,
          pos_left="10",
          pos_top="10%",
          range_text=["High", "Low"],
          range_color=["lightskyblue", "yellow", "orangered"],
          textstyle_opts=opts.TextStyleOpts(color="#000"),
          min_=min_data,
          max_=max_data,
        )
      )
    )

1.2 词云图

# 生成词云数据
data = [(label, val) for val, label in zip(cur_x_data, cur_y_labels)]
word_cloud = (
  WordCloud()
  .add('', data,
    word_size_range=[5,60],
    is_draw_out_of_bound=True,
    width=Basic.word_cloud.get('width'),
    height=Basic.word_cloud.get('height'),
    pos_top=Basic.word_cloud.get('pos_top'),
    pos_left=Basic.word_cloud.get('pos_left'),
    shape=Basic.word_cloud.get('shape')
  )
  .set_global_opts(
    title_opts=opts.TitleOpts(
      title_textstyle_opts=opts.TextStyleOpts(font_size=14)
    ),
    tooltip_opts=opts.TooltipOpts(is_show=True),
  )
)

效果如下

image.png

1.3 折线图

折线图不随TimeLine进行变化,想要统一展示近几年的变化趋势

line = ( # 配置折线图的基础属性
    Line(init_opts=opts.InitOpts(width='716.545454px', height='539.545454px', chart_id='line'))
    .add_xaxis(xaxis_data=columns_list)
    .set_global_opts(
      yaxis_opts=opts.AxisOpts(position='right', axislabel_opts=opts.LabelOpts(color=Basic.font_color)),
      xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(color=Basic.font_color)),
      legend_opts=opts.LegendOpts(
        type_='scroll',
        orient=Basic.line.get('orient'),
        pos_left='-10px',
        pos_top='27px'
      ),
      tooltip_opts=opts.TooltipOpts( # 提示框
        is_show = False,
        trigger = "axis", #坐标轴触发,也可以是item数据项图形触发和none什么都不触发
        trigger_on = "mousemove|click", #触发条件,鼠标移动时触发或鼠标点击时触发
      ),
    )
  )
  new_data_index = [] # 二维列表生成式,去重`data_index`索引,获取柱状图频繁显示的几座城市
  [[new_data_index.append(ele) for ele in ele_ if ele not in new_data_index] for ele_ in data_index]

  flag = True # 只有排名第一的显示具体`label`,不然太冗余
  for idx in new_data_index: # 为每一座城市绘制折线图
    cur_x_data = x_data.iloc[idx].tolist()[::-1]
    cur_y_labels = y_labels[idx]
    line.add_yaxis(
      series_name=cur_y_labels,
      y_axis=cur_x_data,
      label_opts=opts.LabelOpts(is_show=flag),
      areastyle_opts=opts.AreaStyleOpts(opacity=0.5)
    )
    if flag is True:
      flag = False

效果如下 image.png

2. 拖拽式图表整合

搭建图表时采用了pyecharts中的Page组件,是一种顺序多图的组合方式,为了更直观、美观的展示,使用layout参数设置拖拽布局,然后保存配置生成静态文件实现最终效果。

(Page(layout=Page.DraggablePageLayout) # 设置布局方式
  .add(timeline)
  .add(line)
  .render('main.html'))

点击页面中的save config按钮会生成chart_config.json文件,主要记录各图表的位置参数,通过cid作为唯一标识,该标识可以通过图表创建是利用init_opts=opts.InitOpts(chart_id='xxx')设置,最后运行下列代码,后续的动态css代码能在每次生成新的html文件时嵌入css链接。

from pyecharts.charts import Page
from utils.config import Basic

Page.save_resize_html(Basic.orient_file_path, cfg_file=r'./resources/chart_config.json', dest=Basic.dest_file_path)

# 生成动态CSS代码
dynamic_css = '<link rel="stylesheet" href="../css/index.css">'

# 打开HTML文件并将CSS插入到<head>标签中
with open(Basic.dest_file_path, 'r') as html_file:
    html_content = html_file.read()
    # 在<head>标签内插入CSS
    html_content = html_content.replace('</head>', f'{dynamic_css}</head>')

# 将更新后的HTML内容写回文件
with open(Basic.dest_file_path, 'w') as html_file:
    html_file.write(html_content)

效果如下

image.png

完整代码

# main_work.py 生成图表

from pyecharts.charts import Bar, Timeline, Grid, WordCloud, Line
from pyecharts.charts import Page
from pyecharts import options as opts
import numpy as np
from utils.config import Basic
from utils.extend_func import get_data, sorted_data

if __name__ == '__main__':
  _, x_data, y_labels = get_data(file_path=Basic.file_path)
  columns_list = [column for column in x_data][::-1]
  timeline = Timeline(init_opts=opts.InitOpts(theme=Basic.themes, width="1300px",height='600px'))

  data_year = []
  data_index = []

  for column_label in columns_list:
    # 对x_data进行排序
    cur_x_data, cur_y_labels, cur_data_index = sorted_data(x_data[column_label], y_labels)
    data_index.append(cur_data_index[:Basic.top_n].tolist())

    x = cur_x_data[:Basic.top_n][::-1]
    y = cur_y_labels[:Basic.top_n][::-1]
    min_data = int(np.min(x))
    max_data = int(np.max(x))
    bar = (
      Bar(init_opts=opts.InitOpts(theme=Basic.themes))
      .add_xaxis(y)
      .add_yaxis('地区生产总值', x, label_opts=opts.LabelOpts(position='right'))
      .reversal_axis() # 反转y轴
      .set_global_opts(
        xaxis_opts=opts.AxisOpts(name="生产总值",
          name_textstyle_opts=opts.TextStyleOpts(color=Basic.font_color),
          axislabel_opts=opts.LabelOpts(color=Basic.font_color)
        ),  # 修改坐标轴标签颜色
        yaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(is_show=True, color=Basic.font_color)),
        title_opts=opts.TitleOpts(
          title=f'{column_label}地区生产总值',
          subtitle='地区生产总值(当年价格)(亿元)',
          pos_left='50px',
          subtitle_textstyle_opts=opts.TextStyleOpts(color=Basic.font_color)
        ),
        tooltip_opts=opts.TooltipOpts( # 提示框
            is_show = True,
            trigger = "axis", #坐标轴触发,也可以是item数据项图形触发和none什么都不触发
            trigger_on = "mousemove|click", #触发条件,鼠标移动时触发或鼠标点击时触发
        ),
        toolbox_opts=opts.ToolboxOpts( # 工具栏
          is_show=False,
          pos_left='35%',
          pos_top=Basic.bar.get('nav_top_basic')
        ),
        legend_opts=opts.LegendOpts(is_show=False, pos_left='20%', pos_top=Basic.bar.get('nav_top_basic')), # 图例
        visualmap_opts=opts.VisualMapOpts(
          is_calculable=True,
          dimension=0,
          pos_left="10",
          pos_top="10%",
          range_text=["High", "Low"],
          range_color=["lightskyblue", "yellow", "orangered"],
          textstyle_opts=opts.TextStyleOpts(color="#000"),
          min_=min_data,
          max_=max_data,
        )
      )
    )

    if len(cur_x_data) != len(cur_y_labels):
      raise ValueError
  
    # 生成词云数据
    data = [(label, val) for val, label in zip(cur_x_data, cur_y_labels)]
    word_cloud = (
      WordCloud()
      .add('', data,
        word_size_range=[5,60],
        is_draw_out_of_bound=True,
        width=Basic.word_cloud.get('width'),
        height=Basic.word_cloud.get('height'),
        pos_top=Basic.word_cloud.get('pos_top'),
        pos_left=Basic.word_cloud.get('pos_left'),
        shape=Basic.word_cloud.get('shape')
      )
      .set_global_opts(
        title_opts=opts.TitleOpts(
          title_textstyle_opts=opts.TextStyleOpts(font_size=14)
        ),
        tooltip_opts=opts.TooltipOpts(is_show=True),
      )
    )

    grid = (
      Grid(init_opts=opts.InitOpts(chart_id='grid_bar_world_cloud'))
      .add(bar, grid_opts=opts.GridOpts(width='400px',height='220px'))
      .add(word_cloud, grid_opts=opts.GridOpts(width='800px',height='380px', pos_top=Basic.word_cloud.get('pos_top'), pos_left=Basic.word_cloud.get('pos_left')))
    )

    timeline.add(grid, column_label)
  
  # Line
  line = (
    Line(init_opts=opts.InitOpts(width='716.545454px', height='539.545454px', chart_id='line'))
    .add_xaxis(xaxis_data=columns_list)
    .set_global_opts(
      yaxis_opts=opts.AxisOpts(position='right', axislabel_opts=opts.LabelOpts(color=Basic.font_color)),
      xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(color=Basic.font_color)),
      legend_opts=opts.LegendOpts(
        type_='scroll',
        orient=Basic.line.get('orient'),
        pos_left='-10px',
        pos_top='27px'
      ),
      tooltip_opts=opts.TooltipOpts( # 提示框
        is_show = False,
        trigger = "axis", #坐标轴触发,也可以是item数据项图形触发和none什么都不触发
        trigger_on = "mousemove|click", #触发条件,鼠标移动时触发或鼠标点击时触发
      ),
    )
  )
  new_data_index = []
  [[new_data_index.append(ele) for ele in ele_ if ele not in new_data_index] for ele_ in data_index]

  flag = True
  for idx in new_data_index:
    cur_x_data = x_data.iloc[idx].tolist()[::-1]
    cur_y_labels = y_labels[idx]
    line.add_yaxis(
      series_name=cur_y_labels,
      y_axis=cur_x_data,
      label_opts=opts.LabelOpts(is_show=flag),
      areastyle_opts=opts.AreaStyleOpts(opacity=0.5)
    )
    if flag is True:
      flag = False

  (timeline.add_schema(
    play_interval=Basic.timeline.get('2000'),
    is_timeline_show=True,
    is_auto_play=True,
    is_loop_play=True,
    pos_bottom='10px'
  ))

  (Page(layout=Page.DraggablePageLayout)
  .add(timeline)
  .add(line)
  .render('main.html'))

参考文章

  1. pyecharts官网
  2. PyEcharts 修改坐标轴颜色/图例字体颜色
  3. Page函数配置文件说明