This commit is contained in:
2025-09-10 15:42:32 +08:00
parent 177ea6dca8
commit e3dcdc8800
6 changed files with 140 additions and 197 deletions

View File

@@ -0,0 +1,133 @@
import json
import os
from pyecharts import options as opts
from pyecharts.charts import Bar, Line
from pyecharts.globals import CurrentConfig
# 配置使用自定义的ECharts路径
CurrentConfig.ONLINE_HOST = "https://gcore.jsdelivr.net/npm/echarts@6.0.0/dist/"
class RenkouModel:
@staticmethod
def load_population_data():
try:
# 获取当前文件所在目录的父目录然后找到Data文件夹
current_dir = os.path.dirname(os.path.abspath(__file__))
project_root = os.path.dirname(current_dir) # 修正路径计算,只需要上一级目录
data_path = os.path.join(project_root, "Data", "RenKou.json")
with open(data_path, "r", encoding="utf-8") as f:
data = json.load(f)
return data
except Exception as e:
print(f"读取人口数据出错: {e}")
return []
@staticmethod
def generate_population_chart_config(year="2024"):
# 加载人口数据
population_data = RenkouModel.load_population_data()
# 筛选出州市级数据
cities = [item for item in population_data if len(item["area_code"]) == 9 and item["area_code"].endswith("000") and item["area_code"][4:6] == "00" and item["area_code"][2:8] != "000000"]
# 提取城市名称和人口数据
city_names = [city["area_name"] for city in cities]
total_populations = [city["total_population"].get(year, 0) for city in cities]
urban_populations = [city["urban_population"].get(year, 0) for city in cities]
rural_populations = [city["rural_population"].get(year, 0) for city in cities]
# 创建柱状图
c = (
Bar()
.add_xaxis(city_names)
.add_yaxis("总人口", total_populations, stack="stack1")
.add_yaxis("城镇人口", urban_populations, stack="stack1")
.add_yaxis("农村人口", rural_populations, stack="stack1")
.set_global_opts(
title_opts=opts.TitleOpts(
title=f"云南省各州市人口分布图({year}年)",
pos_top="1%",
pos_left="center"
),
tooltip_opts=opts.TooltipOpts(
trigger="axis",
axis_pointer_type="shadow"
),
legend_opts=opts.LegendOpts(
pos_top="8%",
pos_right="5%"
),
datazoom_opts=[opts.DataZoomOpts()],
xaxis_opts=opts.AxisOpts(
axislabel_opts=opts.LabelOpts(rotate=45)
),
yaxis_opts=opts.AxisOpts(
name="人口数量(万人)",
name_location="middle",
name_gap=40
)
)
.set_series_opts(
label_opts=opts.LabelOpts(is_show=False),
markline_opts=opts.MarkLineOpts(
data=[opts.MarkLineItem(type_="average", name="平均值")]
)
)
)
# 获取图表的选项配置
options_str = c.dump_options_with_quotes()
return json.loads(options_str)
@staticmethod
def generate_urbanization_rate_chart_config():
# 加载人口数据
population_data = RenkouModel.load_population_data()
# 筛选出州市级数据
cities = [item for item in population_data if len(item["area_code"]) == 9 and item["area_code"].endswith("000") and item["area_code"][4:6] == "00" and item["area_code"][2:8] != "000000"]
# 提取城市名称
city_names = [city["area_name"] for city in cities]
# 创建折线图
line = (
Line()
.add_xaxis(city_names)
)
# 添加各年份的城镇化率数据
years = ["2020", "2021", "2022", "2023", "2024"]
for year in years:
urbanization_rates = [city["urbanization_rate"].get(year, 0) for city in cities]
line.add_yaxis(f"{year}", urbanization_rates,
markpoint_opts=opts.MarkPointOpts(data=[opts.MarkPointItem(type_="max")]))
line.set_global_opts(
title_opts=opts.TitleOpts(
title="云南省各州市城镇化率变化趋势",
pos_top="1%",
pos_left="center"
),
tooltip_opts=opts.TooltipOpts(trigger="axis"),
legend_opts=opts.LegendOpts(
pos_top="8%",
pos_right="5%"
),
datazoom_opts=[opts.DataZoomOpts()],
xaxis_opts=opts.AxisOpts(
axislabel_opts=opts.LabelOpts(rotate=45)
),
yaxis_opts=opts.AxisOpts(
name="城镇化率(%",
name_location="middle",
name_gap=40,
min_=0,
max_=100
)
)
# 获取图表的选项配置
options_str = line.dump_options_with_quotes()
return json.loads(options_str)

