【数据可视化(二)】Pyecharts绘制带timeline的地图

Pyecharts绘制带timeline的地图网上有很多教程,但大多都是基于csv或txt文件的,我来分享一份使用MySQL数据库中数据的代码。

入门+工具+连接MySQL数据库+数据导入请移步文章:http://t.csdnimg.cn/aRRXV

一、需求+成果展示

Map即地图类,TimeLine为时间轴类,我们需求如下:
在这里插入图片描述
一个地图中数据随时间轴的切换而切换的综合图表。下面是程序编写过程。

二、数据预处理

我们的数据格式为(date,spot,temp):日期str,地点str,温度str
显然对应关系为:将数据按日期排序,可视化显示出在某一日期时所有地点对应的温度值。
上一次我们导入数据成功:

import pymysql.cursors
# 连接数据库
db = pymysql.connect(
    host="localhost",
    user="root",
    password="root",
    db="pyecharts_test",
    charset="utf8",#这里即使之前选择为“utf8mb3”,也写utf8,这是在python中的代码
)
# 查询数据
sql = "SELECT * FROM China_temp_1 "
try:
    cursor = db.cursor()
    cursor.execute(sql)
    result = cursor.fetchall()
except Exception as e:
    db.rollback()
    print("Error", e)
else:
    db.commit()
    print("Success")#输出Success即表示数据导入成功,方便以后debug
#debug代码块
    # # 打印前 5 行数据
    # print("前 5 行数据:")
    # for i in range(min(5, len(result))):
    #     print(result[i])
    # # 获取总行数
    # total_rows = len(result)
    # print(f"总共 {total_rows} 行数据")

下面是示例中的Map类:

from pyecharts import options as opts
from pyecharts.charts import Map
from pyecharts.faker import Faker

c = (
    Map()
    .add("商家A", [list(z) for z in zip(Faker.provinces, Faker.values())], "china")
    .set_global_opts(title_opts=opts.TitleOpts(title="Map-基本示例"))
    .render("map_base.html")
)

只需改写x轴和y轴对应的内容,但在此之前,需要对数据进行预处理:
数据处理的库:

import pandas as pd
import re

pyecharts可以识别DataFrame类型的数据,类似表格。
DataFrame
将数据导入得到的result转换为DataFrame形式,并打印测试

# 创建 DataFrame
df = pd.DataFrame(result, columns=['date', 'spot', 'temp'])
print(df)

df格式
pyecharts只能识别YYYY/mm/dd的日期形式,所以我们对date数据进行一下格式转换,使用正则匹配:

# 定义日期转换函数
def convert_date(date_str):
    # 检查日期格式是否为“2020年1月1日”
    match1 = re.match(r"(\d{4})年(\d{1,2})月(\d{1,2})日", date_str)
    # 检查日期格式是否为“2020-1-1”
    match2 = re.match(r"(\d{4})-(\d{1,2})-(\d{1,2})", date_str)
    if match1:
        year, month, day = match1.groups()
        # 转换为“2020/1/1”格式
        return f"{year}/{month}/{day}"
    if match2:
        year, month, day = match2.groups()
        # 转换为“2020/1/1”格式
        return f"{year}/{month}/{day}"
    return date_str
# 应用日期转换函数
df['date'] = df['date'].apply(convert_date)

这里转换后的格式为String类型,Map类需要datetime类型的数据,转换一下:

# 将日期列转换为 datetime 格式
df['date'] = pd.to_datetime(df['date'], format='%Y/%m/%d', errors='coerce')

为了画出timeline轴,我们肯定希望日期按顺序排列,并且不重复,故先去重在排序。去重我们以【日期+地点】为标准,【】相同的去除。并将日期单独提取出来,作为时间轴之用。

# 去除重复记录
df = df.drop_duplicates(subset=['date', 'spot'], keep='first')
# 按照日期排序
df = df.sort_values(by='date')
# 获取唯一日期
dates = df['date'].dropna().unique()  # 去掉 NaT

三、数据传入与绘图

接下来就该创建时间轴了,代码如下:

from pyecharts import options as opts
from pyecharts.charts import Timeline, Map

其中一些样式部分,参照这张图,还有许多可以调整的部分,参照官网的说明,非常详细。
在这里插入图片描述

