主要利用
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),
)
)
效果如下
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
效果如下
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)
效果如下
完整代码
# 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'))