我用夸克网盘分享了「lgbtq_rights_by_country数据集」,点击链接即可保存。
链接:https://pan.quark.cn/s/aa0fa91491e8
摘要: 本文运用Python编程实现对LGBTQ+权利相关数据的处理与可视化展示。通过直方图与地图两种可视化方式,分别从分类统计和地理分布角度呈现全球不同国家LGBTQ+权利的认可情况。
关键词:LGBTQ+权利;可视化;直方图;地理地图;数据处理
一、有关数据集:全球LGBT+权利(2025)数据集
kaggle源地址:https://www.kaggle.com/datasets/wilomentena/lgbt-rights-worldwide
有如下列数据:
- 同性性行为
- 承认同性婚姻
- 同性婚姻
- 同性伴侣收养
- 允许LGB人士公开在军队服役
- 反歧视法律涉及性取向
- 性别认同/表达相关法律
二、LGBTQ+权利数据的直方图可视化
2.1 数据准备
- 数据加载:利用
pandas
库的read_csv
函数,从指定路径'E:\\pycharm_workspace\\数据集\\lgbtq_rights_by_country.csv'
读取LGBTQ+权利相关数据,代码如下:
import pandas as pd
file_path = 'E:\\pycharm_workspace\\数据集\\lgbtq_rights_by_country.csv'
data = pd.read_csv(file_path)
- 数据预处理:为更清晰表示分类数据,将除
'Territory'
列外的其他列数据类型转换为分类类型,具体代码如下:
columns_to_convert = data.columns[1:]
for col in columns_to_convert:
data[col] = data[col].astype('category')
2.2 直方图绘制
- 创建可视化布局:使用
matplotlib
库创建一个大小为(15, 20)
的图形,并采用4行2列的子图布局,为每个问题绘制单独的条形图。
import matplotlib.pyplot as plt
import seaborn as sns
plt.figure(figsize=(15, 20))
for i, column in enumerate(columns_to_convert, 1):
plt.subplot(4, 2, i)
- 计算与绘制条形图:对每列数据计算每个类别的计数,并使用
seaborn
库的barplot
函数绘制条形图,同时避免弃用警告,代码如下:
counts = data[column].value_counts().sort_index()
sns.barplot(x=counts.index, y=counts.values, hue=counts.index, palette='viridis', legend=False)
- 设置图表属性:为每个子图设置标题、坐标轴标签,并在柱子上方显示具体数值,增强图表可读性。
plt.title(f'{column} 分布', fontsize=14)
plt.xlabel('类别', fontsize=12)
plt.ylabel('国家/地区数量', fontsize=12)
for j, v in enumerate(counts.values):
plt.text(j, v + 0.5, str(v), ha='center')
- 整体图表设置:使用
tight_layout
函数优化子图布局,设置整个图表的总标题,并显示图表。
plt.tight_layout()
plt.suptitle('全球LGBT+权利法律认可情况分布', y=1.02, fontsize=16)
plt.show()
整体代码:
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
# 设置中文字体支持(如果需要显示中文)
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
# ================== 直方图绘制 ==================
# 1. 加载数据
file_path = 'D:\\pyprogect\\图形页面编程\\lgbtq_rights_by_country\\lgbtq_rights_by_country.csv'
data = pd.read_csv(file_path)
# 2. 数据预处理:将所有列转换为分类类型
columns_to_convert = data.columns[1:] # 排除'Territory'列
for col in columns_to_convert:
data[col] = data[col].astype('category')
# 3. 创建可视化
plt.figure(figsize=(14, 12)) # 增加高度以提供更多垂直空间
# 改为 5 行 2 列布局,避免拥挤
for i, column in enumerate(columns_to_convert, 1):
plt.subplot(5, 2, i) # 更宽松的布局
counts = data[column].value_counts().sort_index()
sns.barplot(x=counts.index, y=counts.values, hue=counts.index, palette='viridis', legend=False)
plt.title(f'{column}', fontsize=10) # 更小的标题字体
plt.xlabel('')
plt.ylabel('国家/地区数量', fontsize=9)
plt.xticks(rotation=45, fontsize=8) # 缩小刻度字体
# 柱子上方数值更小字体
for j, v in enumerate(counts.values):
plt.text(j, v + 0.5, str(v), ha='center', fontsize=7)
# 自动调整子图布局
plt.tight_layout()
# 手动增加顶部和垂直间距
plt.subplots_adjust(top=0.92, hspace=0.8) # 增大 hspace 来拉开子图间距
# 添加总标题
plt.suptitle('全球LGBT+权利法律认可情况分布', y=0.97, fontsize=14)
plt.show()
三、LGBTQ+权利数据的地图可视化
3.1 数据准备
- 加载世界地图数据:通过
geopandas
库的read_file
函数,读取世界地图数据文件"E:\\pycharm_workspace\\ne_110m_admin_0_countries.shp"
,代码如下:
import geopandas as gpd
world = gpd.read_file("E:\\pycharm_workspace\\数据集\\ne_110m_admin_0_countries.shp")
- 加载LGBTQ+权利数据:再次从指定路径读取LGBTQ+权利数据文件
"E:\\pycharm_workspace\\数据集\\lgbtq_rights_by_country.csv"
,代码如下:
lgbtq_df = pd.read_csv("E:\\pycharm_workspace\\数据集\\lgbtq_rights_by_country.csv")
- 数据转换为数值评分:定义
calculate_score
函数,将LGBTQ+权利数据中的分类数据转换为数值评分。遍历特定的权利相关列,根据列值'Yes'
、'No'
或'Unknown'
分别赋予1、 - 1和0的分数,并累加到每行对应的评分中,最后将评分结果添加到lgbtq_df
数据集中。
def calculate_score(row):
score = 0
for column in ['Same-sex sexual activity', 'Recognition of same-sex unions', 'Same-sex marriage',
'Adoption by same-sex couples', 'LGBT people allowed to serve openly in military?',
'Anti-discrimination laws concerning sexual orientation', 'Laws concerning gender identity/expression']:
if row[column] == 'Yes':
score += 1
elif row[column] == 'No':
score += -1
else: # Unknown
score += 0
return score
lgbtq_df['Score'] = lgbtq_df.apply(calculate_score, axis=1)
- 数据合并:使用
pandas
的merge
函数,根据world
数据集中的NAME
列和lgbtq_df
数据集中的Territory
列进行左连接合并,确保所有国家在地图数据中有对应的LGBTQ+权利评分,并对可能存在的缺失评分填充为0。
merged = world.merge(lgbtq_df, left_on="NAME", right_on="Territory", how="left")
merged["Score"] = merged["Score"].fillna(0)
3.2 地图绘制
- 创建地图对象:借助
matplotlib
和cartopy
库,创建一个带有ccrs.PlateCarree()
投影的GeoAxes
对象,并设置背景颜色。
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
fig, ax = plt.subplots(figsize=(14, 8), subplot_kw={'projection': ccrs.PlateCarree()})
ax.set_facecolor("#f0f0f0")
- 绘制基础地图:绘制世界地图作为基础底图,设置地图颜色为白色,边界颜色为
"#444"
,线宽为0.5。
world.plot(ax=ax, color="white", edgecolor="#444", linewidth=0.5, transform=ccrs.PlateCarree())
- 设置颜色映射与归一化:选择
"RdBu_r"
颜色映射,设定评分的最小值vmin
为 - 7,最大值vmax
为7,并创建归一化对象norm
。
from matplotlib.colors import Normalize
from matplotlib.cm import get_cmap
cmap = get_cmap("RdBu_r")
vmin, vmax = -7, 7
norm = Normalize(vmin=vmin, vmax=vmax)
- 绘制带有分数的地图:根据合并数据集中的
Score
列绘制地图,设置线条宽度、边界颜色等参数,并处理缺失值的显示。
merged.plot(
column="Score",
cmap=cmap,
norm=norm,
linewidth=0.8,
ax=ax,
edgecolor="#aaaaaa",
missing_kwds={"color": "lightgray"},
transform=ccrs.PlateCarree()
)
- 添加颜色条与标注:添加颜色条以说明评分与颜色的对应关系,并设置其标签。同时设置地图的标题、坐标轴标签。(原代码中对高分和低分国家标注部分被注释,如需使用,可取消注释。)
cbar = plt.colorbar(
plt.cm.ScalarMappable(norm=norm, cmap=cmap),
ax=ax,
orientation="vertical",
shrink=0.6,
pad=0.05,
label="LGBTQ+ Rights Score\n(7 = All Yes, -7 = All Unknown/No)"
)
plt.title("Global LGBTQ+ Rights Distribution", fontsize=16, pad=20)
plt.xlabel("Longitude", fontsize=12)
plt.ylabel("Latitude", fontsize=12)
- 添加网格线并保存显示:添加网格线,并设置其属性,如是否显示标签、线条颜色、样式等。使用
tight_layout
函数优化布局,将绘制好的地图保存为"lgbtq_rights_world_map.png"
文件,并显示地图。
gl = ax.gridlines(
crs=ccrs.PlateCarree(),
draw_labels=True,
linewidth=0.5,
color="gray",
alpha=0.5,
linestyle="--"
)
gl.top_labels = False
gl.right_labels = False
gl.xlabel_style = {"size": 10, "color": "gray"}
gl.ylabel_style = {"size": 10, "color": "gray"}
plt.tight_layout()
plt.savefig("lgbtq_rights_world_map.png", dpi=300, bbox_inches="tight")
plt.show()
完整代码
import matplotlib.pyplot as plt
import geopandas as gpd
import pandas as pd
import numpy as np
from matplotlib.colors import Normalize
from matplotlib.cm import get_cmap
import cartopy.crs as ccrs
# 1. 加载世界地图数据
world = gpd.read_file("D:\\pyprogect\\图形页面编程\\lgbtq_rights_by_country\\ne_110m_admin_0_countries\\ne_110m_admin_0_countries.shp")
# 2. 加载LGBTQ+权利数据
lgbtq_df = pd.read_csv("D:\\pyprogect\\图形页面编程\\lgbtq_rights_by_country\\lgbtq_rights_by_country.csv")
# 3. 将分类数据转换为数值评分
def calculate_score(row):
score = 0
for column in ['Same-sex sexual activity', 'Recognition of same-sex unions', 'Same-sex marriage',
'Adoption by same-sex couples', 'LGBT people allowed to serve openly in military?',
'Anti-discrimination laws concerning sexual orientation', 'Laws concerning gender identity/expression']:
if row[column] == 'Yes':
score += 1
elif row[column] == 'No':
score += -1
else: # Unknown
score += 0
return score
lgbtq_df['Score'] = lgbtq_df.apply(calculate_score, axis=1)
# 4. 合并数据
merged = world.merge(lgbtq_df, left_on="NAME", right_on="Territory", how="left")
merged["Score"] = merged["Score"].fillna(0)
# 5. 绘制地图
# 使用 cartopy 创建 GeoAxes 对象
fig, ax = plt.subplots(figsize=(14, 8), subplot_kw={'projection': ccrs.PlateCarree()})
ax.set_facecolor("#f0f0f0")
# 先绘制基础地图
world.plot(ax=ax, color="white", edgecolor="#444", linewidth=0.5, transform=ccrs.PlateCarree())
cmap = get_cmap("RdBu_r")
vmin, vmax = -7, 7
norm = Normalize(vmin=vmin, vmax=vmax)
# 绘制带有分数的地图
merged.plot(
column="Score",
cmap=cmap,
norm=norm,
linewidth=0.8,
ax=ax,
edgecolor="#aaaaaa",
missing_kwds={"color": "lightgray"},
transform=ccrs.PlateCarree()
)
# 添加颜色条
cbar = plt.colorbar(
plt.cm.ScalarMappable(norm=norm, cmap=cmap),
ax=ax,
orientation="vertical",
shrink=0.6,
pad=0.05,
label="LGBTQ+ Rights Score\n(7 = All Yes, -7 = All Unknown/No)"
)
plt.title("Global LGBTQ+ Rights Distribution", fontsize=16, pad=20)
plt.xlabel("Longitude", fontsize=12)
plt.ylabel("Latitude", fontsize=12)
# # 标注高分和低分国家
# highlight_countries = merged[merged['Score'].isin([-7, 7, -6, 6, -5, 5])][['NAME', 'Score', 'Territory']]
# for _, row in highlight_countries.iterrows():
# try:
# geom = merged[merged["NAME"] == row['NAME']]["geometry"].values[0]
# x, y = geom.centroid.x, geom.centroid.y
# plt.annotate(
# f"{row['Territory']} ({row['Score']})",
# xy=(x, y),
# xytext=(5, 5),
# textcoords="offset points",
# ha="left",
# va="center",
# fontsize=10,
# color="black" if row['Score'] < 0 else "white",
# weight="bold"
# )
# except IndexError:
# pass
# 添加网格线
gl = ax.gridlines(
crs=ccrs.PlateCarree(),
draw_labels=True,
linewidth=0.5,
color="gray",
alpha=0.5,
linestyle="--"
)
gl.top_labels = False
gl.right_labels = False
gl.xlabel_style = {"size": 10, "color": "gray"}
gl.ylabel_style = {"size": 10, "color": "gray"}
plt.tight_layout()
plt.savefig("lgbtq_rights_world_map.png", dpi=300, bbox_inches="tight")
plt.show()
四、结论
通过直方图和地图两种可视化方式,呈现了全球LGBTQ+权利的状况。直方图从各个权利维度展示了不同认可类别的国家数量分布,地图则从地理空间上展示了综合评分的分布情况。