ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Python数据可视化科技图表绘制系列教程(五)

Python数据可视化科技图表绘制系列教程(五) 目录基础径向柱状图排序的径向柱状图添加标签的基础径向柱状图分组径向柱状图词云图1词云图2玫瑰图1玫瑰图2玫瑰图3【声明】未经版权人书面许可任何单位或个人不得以任何形式复制、发行、出租、改编、汇编、传播、展示或利用本博客的全部或部分内容也不得在未经版权人授权的情况下将本博客用于任何商业目的。但版权人允许个人学习、研究、欣赏等非商业性用途的复制和传播。非常推荐大家学习《Python数据可视化科技图表绘制》这本书籍。基础径向柱状图# 导入所需的库 import matplotlib.pyplot as plt import numpy as np import pandas as pd # 创建数据集第一列为数据集各项的名称。第二列各项的数值 df pd.DataFrame( {Name: [Ding str(i) for i in list(range(1, 51))], Value: np.random.randint(low10, high100, size50)} ) df.head(3) # 显示前 3 行数据输出略 # ① plt.figure(figsize(20, 10)) # 设置图形大小 ax plt.subplot(111, polarTrue) # 绘制极坐标轴 plt.axis(off) # 移除网格线 upperLimit 100 # 设置坐标轴的上限 lowerLimit 30 # 设置坐标轴的下限 max_value df[Value].max() # 计算数据集中的最大值 # 计算每个条形图的高度它们是在新坐标系中将每个条目值转换的结果 # 数据集中的0转换为lowerLimit(30)最大值被转换为upperLimit(100) slope (max_value - lowerLimit) / max_value heights slope * df.Value lowerLimit width 2 * np.pi / len(df.index) # 计算每个条形图的宽度共有2*Pi360° # 计算每个条形图中心的角度 indexes list(range(1, len(df.index) 1)) angles [element * width for element in indexes] # ② # 绘制条形图 bars ax.bar(xangles, heightheights, widthwidth, bottomlowerLimit, linewidth2, edgecolorwhite) # 保存图片时自动调整边界 plt.savefig(P125基础径向柱状图.png, dpi600, bbox_inchestight, transparentTrue) plt.show()基础径向柱状图排序的径向柱状图# 导入所需的库 import matplotlib.pyplot as plt import numpy as np import pandas as pd # 创建数据集第一列为数据集各项的名称。第二列各项的数值 df pd.DataFrame( {Name: [Ding str(i) for i in list(range(1, 51))], Value: np.random.randint(low10, high100, size50)} ) df.head(3) # 显示前 3 行数据输出略 # ① df df.sort_values(by[Value]) # 重新按值对数据集进行排序 plt.figure(figsize(20, 10)) # 设置图形大小 ax plt.subplot(111, polarTrue) # 绘制极坐标轴 plt.axis(off) # 移除网格线 upperLimit 100 # 设置坐标轴的上限 lowerLimit 30 # 设置坐标轴的下限 max_value df[Value].max() # 计算数据集中的最大值 # 计算每个条形图的高度它们是在新坐标系中将每个条目值转换的结果 # 数据集中的0转换为lowerLimit(30)最大值被转换为upperLimit(100) slope (max_value - lowerLimit) / max_value heights slope * df.Value lowerLimit width 2 * np.pi / len(df.index) # 计算每个条形图的宽度共有2*Pi360° # 计算每个条形图中心的角度 indexes list(range(1, len(df.index) 1)) angles [element * width for element in indexes] # ② # 绘制条形图 bars ax.bar(xangles, heightheights, widthwidth, bottomlowerLimit, linewidth2, edgecolorwhite, color#61a4b2, ) labelPadding 4 # 条形图和标签之间的小间距 # 添加标签 for bar, angle, height, label in zip(bars, angles, heights, df[Name]): rotation np.rad2deg(angle) # 标签被旋转旋转必须以度数为单位指定 # 翻转部分标签使其朝下 alignment if angle np.pi / 2 and angle 3 * np.pi / 2: alignment right rotation rotation 180 else: alignment left # 添加标签 ax.text(xangle, ylowerLimit bar.get_height() labelPadding, slabel, haalignment, vacenter, rotationrotation, rotation_modeanchor) # 保存图片时自动调整边界 plt.savefig(P126排序的径向柱状图.png, dpi600, bbox_inchestight, transparentTrue) plt.show()排序的径向柱状图添加标签的基础径向柱状图# 导入所需的库 import matplotlib.pyplot as plt import numpy as np import pandas as pd # 创建数据集第一列为数据集各项的名称。第二列各项的数值 df pd.DataFrame( {Name: [Ding str(i) for i in list(range(1, 51))], Value: np.random.randint(low10, high100, size50)} ) df.head(3) # 显示前 3 行数据输出略 # ① plt.figure(figsize(20, 10)) # 设置图形大小 ax plt.subplot(111, polarTrue) # 绘制极坐标轴 plt.axis(off) # 移除网格线 upperLimit 100 # 设置坐标轴的上限 lowerLimit 30 # 设置坐标轴的下限 max_value df[Value].max() # 计算数据集中的最大值 # 计算每个条形图的高度它们是在新坐标系中将每个条目值转换的结果 # 数据集中的0转换为lowerLimit(30)最大值被转换为upperLimit(100) slope (max_value - lowerLimit) / max_value heights slope * df.Value lowerLimit width 2 * np.pi / len(df.index) # 计算每个条形图的宽度共有2*Pi360° # 计算每个条形图中心的角度 indexes list(range(1, len(df.index) 1)) angles [element * width for element in indexes] # ② # 绘制条形图 bars ax.bar(xangles, heightheights, widthwidth, bottomlowerLimit, linewidth2, edgecolorwhite, color#61a4b2, ) labelPadding 4 # 条形图和标签之间的小间距 # 添加标签 for bar, angle, height, label in zip(bars, angles, heights, df[Name]): rotation np.rad2deg(angle) # 标签被旋转旋转必须以度数为单位指定 # 翻转部分标签使其朝下 alignment if angle np.pi / 2 and angle 3 * np.pi / 2: alignment right rotation rotation 180 else: alignment left # 添加标签 ax.text(xangle, ylowerLimit bar.get_height() labelPadding, slabel, haalignment, vacenter, rotationrotation, rotation_modeanchor) # 保存图片时自动调整边界 plt.savefig(P126添加标签的基础径向柱状图.png, dpi600, bbox_inchestight, transparentTrue) plt.show()添加标签的基础径向柱状图分组径向柱状图import matplotlib.pyplot as plt import numpy as np import pandas as pd rng np.random.default_rng(123) # 确保随机数的可重现性 # 构建数据集 df pd.DataFrame({ name: [fDing {i} for i in range(1, 51)], value: rng.integers(low30, high100, size50), group: [A] * 10 [B] * 20 [C] * 12 [D] * 8 }) # ①处 df.head(5) # 显示前5行数据 # 辅助函数用于标签的旋转和对齐 def get_label_rotation(angle, offset): 根据给定的角度和偏移量计算文本标签的旋转角度和对齐方式 参数: angle (float):标签的角度。 offset (float):开始角度的偏移量。 返回: rotation (float):标签文本的旋转角度。 alignment (str):文本对齐方式left 或 right。 rotation np.rad2deg(angle offset) if angle np.pi: alignment right rotation rotation 180 else: alignment left return rotation, alignment # 辅助函数用于添加标签 def add_labels(angles, values, labels, offset, ax): 添加文本标签到极坐标图。 参数: angles (array-like):每个柱的角度 values (array-like):每个柱的值。 labels (array-like):每个柱的标签。 offset (float):开始角度的偏移量。 ax (matplotlib.axes._subplots.PolarAxesSubplot):极坐标图的轴对象。 padding 4 # 遍历角度、值和标签以添加 for angle, value, label, in zip(angles, values, labels): angle angle # 获取文本的旋转角度和对齐方式 rotation, alignment get_label_rotation(angle, offset) # 添加文本 ax.text(xangle, yvalue padding, slabel, haalignment, vacenter, rotationrotation, rotation_modeanchor) # 1绘制基础径向柱状图 ANGLES np.linspace(0, 2 * np.pi, len(df), endpointFalse) VALUES df[value].values # 获取数据集中的数值列作为柱的高度 LABELS df[name].values # 获取数据集中的名称列作为柱的标签 WIDTH 2 * np.pi / len(VALUES) # 确定每个柱的宽度 OFFSET np.pi / 2 # 指定从90度开始 fig, ax plt.subplots(figsize(20, 10), subplot_kw{projection: polar}) ax.set_theta_offset(OFFSET) ax.set_ylim(-100, 100) ax.set_frame_on(False) ax.xaxis.grid(False) ax.yaxis.grid(False) ax.set_xticks([]) ax.set_yticks([]) ax.bar(ANGLES, VALUES, widthWIDTH, color#61a4b2, edgecolorwhite, linewidth2) add_labels(ANGLES, VALUES, LABELS, OFFSET, ax) # 保存第一张图片 plt.savefig(P127基础径向柱状图.png, dpi600, bbox_inchestight, transparentTrue) plt.close() # 关闭当前图避免影响后续绘图 # 2在圆环中添加缺口 PAD 3 # 设置额外空白柱的数量 ANGLES_N len(VALUES) PAD # 计算包含额外空白柱的角度数量 ANGLES np.linspace(0, 2 * np.pi, numANGLES_N, endpointFalse) WIDTH (2 * np.pi) / len(ANGLES) # 计算每个柱的宽度 IDXS slice(0, ANGLES_N - PAD) # 确定非空柱的索引范围 fig, ax plt.subplots(figsize(20, 10), subplot_kw{projection: polar}) ax.set_theta_offset(OFFSET) ax.set_ylim(-100, 100) ax.set_frame_on(False) ax.xaxis.grid(False) ax.yaxis.grid(False) ax.set_xticks([]) ax.set_yticks([]) ax.bar(ANGLES[IDXS], VALUES, widthWIDTH, color#61a4b2, edgecolorwhite, linewidth2) add_labels(ANGLES[IDXS], VALUES, LABELS, OFFSET, ax) # 保存第二张图片 plt.savefig(P127在圆环中添加缺口的基础径向柱状图.png, dpi600, bbox_inchestight, transparentTrue) plt.close() # 关闭当前图避免影响后续绘图 # 3在组内排序并添加缺口 df_sorted (df .groupby([group]) .apply(lambda x: x.sort_values([value], ascendingFalse)) .reset_index(dropTrue)) df df_sorted VALUES df[value].values # 获取数据集中的数值列作为柱的高度 LABELS df[name].values # 获取数据集中的名称列作为柱的标签 GROUP df[group].values # 获取分组值 PAD 3 # 向每个分组的末尾添加三个空柱 ANGLES_N len(VALUES) PAD * len(np.unique(GROUP)) # 计算包含额外空白柱的角度数量 ANGLES np.linspace(0, 2 * np.pi, numANGLES_N, endpointFalse) WIDTH (2 * np.pi) / len(ANGLES) # 计算每个柱的宽度 GROUPS_SIZE [len(i[1]) for i in df.groupby(group)] # 获取每个分组的大小 offset 0 IDXS [] for size in GROUPS_SIZE: IDXS list(range(offset PAD, offset size PAD)) offset size PAD COLORS [fC{i} for i, size in enumerate(GROUPS_SIZE) for _ in range(size)] # 为每个分组分配颜色 fig, ax plt.subplots(figsize(20, 10), subplot_kw{projection: polar}) ax.set_theta_offset(OFFSET) ax.set_ylim(-100, 100) ax.set_frame_on(False) ax.xaxis.grid(False) ax.yaxis.grid(False) ax.set_xticks([]) ax.set_yticks([]) ax.bar(ANGLES[IDXS], VALUES, widthWIDTH, colorCOLORS, edgecolorwhite, linewidth2) add_labels(ANGLES[IDXS], VALUES, LABELS, OFFSET, ax) # 保存第三张图片 plt.savefig(P127组内排序的分组径向柱状图.png, dpi600, bbox_inchestight, transparentTrue) plt.close() # 关闭当前图基础径向柱状图在圆环中添加缺口的基础径向柱状图组内排序的分组径向柱状图词云图1from os import path # 导入操作系统路径模块中的path函数用于处理文件路径 from PIL import Image # 导入PIL中的Image类用于读取、处理图像 import numpy as np # 导入NumPy库用于处理数组和矩阵 import matplotlib.pyplot as plt # 导入pyplot模块用于绘制图形 import os # 导入操作系统相关的模块用于获取当前工作目录等操作 from wordcloud import WordCloud, STOPWORDS # 导入词云库中的WordCloud类和STOPWORDS集合用于生成和处理词云图 # 获取当前文件的目录 d path.dirname(__file__) if __file__ in locals() else os.getcwd() # 读取整个文本文件的内容 text open(path.join(d, rE:\PythonProjects\experiments_figures\绘图案例数据\alice.txt)).read() # 读取蒙版图像掩码图像 # 蒙版图像用于控制词云形状这里使用了一个Alice in Wonderland的蒙版图像 alice_mask np.array(Image.open( path.join(d, rE:\PythonProjects\experiments_figures\绘图案例数据\alice_mask.png))) # 设置停用词在词云中不显示的词语 stopwords set(STOPWORDS) stopwords.add(said) # 添加一个额外的停用词 # 创建词云对象指定背景颜色、最大词数、蒙版图像、停用词等参数 wc WordCloud(background_colorwhite, max_words2000, maskalice_mask, stopwordsstopwords, contour_width3, contour_colorsteelblue) wc.generate(text) # 生成词云图 # 显示词云图 plt.figure(figsize(10, 8)) # 设置图像大小 plt.imshow(wc, interpolationbilinear) plt.axis(off) # 不显示坐标轴 # 保存图片时自动调整边界设置透明背景 plt.savefig(P133词云图1.png, dpi1000, bbox_inchestight, transparentTrue) plt.show() # 显示蒙版图像仅为了对比效果 plt.figure() plt.imshow(alice_mask, cmapplt.cm.gray, interpolationbilinear) plt.axis(off) # 不显示坐标轴 plt.show()词云图1词云图2import numpy as np # 导入NumPy库用于处理数组和矩阵 from PIL import Image # 导入PIL中的Image类用于读取、处理图像 from os import path # 导入操作系统路径模块中的path函数用于处理文件路径 import matplotlib.pyplot as plt # 导入pyplot模块用于绘制图形 import os # 导入操作系统相关的模块用于获取当前工作目录等操作 import random # 导入random模块用于生成随机数 from wordcloud import WordCloud, STOPWORDS # 导入词云库中的WordCloud类和STOPWORDS集合用于生成和处理词云图 # 定义自定义颜色函数用于生成词云中词语的颜色 def grey_color_func(word, font_size, position, orientation, random_stateNone, **kwargs): # 使用随机的亮度值来生成灰度颜色使词云图更加丰富多彩 return hsl(0,0%%,%d%%) % random.randint(60, 100) # 获取当前文件的目录 d path.dirname(__file__) if __file__ in locals() else os.getcwd() # 读取蒙版图像掩码图像 # 这里使用了一个星球大战中的Stormtrooper的蒙版图像 mask np.array(Image.open( path.join(d, rE:\PythonProjects\experiments_figures\绘图案例数据\stormtrooper_mask.png))) # 读取星球大战电影《新希望》的剧本文本 text open(path.join(d, rE:\PythonProjects\experiments_figures\绘图案例数据\a_new_hope.txt)).read() # 对文本进行一些预处理例如替换文本中的特定词语 text text.replace(HAN, Han) text text.replace(LUKES, Luke) # 添加剧本特定的停用词 stopwords set(STOPWORDS) stopwords.add(int) stopwords.add(ext) # 创建词云对象并生成词云图 wc WordCloud(max_words1000, maskmask, stopwordsstopwords, margin10, random_state1).generate(text) default_colors wc.to_array() # 保存默认颜色的词云图 # 显示自定义颜色的词云图 plt.figure(figsize(10, 10)) # 设置图像大小 plt.title(Custom colors, fontsize16) # 设置标题及字体大小 plt.imshow(wc.recolor(color_funcgrey_color_func, random_state3), interpolationbilinear) plt.axis(off) # 关闭坐标轴 plt.savefig(P134词云图2_自定义颜色.png, dpi600, bbox_inchestight, transparentTrue) # 保存图片 plt.show() # 显示默认颜色的词云图 plt.figure(figsize(10, 10)) # 设置图像大小 plt.title(Default colors, fontsize16) # 设置标题及字体大小 plt.imshow(default_colors, interpolationbilinear) plt.axis(off) # 关闭坐标轴 plt.savefig(P134词云图2_默认颜色.png, dpi600, bbox_inchestight, transparentTrue) # 保存图片 plt.show()词云图2_默认颜色词云图2_自定义颜色玫瑰图1import matplotlib.pyplot as plt import numpy as np np.random.seed(19781101) # 固定随机种子以便结果可复现 # 计算扇形柱 N 20 theta np.linspace(0.0, 2 * np.pi, N, endpointFalse) radii 10 * np.random.rand(N) width np.pi / 4 * np.random.rand(N) colors plt.cm.viridis(radii / 10.) # 创建极坐标子图 ax plt.subplot(projectionpolar) # 绘制柱状图 ax.bar(theta, radii, widthwidth, bottom0.0, colorcolors, alpha0.5) # 保存图片 plt.savefig(P136玫瑰图1.png, dpi600, bbox_inchestight, transparentTrue) plt.show()玫瑰图1玫瑰图2import numpy as np from windrose import WindroseAxes from matplotlib import cm import matplotlib.pyplot as plt # 生成随机的风速和风向数据 N 500 ws np.random.random(N) * 6 # 随机生成风速数据0到6之间 wd np.random.random(N) * 360 # 随机生成风向数据0到360之间 # 创建风玫瑰图对象并绘制归一化柱状图 ax WindroseAxes.from_ax() ax.bar(wd, ws, normedTrue, opening0.8, edgecolorwhite) # 绘制柱状图 ax.set_legend() # 添加图例 # 保存图片 plt.savefig(P137玫瑰图2_1.png, dpi600, bbox_inchestight, transparentTrue) plt.show() # 创建风玫瑰图对象并绘制箱线图 ax WindroseAxes.from_ax() ax.box(wd, ws, binsnp.arange(0, 8, 1)) # 绘制箱线图 ax.set_legend() # 添加图例 # 保存图片 plt.savefig(P137玫瑰图2_2.png, dpi600, bbox_inchestight, transparentTrue) plt.show() # 创建风玫瑰图对象并绘制填充等高线图 ax WindroseAxes.from_ax() ax.contourf(wd, ws, binsnp.arange(0, 8, 1), cmapcm.hot) # 绘制填充等高线图 ax.set_legend() # 添加图例 # 保存图片 plt.savefig(P137玫瑰图2_3.png, dpi600, bbox_inchestight, transparentTrue) plt.show() # 创建风玫瑰图对象并绘制等高线图 ax WindroseAxes.from_ax() ax.contour(wd, ws, binsnp.arange(0, 8, 1), cmapcm.hot, lw1) # 绘制等高线图 ax.set_legend() # 添加图例 # 保存图片 plt.savefig(P137玫瑰图2_4.png, dpi600, bbox_inchestight, transparentTrue) plt.show()玫瑰图2_1玫瑰图2_2玫瑰图2_3玫瑰图2_4玫瑰图3import numpy as np import pandas as pd import seaborn as sns from matplotlib import pyplot as plt # 导入 windrose 库中的 WindroseAxes 和 plot_windrose 函数 from windrose import WindroseAxes, plot_windrose # 创建包含风速、风向和月份的 DataFrame wind_data pd.DataFrame({ ws: np.random.random(1200) * 6, # 随机生成风速数据0到6之间 wd: np.random.random(1200) * 360, # 随机生成风向数据0到360之间 month: np.repeat(range(1, 13), 100), # 重复月份数据100次 }) def plot_windrose_subplots(data, *, direction, var, colorNone, **kwargs): 封装函数用于在子图中绘制风玫瑰图 ax plt.gca() # 获取当前轴对象 ax WindroseAxes.from_ax(axax) # 创建风玫瑰图对象并在当前轴上添加 # 调用 plot_windrose 函数绘制风玫瑰图 plot_windrose(direction_or_dfdata[direction], vardata[var], axax, **kwargs) # 使用 FacetGrid 创建子图结构 g sns.FacetGrid(datawind_data, colmonth, # 按月份创建子图列 col_wrap4, # 每行最多显示4个子图 subplot_kws{projection: windrose}, # 使用风玫瑰图投影 sharexFalse, shareyFalse, # 不共享 x、y 轴 despineFalse, # 不去掉轴线外侧边框 height3.5, ) # 子图高度 # 在每个子图上调用 plot_windrose_subplots 函数绘制风玫瑰图 g.map_dataframe(plot_windrose_subplots, directionwd, # 风向数据列名 varws, # 风速数据列名 normedTrue, # 对频率进行归一化 bins(0.1, 1, 2, 3, 4, 5), # 设置频率区间 calm_limit0.1, # 静风的限制值 kindbar, # 使用柱状图形式 ) # 设置每个子图的图例和径向网格线 y_ticks range(0, 17, 4) # 设置径向网格线范围 for ax in g.axes: ax.set_legend(title$m \\cdot s^{-1}$, # 图例标题 bbox_to_anchor(1.15, -0.1), # 图例位置 loclower right, # 图例位置 ) # 保存图片 plt.savefig(P138玫瑰图3.png, dpi600, bbox_inchestight, transparentTrue) plt.show() ax.set_rgrids(y_ticks, y_ticks) # 设置径向网格线 plt.subplots_adjust(wspace-0.2) # 调整子图之间的间距玫瑰图3
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进