import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
from matplotlib.animation import FuncAnimation
import matplotlib.patches as mpatches
from matplotlib.animation import FFMpegWriter
# 定义一个函数,用于生成颜色列表
def generate_colors(string_list):
num_colors = len(string_list)
# 使用tab10调色板,可以根据需要选择不同的调色板
colormap = plt.cm.get_cmap('tab10', num_colors)
colors = []
for i in range(num_colors):
color = colormap(i)
colors.append(color)
return colors
# 读取CSV文件,并选择所需的列
# 数据地址:https://media.geeksforgeeks.org/wp-content/cdn-uploads/20210901121516/city_populations.csv
df = pd.read_csv(r'C:\Users\wangkejun\Desktop\city_populations.csv', usecols=[
'name', 'group', 'year', 'value'])
# 将年份列转换为整数型
df['year'] = df['year'].astype(int)
# 将人口数量列转换为浮点型
df['value'] = df['value'].astype(float)
# 获取城市分组列表
group = list(set(df.group))
# 生成城市分组对应的颜色字典
group_clolor = dict(zip(group, generate_colors(group)))
# 创建城市名称与分组的字典
group_name = df.set_index('name')['group'].to_dict()
# 定义绘制柱状图的函数
def draw_barchart(year):
# 根据年份筛选数据,并按人口数量进行降序排序,取出最大范围的数据
df_year = df[df['year'].eq(year)].sort_values(
by='value', ascending=True).tail(max_range)
ax.clear()
# 绘制水平柱状图,并设置颜色
ax.barh(df_year['name'], df_year['value'], color=[
group_clolor[group_name[x]] for x in df_year['name']])
# 在柱状图上方添加文字标签
dx = df_year['value'].max() / 200
for i, (value, name) in enumerate(zip(df_year['value'], df_year['name'])):
# 城市名
ax.text(value-dx, i, name,
size=12, weight=600,
ha='right', va='bottom')
ax.text(value-dx, i-0.25, group_name[name],
size=10, color='#333333',
ha='right', va='baseline')
# 地区名
ax.text(value+dx, i, f'{value:,.0f}',
size=12, ha='left', va='center')
# 设置其他样式
ax.text(1, 0.2, year, transform=ax.transAxes,
color='#777777', size=46, ha='right',
weight=800)
ax.text(0, 1.06, 'Population (thousands)',
transform=ax.transAxes, size=12,
color='#777777')
# 添加图例
handles = []
for name, color in group_clolor.items():
patch = mpatches.Patch(color=color, label=name)
handles.append(patch)
ax.legend(handles=handles, fontsize=12, loc='center', bbox_to_anchor=(
0.5, -0.03), ncol=len(group_clolor), frameon=False)
# x轴的主要刻度格式化,不保留小数
ax.xaxis.set_major_formatter(ticker.StrMethodFormatter('{x:,.0f}'))
# 将x轴的刻度位置设置在图的顶部
ax.xaxis.set_ticks_position('top')
# 设置x轴的刻度颜色为灰色(#777777),字体大小为16
ax.tick_params(axis='x', colors='#777777', labelsize=16)
# 清除y轴的刻度标签
ax.set_yticks([])
# 在x轴和y轴上设置0.01的边距
ax.margins(0, 0.01)
# 在x轴上绘制主要网格线,线条样式为实线
ax.grid(which='major', axis='x', linestyle='-')
# 设置网格线绘制在图像下方
ax.set_axisbelow(True)
# 添加绘图信息
ax.text(0, 1.10, f'The {max_range} most populous cities in the world from {start_year} to {end_year}',
transform=ax.transAxes, size=24, weight=600, ha='left')
ax.text(1, 0, 'Produced by luohenyueji',
transform=ax.transAxes, ha='right', color='#777777',
bbox=dict(facecolor='white', alpha=0.8, edgecolor='white'))
plt.box(False)
# 创建绘图所需的figure和axes
fig, ax = plt.subplots(figsize=(12, 8))
start_year = 2000
end_year = 2020
# 设置最多显示城市数量
max_range = 15
# 获取数据中的最小年份和最大年份,并进行校验
min_year, max_year = min(set(df.year)), max(set(df.year))
assert min_year <= start_year, f"end_year cannot be lower than {min_year}"
assert end_year <= max_year, f"end_year cannot be higher than {max_year}"
# 创建动画对象,调用draw_barchart函数进行绘制
ani = FuncAnimation(fig, draw_barchart, frames=range(
start_year, end_year+1), repeat_delay=1000, interval=200)
fig.subplots_adjust(left=0.04, right=0.94, bottom=0.05)
# 显示图形
plt.show()
-
库:pandas 用于数据处理,matplotlib 用于绘图,matplotlib.ticker 用于设置刻度格式,matplotlib.animation 中的 FuncAnimation 用于创建动画,matplotlib.patches 用于创建图例,FFMpegWriter 用于保存动画。
-
定义了一个函数 generate_colors(string_list),用于生成颜色列表。
-
使用 pandas 读取城市人口数据的 CSV 文件,并选择所需的列。
-
将年份列和人口数量列转换为整数型和浮点型。
-
获取城市分组列表,并生成城市分组对应的颜色字典。
-
创建城市名称与分组的字典。
-
定义了绘制柱状图的函数 draw_barchart(year),用于根据年份绘制相应的水平柱状图。
-
在 draw_barchart 函数中,根据年份筛选数据并按人口数量进行降序排序,绘制柱状图并添加标签、图例等。
-
设置了图形的样式,包括文字标签、图例、刻度格式化、网格线等。
-
创建绘图所需的 figure 和 axes,并设置起始年份、结束年份以及最多显示城市数量。
-
创建动画对象 FuncAnimation,并调用 draw_barchart 函数进行绘制。
-
调整图形的布局并显示图形。