# 创建时间线图实例
timeline = Timeline(init_opts=opts.InitOpts(
		#时间轴总的样式部分在这里写
        theme='light',
        bg_color='rgba(0,0,0,0)'  # 设置页面背景颜色为完全透明
    )
)
timeline.add_schema(
    orient='horizontal',  # 时间轴水平显示
    is_auto_play=True,  # 自动播放
    play_interval=10,  # 播放间隔时间,单位毫秒
    label_opts=opts.LabelOpts(
    	#标签的样式在这里写
        is_show=True,  # 显示标签
        font_family='Arial',  # 标签字体样式
        rotate=-5,  # 标签旋转角度
        # distance='30px',  # 垂直偏移量,向下移动30像素
        # formatter="{value}",  # 设置标签格式为年月日,固定为一月一日
        # interval=365 * 24 * 3600 * 1000,  # 时间轴标签间隔为一年
        # color='#333',  # 标签文字颜色
        # font_size=10,  # 标签文字大小
    ),
    # control_style_opts=opts.ControlStyleOpts(
    #     position='left',  # 控制按钮位置:左侧
    #     item_size=20  # 控制按钮大小
    # )
    #其余种种样式见官网
)

接下来,开始导入数据了,我先放出完整代码:

# 遍历每个日期,创建地图并加入时间线
for date in dates:
    df_date = df[df['date'] == date]
    # 确保数据格式为 [(地区名, 数值), ...]
    province_data = df_date[['spot', 'temp']].values.tolist()
    # 数据格式检查
    if all(isinstance(item, list) and len(item) == 2 for item in province_data):
        china_map = (
            Map(init_opts=opts.InitOpts(
            #样式
            width="2000px",
            height="1000px",
            bg_color='rgba(0,0,0,0)'
            	)
            )
            .add('温度', province_data, 'china', is_map_symbol_show=False, is_roam=True) #如果要使用世界地图,将‘china’改为‘world’即可
            .set_series_opts(label_opts=opts.LabelOpts(is_show=False, color='#ffffff'))
            .set_global_opts(
            	#全局样式在这里写
                title_opts=opts.TitleOpts(
                	#标题样式
                				title=f"{date.strftime('%Y-%m-%d')}",
                                pos_left='center',
                                pos_right='center',
                                title_textstyle_opts=opts.TextStyleOpts(
                                	   #标题文本样式
                                       color='#DDF3FF',
                                       font_family='Times New Roman',
                                       font_size='30px',
                                       font_weight='bold',
                                     )
                           ),
                legend_opts=opts.LegendOpts(
                		is_show=False #图例文字,显示出来非常乱,一般关闭
                	),
                visualmap_opts=opts.VisualMapOpts(
                	#可视化核心部分,颜色随数据范围变化
                    is_piecewise=True, #True就是示例图那样分段,False就是连续的渐变
                    pos_left='280px',
                    pos_bottom='250px',
                    textstyle_opts=opts.TextStyleOpts(
                    							color='#ffffff'  # 设置字体颜色为白色
                    						), 
                    							  #温度-颜色对应关系,来自天气预报网站
                                                  pieces=[
                                                      {"max": 80, "min": 35, "label": ">35℃", "color": "#E00501"},
                                                      {"max": 34.99, "min": 32, "label": "32-35℃", "color": "#FA5702"},
                                                      {"max": 31.99, "min": 28, "label": "28-32℃", "color": "#FA9682"},
                                                      {"max": 27.99, "min": 24, "label": "24-28℃", "color": "#FFCCA1"},
                                                      {"max": 23.99, "min": 20, "label": "20-24℃", "color": "#FFF3C3"},
                                                      {"max": 19.99, "min": 16, "label": "16-20℃", "color": "#BAFB95"},
                                                      {"max": 15.99, "min": 12, "label": "12~16℃", "color": "#CEFFCE"},
                                                      {"max": 11.99, "min": 8, "label": "8~12℃", "color": "#D0FCFF"},
                                                      {"max": 7.99, "min": 4, "label": "4~8℃", "color": "#AAE9F8"},
                                                      {"max": 3.99, "min": 0, "label": "0~4℃", "color": "#85D0FF"},
                                                      {"max": -0.01, "min": -4, "label": "-4~0℃", "color": "#3E9FEC"},
                                                      {"max": -4.01, "min": -10, "label": "-10~-4℃", "color": "#2373D2"},
                                                      {"max": -10.01, "min": -20, "label": "-20~-10℃", "color": "#1C5D9E"},
                                                      {"max": -20.01, "min": -50, "label": "<-20℃", "color": "#002F87"},
                                                  ]
                                                  ),
            )
        )
        # 将地图加入时间线
        timeline.add(china_map, date.strftime('%Y-%m-%d'))#这就成了
    else:
        print(f"Data format error for date: {date.strftime('%Y-%m-%d')}")