Binary file not shown.

Binary file not shown.

View File

@@ -1,213 +1,27 @@
from fastapi import APIRouter from fastapi import APIRouter
import pyecharts
from pyecharts import options as opts
from pyecharts.charts import Bar, Line
from pyecharts.faker import Faker
from pyecharts.globals import CurrentConfig
import json import json
import os from Model.RenkouModel import RenkouModel
# 创建APIRouter实例 # 创建APIRouter实例
router = APIRouter(prefix="/bigscreen", tags=["大屏展示"]) router = APIRouter(prefix="/bigscreen", tags=["大屏展示"])
# 配置使用自定义的 ECharts 路径 # 定义路由
CurrentConfig.ONLINE_HOST = "https://gcore.jsdelivr.net/npm/echarts@6.0.0/dist/"
# 定义一个 helloWorld 路由
@router.get("/") @router.get("/")
async def root(): async def root():
return {"message": "Welcome to YunNan Education World!"} return {"message": "Welcome to YunNan Education World!"}
# 生成图表配置的函数
def generate_bar_chart_config():
c = (
Bar()
.add_xaxis(Faker.choose())
.add_yaxis("商家A", Faker.values())
.add_yaxis("商家B", Faker.values())
.set_global_opts(title_opts=opts.TitleOpts(title="Bar-MarkLine自定义"))
.set_series_opts(
label_opts=opts.LabelOpts(is_show=False),
markline_opts=opts.MarkLineOpts(
data=[opts.MarkLineItem(y=50, name="yAxis=50")]
),
)
)
# 获取图表的选项配置,使用 dump_options_with_quotes 方法获取可以直接序列化的选项
options_str = c.dump_options_with_quotes()
# 将字符串转换为 JSON 对象
options_json = json.loads(options_str)
return options_json
# 定义一个返回图表配置的路由
@router.get("/chart/bar") @router.get("/chart/bar")
async def get_bar_chart_config(): async def get_bar_chart_config():
""" return RenkouModel.generate_population_chart_config()
获取柱状图配置
"""
chart_config = generate_bar_chart_config()
return chart_config
# 读取人口数据
def load_population_data():
try:
# 获取当前文件所在目录的父目录然后找到Data文件夹
current_dir = os.path.dirname(os.path.abspath(__file__))
project_root = os.path.dirname(current_dir)
data_path = os.path.join(project_root, "Data", "RenKou.json")
with open(data_path, "r", encoding="utf-8") as f:
data = json.load(f)
return data
except Exception as e:
print(f"读取人口数据出错: {e}")
return []
# 生成人口数据图表配置
def generate_population_chart_config(year="2024"):
# 加载人口数据
population_data = load_population_data()
# 筛选出州市级数据(排除县级数据)
# 正确的格式是9位数字以000结尾且第5-6位为00表示州市级
cities = [item for item in population_data if len(item["area_code"]) == 9 and item["area_code"].endswith("000") and item["area_code"][4:6] == "00"]
# 提取城市名称和人口数据
city_names = [city["area_name"] for city in cities]
total_populations = [city["total_population"].get(year, 0) for city in cities]
urban_populations = [city["urban_population"].get(year, 0) for city in cities]
rural_populations = [city["rural_population"].get(year, 0) for city in cities]
# 创建柱状图
c = (
Bar()
.add_xaxis(city_names)
.add_yaxis("总人口", total_populations, stack="stack1")
.add_yaxis("城镇人口", urban_populations, stack="stack1")
.add_yaxis("农村人口", rural_populations, stack="stack1")
.set_global_opts(
title_opts=opts.TitleOpts(
title=f"云南省各州市人口分布图({year}年)",
pos_top="1%", # 调整标题位置到顶部1%
pos_left="center"
),
tooltip_opts=opts.TooltipOpts(
trigger="axis",
axis_pointer_type="shadow"
),
legend_opts=opts.LegendOpts(
pos_top="8%", # 调整图例位置到标题下方
pos_right="5%"
),
datazoom_opts=[opts.DataZoomOpts()],
xaxis_opts=opts.AxisOpts(
axislabel_opts=opts.LabelOpts(rotate=45)
),
yaxis_opts=opts.AxisOpts(
name="人口数量(万人)",
name_location="middle",
name_gap=40
)
)
.set_series_opts(
label_opts=opts.LabelOpts(is_show=False),
markline_opts=opts.MarkLineOpts(
data=[opts.MarkLineItem(type_="average", name="平均值")]
)
)
)
# 获取图表的选项配置
options_str = c.dump_options_with_quotes()
# 将字符串转换为 JSON 对象
options_json = json.loads(options_str)
return options_json
# 生成城镇化率图表配置
def generate_urbanization_rate_chart_config():
# 加载人口数据
population_data = load_population_data()
# 筛选出州市级数据(排除县级数据)
# 排除省级数据(如云南省530000000)和县级数据,只保留州市级数据
cities = [item for item in population_data if len(item["area_code"]) == 9 and item["area_code"].endswith("000") and item["area_code"][4:6] == "00" and item["area_code"][2:8] != "000000"]
# 提取城市名称和城镇化率数据
city_names = [city["area_name"] for city in cities]
# 创建折线图
line = (
Line()
.add_xaxis(city_names)
)
# 添加各年份的城镇化率数据
years = ["2020", "2021", "2022", "2023", "2024"]
for year in years:
urbanization_rates = [city["urbanization_rate"].get(year, 0) for city in cities]
line.add_yaxis(f"{year}", urbanization_rates,
markpoint_opts=opts.MarkPointOpts(data=[opts.MarkPointItem(type_="max")]))
line.set_global_opts(
title_opts=opts.TitleOpts(
title="云南省各州市城镇化率变化趋势",
pos_top="1%", # 调整标题位置到顶部1%
pos_left="center"
),
tooltip_opts=opts.TooltipOpts(trigger="axis"),
legend_opts=opts.LegendOpts(
pos_top="8%", # 调整图例位置到标题下方
pos_right="5%"
),
datazoom_opts=[opts.DataZoomOpts()],
xaxis_opts=opts.AxisOpts(
axislabel_opts=opts.LabelOpts(rotate=45)
),
yaxis_opts=opts.AxisOpts(
name="城镇化率(%",
name_location="middle",
name_gap=40,
min_=0,
max_=100
)
)
# 获取图表的选项配置
options_str = line.dump_options_with_quotes()
# 将字符串转换为 JSON 对象
options_json = json.loads(options_str)
return options_json
# 定义一个返回人口数据图表配置的路由
@router.get("/population/chart/{year}") @router.get("/population/chart/{year}")
async def get_population_chart_config(year: str = "2024"): async def get_population_chart_config(year: str = "2024"):
""" return RenkouModel.generate_population_chart_config(year)
获取人口数据图表配置
"""
chart_config = generate_population_chart_config(year)
return chart_config
# 定义一个返回城镇化率图表配置的路由
@router.get("/population/urbanization") @router.get("/population/urbanization")
async def get_urbanization_rate_chart_config(): async def get_urbanization_rate_chart_config():
""" return RenkouModel.generate_urbanization_rate_chart_config()
获取城镇化率图表配置
"""
chart_config = generate_urbanization_rate_chart_config()
return chart_config
# 定义一个返回人口数据原始数据的路由
@router.get("/population/data") @router.get("/population/data")
async def get_population_data(): async def get_population_data():
""" return {"data": RenkouModel.load_population_data()}
获取人口数据原始数据
"""
population_data = load_population_data()
return {"data": population_data}

View File

@@ -30,19 +30,15 @@
<option value="2023">2023年</option> <option value="2023">2023年</option>
<option value="2024" selected>2024年</option> <option value="2024" selected>2024年</option>
</select> </select>
<button id="loadPopulationChart">加载图表</button>
</div> </div>
<div id="populationChart" class="chart"></div> <div id="populationChart" class="chart"></div>
<!-- <div class="message" id="populationMessage">点击"加载图表"按钮获取数据</div>-->
</div> </div>
<div class="tab-content" id="urbanization-tab"> <div class="tab-content" id="urbanization-tab">
<h2>云南省各州市城镇化率变化趋势</h2> <h2>云南省各州市城镇化率变化趋势</h2>
<div class="controls"> <div class="controls">
<button id="loadUrbanizationChart">加载图表</button>
</div> </div>
<div id="urbanizationChart" class="chart"></div> <div id="urbanizationChart" class="chart"></div>
<div class="message" id="urbanizationMessage">点击"加载图表"按钮获取数据</div>
</div> </div>
</div> </div>