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() / 200for 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),字体大小为16ax.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 函数进行绘制。
-
调整图形的布局并显示图形。