最后,渲染为html文件,关闭数据库连接

# 渲染时间线图到 HTML 文件
timeline.render(path='AAA_pyecharts_map.html')
# 关闭数据库连接
cursor.close()
db.close()

四、运行结果

运行一下,没有报错
在这里插入图片描述
找到html文件并打开,我的数据量太大,没法直接打开,右键
在这里插入图片描述
在这里插入图片描述

前端部分我就不调了,朋友们自己设计。
完整代码:

import pymysql.cursors
import pandas as pd
import re
from pyecharts import options as opts
from pyecharts.charts import Timeline, Map
# 连接数据库
db = pymysql.connect(
    host="localhost",
    user="root",
    password="root",
    db="pyecharts_test",
    charset="utf8",#这里即使之前选择为“utf8mb3”,也写utf8,这是在python中的代码
)
# 查询数据
sql = "SELECT * FROM China_temp_1 "
try:
    cursor = db.cursor()
    cursor.execute(sql)
    result = cursor.fetchall()
except Exception as e:
    db.rollback()
    print("Error", e)
else:
    db.commit()
    print("Success")#输出Success即表示数据导入成功,方便以后debug
#debug代码块
    # # 打印前 5 行数据
    # print("前 5 行数据:")
    # for i in range(min(5, len(result))):
    #     print(result[i])
    # # 获取总行数
    # total_rows = len(result)
    # print(f"总共 {total_rows} 行数据")
# 创建 DataFrame
df = pd.DataFrame(result, columns=['date', 'spot', 'temp'])
print(df)
# 定义日期转换函数
def convert_date(date_str):
    # 检查日期格式是否为“2020年1月1日”
    match1 = re.match(r"(\d{4})年(\d{1,2})月(\d{1,2})日", date_str)
    match2 = re.match(r"(\d{4})-(\d{1,2})-(\d{1,2})", date_str)
    if match1:
        year, month, day = match1.groups()
        # 转换为“2020/1/1”格式
        return f"{year}/{month}/{day}"
    if match2:
        year, month, day = match2.groups()
        # 转换为“2020/1/1”格式
        return f"{year}/{month}/{day}"
    return date_str
