10-综合案例-数据可视化-折线图
Python数据可视化综合案例:折线图可视化全面指南
一、项目概述
1.1 案例背景与目标
本案例基于Python数据可视化技术,通过pyecharts库实现新冠疫情数据的可视化分析,主要包含三个核心可视化效果:
案例目标:
- 掌握使用pyecharts进行数据可视化的完整流程
- 理解JSON数据格式及其在Python中的处理
- 学会创建专业的折线图并进行个性化配置
- 培养数据分析和可视化表达能力
1.2 技术栈介绍
核心技术:
- 数据格式:JSON
- 可视化库:pyecharts
- 数据来源:百度疫情实时大数据报告
- 图表类型:折线图、地图、动态图表
案例效果展示:
二、JSON数据格式详解
2.1 JSON基础概念
2.1.1 什么是JSON
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,采用完全独立于编程语言的文本格式来存储和表示数据。
JSON的特点:
- 易于阅读和编写
- 易于机器解析和生成
- 支持嵌套数据结构
- 跨语言兼容性好
2.1.2 JSON数据结构
// 对象形式
{
"name": "张三",
"age": 25,
"is_student": false,
"hobbies": ["读书", "运动", "音乐"],
"address": {
"city": "北京",
"district": "海淀区"
}
}
// 数组形式
[
{"name": "张三", "age": 25},
{"name": "李四", "age": 30},
{"name": "王五", "age": 28}
]
2.2 Python与JSON数据转换
2.2.1 基本转换方法
import json
# Python数据 → JSON字符串
python_data = {
"name": "张三",
"age": 25,
"hobbies": ["读书", "运动"]
}
# 序列化:Python对象 → JSON字符串
json_str = json.dumps(python_data, ensure_ascii=False, indent=2)
print("JSON字符串:")
print(json_str)
# 反序列化:JSON字符串 → Python对象
python_obj = json.loads(json_str)
print("\nPython对象:")
print(python_obj)
2.2.2 文件读写操作
import json
# 写入JSON文件
data = {"name": "李四", "scores": [85, 92, 78]}
with open('data.json', 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
# 读取JSON文件
with open('data.json', 'r', encoding='utf-8') as f:
loaded_data = json.load(f)
print("从文件读取的数据:", loaded_data)
2.2.3 处理复杂JSON数据
import json
# 复杂的疫情数据示例
epidemic_data = {
"status": 0,
"msg": "success",
"data": {
"name": "日本",
"trend": {
"updateDate": ["1.20", "1.21", "1.22", "1.23"],
"list": [
{
"name": "确诊",
"data": [10, 15, 20, 25]
},
{
"name": "治愈",
"data": [2, 3, 5, 8]
}
]
}
}
}
# 提取特定数据
trend_data = epidemic_data["data"]["trend"]
dates = trend_data["updateDate"]
confirmed_cases = trend_data["list"][0]["data"]
print("日期:", dates)
print("确诊人数:", confirmed_cases)
三、pyecharts模块详解
3.1 pyecharts简介
3.1.1 什么是pyecharts
pyecharts是百度开源的数据可视化库Echarts的Python接口,结合了Python的数据处理能力和Echarts的丰富图表类型。
优势特点:
- 丰富的图表类型:折线图、柱状图、饼图、地图等
- 交互性强:支持鼠标悬停、缩放、拖拽等交互
- 配置灵活:高度可定制的图表样式
- 输出多样:支持HTML、图片等多种输出格式
3.1.2 安装与环境配置
# 基础安装
pip install pyecharts
# 安装地图扩展(如果需要地图功能)
pip install echarts-countries-pypkg # 世界地图
pip install echarts-china-provinces-pypkg # 中国省份地图
pip install echarts-china-cities-pypkg # 中国城市地图
3.2 官方资源与学习
- 官方画廊:https://gallery.pyecharts.org
- 官方文档:https://pyecharts.org
- GitHub仓库:https://github.com/pyecharts/pyecharts
四、pyecharts快速入门
4.1 基础折线图创建
4.1.1 最简单的折线图
from pyecharts.charts import Line
# 创建折线图对象
line = Line()
# 添加X轴数据(分类数据)
line.add_xaxis(["1月", "2月", "3月", "4月", "5月"])
# 添加Y轴数据(数值数据)
line.add_yaxis("销售额", [100, 200, 150, 300, 250])
# 生成HTML文件
line.render("basic_line.html")
4.1.2 多系列折线图
from pyecharts.charts import Line
line = Line()
# X轴数据
months = ["1月", "2月", "3月", "4月", "5月", "6月"]
# 添加多个数据系列
line.add_xaxis(months)
line.add_yaxis("产品A", [120, 132, 101, 134, 90, 230])
line.add_yaxis("产品B", [150, 182, 191, 234, 290, 330])
line.add_yaxis("产品C", [320, 332, 301, 334, 390, 330])
# 渲染图表
line.render("multi_series_line.html")
4.2 全局配置选项
4.2.1 标题配置
from pyecharts import options as opts
from pyecharts.charts import Line
line = Line()
# 基础数据
line.add_xaxis(["1月", "2月", "3月", "4月"])
line.add_yaxis("销量", [100, 200, 150, 300])
# 全局配置
line.set_global_opts(
title_opts=opts.TitleOpts(
title="2023年销售趋势", # 主标题
subtitle="单位:万元", # 副标题
pos_left="center", # 标题位置
title_textstyle_opts=opts.TextStyleOpts(color="#333", font_size=16)
)
)
line.render("title_config.html")
4.2.2 坐标轴配置
line.set_global_opts(
# X轴配置
xaxis_opts=opts.AxisOpts(
name="时间", # 轴名称
name_location="end", # 名称位置
name_gap=20, # 名称与轴线距离
axislabel_opts=opts.LabelOpts(rotate=45) # 标签旋转
),
# Y轴配置
yaxis_opts=opts.AxisOpts(
name="销量",
name_location="end",
name_gap=30,
min_=0, # 最小值
max_=400 # 最大值
)
)
4.2.3 图例与工具箱
line.set_global_opts(
# 图例配置
legend_opts=opts.LegendOpts(
is_show=True, # 是否显示图例
pos_left="right", # 图例位置
orient="vertical", # 排列方向
textstyle_opts=opts.TextStyleOpts(font_size=12)
),
# 工具箱配置
toolbox_opts=opts.ToolboxOpts(
is_show=True, # 显示工具箱
feature={
"saveAsImage": {}, # 保存图片
"restore": {}, # 还原
"dataView": {}, # 数据视图
"dataZoom": {}, # 数据缩放
"magicType": {"type": ["line", "bar"]} # 图表类型切换
}
)
)
五、数据处理实战
5.1 疫情数据预处理
5.1.1 原始数据格式分析
// 原始数据格式(包含JSONP包装)
jsonp_1629350871167_29498({
"status": 0,
"msg": "success",
"data": {
"name": "日本",
"trend": {
"updateDate": ["1.20", "1.21", "1.22", "1.23"],
"list": [
{
"name": "确诊",
"data": [10, 15, 20, 25]
}
]
}
}
})
5.1.2 数据清洗与提取
import json
import re
def process_epidemic_data(raw_data):
"""
处理疫情原始数据,提取结构化信息
:param raw_data: 原始数据字符串
:return: 处理后的数据字典
"""
try:
# 1. 移除JSONP包装
# 匹配 jsonp_xxx(...) 格式
pattern = r'^[a-zA-Z_][a-zA-Z0-9_]*\('
cleaned_data = re.sub(pattern, '', raw_data)
cleaned_data = cleaned_data.rstrip(');')
# 2. 解析JSON数据
data_dict = json.loads(cleaned_data)
# 3. 提取趋势数据
trend_data = data_dict["data"]["trend"]
# 4. 按年份筛选数据(2020年)
dates = trend_data["updateDate"]
confirmed_data = trend_data["list"][0]["data"] # 确诊数据
# 假设前314个数据点是2020年的
dates_2020 = dates[:314]
confirmed_2020 = confirmed_data[:314]
return {
"country": data_dict["data"]["name"],
"dates": dates_2020,
"confirmed": confirmed_2020
}
except (json.JSONDecodeError, KeyError, IndexError) as e:
print(f"数据处理错误: {e}")
return None
# 使用示例
raw_data = 'jsonp_1629350871167_29498({"status":0,"msg":"success","data":{"name":"日本","trend":{"updateDate":["1.20","1.21"],"list":[{"name":"确诊","data":[10,15]}]}}})'
processed_data = process_epidemic_data(raw_data)
print(processed_data)
5.2 多国数据整合
def load_multiple_countries_data():
"""
加载并整合多国疫情数据
"""
countries_data = {}
# 模拟多个国家的数据处理
countries = ["美国", "印度", "日本"]
for country in countries:
# 这里应该是从实际数据源加载数据
# 模拟数据
if country == "美国":
dates = [f"2020.{i+1:02d}.{j+1:02d}" for i in range(12) for j in range(26)]
confirmed = [i*1000 + j*100 for i in range(12) for j in range(26)]
elif country == "印度":
dates = [f"2020.{i+1:02d}.{j+1:02d}" for i in range(12) for j in range(26)]
confirmed = [i*800 + j*80 for i in range(12) for j in range(26)]
else: # 日本
dates = [f"2020.{i+1:02d}.{j+1:02d}" for i in range(12) for j in range(26)]
confirmed = [i*600 + j*60 for i in range(12) for j in range(26)]
countries_data[country] = {
"dates": dates[:314], # 取2020年数据
"confirmed": confirmed[:314]
}
return countries_data
# 加载数据
epidemic_data = load_multiple_countries_data()
print("加载的国家:", list(epidemic_data.keys()))
六、创建专业折线图
6.1 完整疫情折线图实现
6.1.1 基础图表结构
from pyecharts.charts import Line
from pyecharts import options as opts
from pyecharts.commons.utils import JsCode
def create_epidemic_chart(epidemic_data):
"""
创建疫情数据折线图
:param epidemic_data: 处理后的疫情数据
:return: 折线图对象
"""
# 初始化图表
line = Line(
init_opts=opts.InitOpts(
width="1400px",
height="700px",
bg_color="#f5f5f5"
)
)
return line
6.1.2 添加数据系列
def add_data_series(line, epidemic_data):
"""添加数据系列到图表"""
# 使用第一个国家的日期作为X轴(假设所有国家日期相同)
first_country = list(epidemic_data.keys())[0]
dates = epidemic_data[first_country]["dates"]
# 添加X轴数据
line.add_xaxis(dates)
# 定义颜色方案
colors = ["#c23531", "#2f4554", "#61a0a8", "#d48265"]
# 为每个国家添加数据系列
for i, (country, data) in enumerate(epidemic_data.items()):
line.add_yaxis(
series_name=f"{country}确诊人数",
y_axis=data["confirmed"],
is_smooth=True, # 平滑曲线
symbol="circle", # 数据点形状
symbol_size=6, # 数据点大小
color=colors[i % len(colors)],
# 线条样式
linestyle_opts=opts.LineStyleOpts(width=3),
# 标签样式
label_opts=opts.LabelOpts(
is_show=False, # 默认不显示数据标签
position="top",
font_size=10
),
# 区域填充
areastyle_opts=opts.AreaStyleOpts(
opacity=0.1, # 填充透明度
color=JsCode(f"""
function(params) {{
return '{colors[i % len(colors)]}';
}}
""")
)
)
return line
6.1.3 完整图表配置
def configure_chart(line):
"""配置图表全局选项"""
line.set_global_opts(
# 标题配置
title_opts=opts.TitleOpts(
title="2020年新冠疫情累计确诊人数趋势",
subtitle="数据来源:百度疫情实时大数据报告",
pos_left="center",
title_textstyle_opts=opts.TextStyleOpts(
color="#2c3e50",
font_size=20,
font_weight="bold"
),
subtitle_textstyle_opts=opts.TextStyleOpts(
color="#7f8c8d",
font_size=12
)
),
# 图例配置
legend_opts=opts.LegendOpts(
is_show=True,
pos_left="10%",
pos_top="10%",
orient="horizontal",
textstyle_opts=opts.TextStyleOpts(font_size=12)
),
# X轴配置
xaxis_opts=opts.AxisOpts(
name="时间",
name_location="end",
type_="category",
axislabel_opts=opts.LabelOpts(
rotate=45,
font_size=10,
interval=30 # 间隔显示标签
),
axiline_opts=opts.AxisLineOpts(
linestyle_opts=opts.LineStyleOpts(color="#bdc3c7")
)
),
# Y轴配置
yaxis_opts=opts.AxisOpts(
name="累计确诊人数",
name_location="end",
type_="value",
name_gap=30,
axislabel_opts=opts.LabelOpts(
font_size=10,
formatter="{value} 人"
),
splitline_opts=opts.SplitLineOpts(
is_show=True,
linestyle_opts=opts.LineStyleOpts(
color="#ecf0f1",
type_="dashed"
)
)
),
# 工具箱配置
toolbox_opts=opts.ToolboxOpts(
is_show=True,
pos_left="right",
feature={
"saveAsImage": {
"title": "保存为图片",
"pixel_ratio": 2
},
"restore": {"title": "还原"},
"dataView": {
"title": "数据视图",
"lang": ["数据视图", "关闭", "刷新"]
},
"dataZoom": {
"title": {"zoom": "区域缩放", "back": "缩放还原"}
},
"magicType": {
"type": ["line", "bar"],
"title": {"line": "折线图", "bar": "柱状图"}
}
}
),
# 数据区域缩放
datazoom_opts=[
opts.DataZoomOpts(
type_="inside", # 内置型数据区域缩放
xaxis_index=[0], # 控制第一个x轴
range_start=0,
range_end=100
),
opts.DataZoomOpts(
type_="slider", # 滑动条型数据区域缩放
xaxis_index=[0],
pos_bottom="5%",
range_start=0,
range_end=100
)
],
# 提示框配置
tooltip_opts=opts.TooltipOpts(
trigger="axis",
axispointer_opts=opts.AxisPointerOpts(
type_="cross",
label=opts.LabelOpts(background_color="#6a7985")
),
background_color="rgba(0,0,0,0.7)",
border_color="#ccc",
textstyle_opts=opts.TextStyleOpts(color="#fff")
)
)
return line
6.2 高级功能扩展
6.2.1 鼠标悬停效果增强
def enhance_tooltip(line):
"""增强提示框功能"""
line.set_series_opts(
tooltip_opts=opts.TooltipOpts(
trigger="axis",
formatter=JsCode("""
function(params) {
let result = params[0].name + '<br/>';
params.forEach(function(item) {
// 格式化数字,添加千分位分隔符
let value = item.value.toLocaleString();
result += item.marker + ' ' + item.seriesName + ': ' + value + '人<br/>';
});
return result;
}
""")
)
)
return line
6.2.2 响应式配置
def make_chart_responsive(line):
"""使图表响应式"""
# 添加响应式JavaScript代码
line.add_js_funcs("""
// 窗口大小改变时重绘图表
window.addEventListener('resize', function() {
chart.resize();
});
""")
return line
七、完整案例实现
7.1 主程序整合
import json
import re
from pyecharts.charts import Line
from pyecharts import options as opts
from pyecharts.commons.utils import JsCode
def main():
"""主函数:完整的疫情数据可视化案例"""
print("开始处理疫情数据可视化...")
# 1. 加载和预处理数据
epidemic_data = load_multiple_countries_data()
print("数据加载完成")
# 2. 创建基础图表
line_chart = create_epidemic_chart(epidemic_data)
# 3. 添加数据系列
line_chart = add_data_series(line_chart, epidemic_data)
# 4. 配置图表
line_chart = configure_chart(line_chart)
line_chart = enhance_tooltip(line_chart)
line_chart = make_chart_responsive(line_chart)
# 5. 生成图表
output_file = "2020_pandemic_trend.html"
line_chart.render(output_file)
print(f"图表已生成: {output_file}")
return line_chart
def load_multiple_countries_data():
"""
模拟加载多国疫情数据
实际应用中应从API或文件加载真实数据
"""
# 这里使用模拟数据代替真实数据加载
countries_data = {}
countries = ["美国", "印度", "日本"]
for country in countries:
# 生成模拟的日期和数据
dates = []
confirmed = []
# 生成2020年的日期(简化版)
for month in range(1, 13):
for day in range(1, 27): # 每月26天,简化处理
dates.append(f"2020.{month:02d}.{day:02d}")
# 生成模拟的确诊数据(指数增长趋势)
base_cases = 100
growth_rate = 1.05 # 日增长率5%
current_cases = base_cases
for _ in range(len(dates)):
confirmed.append(int(current_cases))
current_cases *= growth_rate
countries_data[country] = {
"dates": dates,
"confirmed": confirmed
}
return countries_data
if __name__ == "__main__":
# 运行主程序
chart = main()
# 在Jupyter Notebook中显示图表
# chart.render_notebook()
7.2 效果优化与调试
7.2.1 性能优化
def optimize_performance(line):
"""图表性能优化"""
# 对于大数据量,启用数据采样
line.set_series_opts(
large=True, # 开启大数据模式
large_threshold=2000 # 数据量阈值
)
return line
7.2.2 移动端适配
def mobile_optimization(line):
"""移动端优化"""
line.set_global_opts(
# 移动端触摸优化
touch_opts=opts.TouchOpts(
is_touch=True,
is_prevent_default=False
)
)
return line
八、扩展功能
8.1 数据导出功能
import pandas as pd
from pyecharts.components import Table
from pyecharts.charts import Page
def export_data_table(epidemic_data, filename="疫情数据汇总.html"):
"""导出数据表格"""
# 创建数据表格
table = Table()
headers = ["日期"] + list(epidemic_data.keys())
rows = []
# 获取第一个国家的日期作为基准
first_country = list(epidemic_data.keys())[0]
dates = epidemic_data[first_country]["dates"]
for i, date in enumerate(dates):
row = [date]
for country in epidemic_data.keys():
if i < len(epidemic_data[country]["confirmed"]):
row.append(str(epidemic_data[country]["confirmed"][i]))
else:
row.append("N/A")
rows.append(row)
table.add(headers, rows)
# 创建页面,包含图表和表格
page = Page(layout=Page.SimplePageLayout)
page.add(
create_epidemic_chart(epidemic_data),
table
)
page.render(filename)
print(f"数据报表已生成: {filename}")
# 使用示例
# export_data_table(epidemic_data)
8.2 自动化报告生成
def generate_automated_report(epidemic_data):
"""生成自动化分析报告"""
# 计算统计信息
stats = {}
for country, data in epidemic_data.items():
cases = data["confirmed"]
stats[country] = {
"最大确诊数": max(cases),
"最终确诊数": cases[-1],
"平均日增长": (cases[-1] - cases[0]) / len(cases)
}
# 生成分析文本
analysis_text = "## 2020年新冠疫情分析报告\n\n"
analysis_text += "### 各国疫情数据汇总\n\n"
for country, stat in stats.items():
analysis_text += f"**{country}**:\n"
analysis_text += f"- 最高确诊: {stat['最大确诊数']:,} 人\n"
analysis_text += f"- 年末确诊: {stat['最终确诊数']:,} 人\n"
analysis_text += f"- 日均增长: {stat['平均日增长']:,.0f} 人/天\n\n"
print(analysis_text)
return analysis_text
# 生成报告
# report = generate_automated_report(epidemic_data)

浙公网安备 33010602011771号