如何消除plotnine中多父类别与子类别分面图的多余行间距?
如何消除plotnine中多父类别与子类别分面图的多余行间距?
你遇到的这个问题其实是plotnine里facet_wrap的一个小局限——它默认所有分面面板的尺寸都是统一的,哪怕不同父类对应的子类别数量差异很大,也没法自动让面板高度跟着子类别数量调整,所以才会出现多余的空白区域。
要实现面板高度随子类别数量自适应的效果,我们可以换个思路:手动拆分数据,结合matplotlib的子图功能,给每个父类别创建对应高度的子图,再逐个绘制内容。下面是完整的实现方案:
步骤1:准备数据(和你原数据一致)
import pandas as pd new_data = { 'date': pd.date_range('2022-01-01', periods=11, freq="ME"), 'parent_category': ['Electronics', 'Electronics', 'Fashion', 'Fashion', 'Home Goods', 'Electronics', 'Fashion','Electronics','Electronics','Electronics','Electronics'], 'child_category': ['Smartphones', 'Laptops', 'Shirts', 'Pants', 'Kitchenware','Laptops', 'Shirts', 'Smartphones','PS4','Oven','Vaccum cleaner'] } new_data = pd.DataFrame(new_data)
步骤2:实现自适应高度的分面图
我们先统计每个父类的子类别数量,以此为依据设置子图的高度比例,再循环绘制每个父类的内容:
import matplotlib.pyplot as plt from plotnine import * # 1. 统计每个父类的唯一子类别数量,用于设置子图高度比例 parent_groups = new_data.groupby('parent_category') parent_names = list(parent_groups.groups.keys()) # 计算每个父类对应的子类别数量 child_counts = [len(group['child_category'].unique()) for _, group in parent_groups] # 用子类别数量作为子图高度的比例(可以根据需求调整,比如乘以系数让整体高度更合适) height_ratios = child_counts # 2. 创建matplotlib子图,指定高度比例 fig, axes = plt.subplots( nrows=len(parent_names), ncols=1, figsize=(8, 6), gridspec_kw={'height_ratios': height_ratios} ) # 调整子图之间的垂直间距 fig.subplots_adjust(hspace=0.6) # 3. 循环绘制每个父类的内容到对应子图 for ax, parent_name in zip(axes, parent_names): # 筛选当前父类别的数据 subset = new_data[new_data['parent_category'] == parent_name] # 创建plotnine绘图对象,指定绘制到当前matplotlib轴 plot = ( ggplot(subset, aes(x="date", y="child_category", group="child_category")) + geom_line(size=1, color="pink") + geom_point(size=3, color="grey") + theme_538() + theme( axis_text_x=element_text(angle=45, hjust=1), panel_grid_major=element_blank(), axis_title_y=element_blank(), # 隐藏y轴标题,避免重复 figure_size=None # 禁用plotnine的自动尺寸设置,用matplotlib的配置 ) ) # 将plotnine图形绘制到指定轴 plot.draw(ax=ax) # 设置子图标题为父类别名称 ax.set_title(parent_name, fontweight='bold') # 优化x轴显示:除了最后一个子图,隐藏x轴标签,避免重复 if parent_name != parent_names[-1]: ax.set_xlabel('') # 调整整体布局,避免元素重叠 plt.tight_layout() plt.show()
代码关键点说明
- 高度比例计算:我们用每个父类的子类别数量作为子图高度的比例,这样子类越多的父类,对应的子图高度就越高,从根源上消除空白区域。
- matplotlib子图控制:通过
gridspec_kw={'height_ratios': height_ratios}指定子图的高度比例,这是实现自适应高度的核心。 - plotnine与matplotlib结合:用
plot.draw(ax=ax)将plotnine的图形绑定到matplotlib的指定轴上,既保留了plotnine的语法便利性,又能利用matplotlib的精细布局控制。
这样实现的图,每个父类的面板高度会完全匹配自身的子类别数量,不会再有多余的空白行啦。
备注:内容来源于stack exchange,提问作者ViSa
相关产品推荐
相关产品推荐