# 应用日期转换函数
df['date'] = df['date'].apply(convert_date)
# 将日期列转换为 datetime 格式
df['date'] = pd.to_datetime(df['date'], format='%Y/%m/%d', errors='coerce')
# 去除重复记录
df = df.drop_duplicates(subset=['date', 'spot'], keep='first')
# 按照日期排序
df = df.sort_values(by='date')
# 获取唯一日期
dates = df['date'].dropna().unique()  # 去掉 NaT
# 创建时间线图实例
timeline = Timeline(init_opts=opts.InitOpts(
        theme='light',
        bg_color='rgba(0,0,0,0)'  # 设置页面背景颜色为完全透明
    )
)
timeline.add_schema(
    orient='horizontal',  # 时间轴水平显示
    is_auto_play=True,  # 自动播放
    play_interval=10,  # 播放间隔时间,单位毫秒
    label_opts=opts.LabelOpts(
        is_show=True,  # 显示标签
        font_family='Arial',  # 标签字体样式
        rotate=-5,  # 标签旋转角度
    ),
)
# 遍历每个日期,创建地图并加入时间线
for date in dates:
    df_date = df[df['date'] == date]
    # 确保数据格式为 [(地区名, 数值), ...]
    province_data = df_date[['spot', 'temp']].values.tolist()
    # 数据格式检查
    if all(isinstance(item, list) and len(item) == 2 for item in province_data):
        china_map = (
            Map(init_opts=opts.InitOpts(
            #样式
            width="2000px",
            height="1000px",
            bg_color='rgba(0,0,0,0)'
            	)
            )
            .add('温度', province_data, 'china', is_map_symbol_show=False, is_roam=True) #如果要使用世界地图,将‘china’改为‘world’即可
            .set_series_opts(label_opts=opts.LabelOpts(is_show=False, color='#ffffff'))
            .set_global_opts(
            	#全局样式在这里写
                title_opts=opts.TitleOpts(
                	#标题样式
                				title=f"{date.strftime('%Y-%m-%d')}",
                                pos_left='center',
                                pos_right='center',
                                title_textstyle_opts=opts.TextStyleOpts(
                                	   #标题文本样式
                                       color='#DDF3FF',
                                       font_family='Times New Roman',
                                       font_size='30px',
                                       font_weight='bold',
                                     )
                           ),
                legend_opts=opts.LegendOpts(
                		is_show=False #图例文字,显示出来非常乱,一般关闭
                	),
                visualmap_opts=opts.VisualMapOpts(
                	#可视化核心部分,颜色随数据范围变化
                    is_piecewise=True, #True就是示例图那样分段,False就是连续的渐变
                    pos_left='280px',
                    pos_bottom='250px',
                    textstyle_opts=opts.TextStyleOpts(
                    							color='#ffffff'  # 设置字体颜色为白色
                    						),
                    							  #温度-颜色对应关系,来自天气预报网站
                                                  pieces=[
                                                      {"max": 80, "min": 35, "label": ">35℃", "color": "#E00501"},
                                                      {"max": 34.99, "min": 32, "label": "32-35℃", "color": "#FA5702"},
                                                      {"max": 31.99, "min": 28, "label": "28-32℃", "color": "#FA9682"},
                                                      {"max": 27.99, "min": 24, "label": "24-28℃", "color": "#FFCCA1"},
                                                      {"max": 23.99, "min": 20, "label": "20-24℃", "color": "#FFF3C3"},
                                                      {"max": 19.99, "min": 16, "label": "16-20℃", "color": "#BAFB95"},
                                                      {"max": 15.99, "min": 12, "label": "12~16℃", "color": "#CEFFCE"},
                                                      {"max": 11.99, "min": 8, "label": "8~12℃", "color": "#D0FCFF"},
                                                      {"max": 7.99, "min": 4, "label": "4~8℃", "color": "#AAE9F8"},
                                                      {"max": 3.99, "min": 0, "label": "0~4℃", "color": "#85D0FF"},
                                                      {"max": -0.01, "min": -4, "label": "-4~0℃", "color": "#3E9FEC"},
                                                      {"max": -4.01, "min": -10, "label": "-10~-4℃", "color": "#2373D2"},
                                                      {"max": -10.01, "min": -20, "label": "-20~-10℃", "color": "#1C5D9E"},
                                                      {"max": -20.01, "min": -50, "label": "<-20℃", "color": "#002F87"},
                                                  ]
                                                  ),
            )
        )
        # 将地图加入时间线
        timeline.add(china_map, date.strftime('%Y-%m-%d'))#这就成了
    else:
        print(f"Data format error for date: {date.strftime('%Y-%m-%d')}")
# 渲染时间线图到 HTML 文件
timeline.render(path='AAA_pyecharts_map.html')
# 关闭数据库连接
cursor.close()
db.close()
Pyecharts是一个强大的数据可视化库,它支持通过JavaScript渲染图表,其中也包含了绘制地图的功能。如果你想在Pyecharts中创建动态地图,可以利用其提供的`GeoMap`组件。`GeoMap`允许你在地图上显示数据点,并且可以配合时间序列数据实现动态效果。 下面是一个简单的例子,展示如何使用Pyecharts绘制静态的中国地图并添加标记: ```python from pyecharts import options as opts from pyecharts.charts import Geo data = { '北京': 200, '上海': 250, '广州': 180, # 更多城市... } geo = ( Geo() .add("人口", data, maptype="china") .set_series_opts(label_opts=opts.LabelOpts(is_show=False)) .set_global_opts( title_opts=opts.TitleOpts(title="中国各城市人口分布"), visual_map_opts=opts.VisualMapOpts(max_=600), ) ) geo.render('China_Population_Geo.html') ``` 要实现动态地图,你可以结合`Timeline`(时间线)组件来展示随时间变化的数据。例如,如果你有按年份划分的人口数据,可以这样做: ```python import pandas as pd # 假设df是一个包含年份和对应城市人口数据的DataFrame timeline_data = df.groupby('year').sum().reset_index() timeline = ( Geo() .add_schema(maptype="china") .add("人口随时间变化", timeline_data, is_more_utils=True) .set_global_opts(TimelineOpts(data=timeline_data['year'], pos_top="1%"), VisualMapOpts(max_=[min(timeline_data['population']), max(timeline_data['population'])])) .set_series_opts(label_opts=opts.LabelOpts(position="right")) ) timeline.render('Population_Timeline_Geo.html') ``` 在这个例子中,`Timeline`会随着滑动时间轴展示每个年份的数据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值