如何在Matplotlib/Seaborn条形图添加次坐标轴并使点对齐对应条形
Got it, let's tackle this problem step by step. The key challenges here are aligning the median points perfectly with their corresponding bars and setting up the secondary axis correctly. Here's how you can modify your function to achieve exactly what you want:
Modified Function Code
import pandas as pd import seaborn as sns import matplotlib.pyplot as plt import numpy as np df = pd.DataFrame({ 'Student' : ['Alice', 'Bob', 'Chris', 'Dave', 'Edna', 'Frank'], 'Education' : ['HS', 'HS', 'HS', 'College', 'College', 'HS' ], 'Household Size': [4, 4, 3, 3, 3, 6 ], 'Gender' : ['F', 'M', 'M', 'M', 'F', 'M' ] }) def MakePercentageFrequencyTable(dataFrame, primaryDimension, secondaryDimension=None, extraAggregatedField=None): # Calculate percentage frequency table if secondaryDimension is not None: # Compute percentages grouped by secondary + primary dimensions primaryDimensionPercent = ( dataFrame.groupby([secondaryDimension, primaryDimension]) .size() .groupby(level=0) .apply(lambda x: 100 * x / x.sum()) .rename('percentage') .reset_index() ) # Create grouped bar plot with dodge enabled for easy alignment g = sns.catplot( x="percentage", y=secondaryDimension, hue=primaryDimension, kind='bar', data=primaryDimensionPercent, dodge=True ) ax = g.axes[0, 0] # Extract the axis from the FacetGrid else: # Original logic for no secondary dimension primaryDimensionPercent = ( dataFrame[primaryDimension].value_counts(normalize=True) .rename('percentage') .mul(100) .reset_index(drop=False) ) g = sns.catplot(x="percentage", y='index', kind='bar', data=primaryDimensionPercent) ax = g.axes[0, 0] # Handle extra aggregated field for median points and secondary axis if extraAggregatedField is not None and secondaryDimension is not None: # Calculate median for each subgroup median_data = ( dataFrame.groupby([secondaryDimension, primaryDimension])[extraAggregatedField] .median() .reset_index() ) # Create top-aligned secondary axis ax_top = ax.twiny() ax_top.set_xlabel(f'{extraAggregatedField} Median') # Get bar position details for alignment y_category_positions = ax.get_yticks() bar_width = [bar.get_width() for bar in ax.patches][0] dodge_offset = bar_width * 0.4 # Matches seaborn's default dodge spacing # Plot median points aligned to bar centers for idx, row in median_data.iterrows(): # Find y-axis position for the current secondary category y_pos = np.where(ax.get_yticklabels() == row[secondaryDimension])[0][0] # Find hue index to adjust horizontal position hue_idx = g.hue_order.index(row[primaryDimension]) # Calculate exact center of the target bar bar_center_x = ax.patches[idx].get_x() + bar_width / 2 # Plot point on secondary axis ax_top.scatter(row[extraAggregatedField], y_pos, color='red', zorder=5) # Add value label for clarity ax_top.text(row[extraAggregatedField], y_pos, f'{row[extraAggregatedField]}', ha='center', va='center', fontweight='bold') # Adjust axis limits to fit all elements ax_top.set_xlim(median_data[extraAggregatedField].min() - 0.5, median_data[extraAggregatedField].max() + 0.5) ax.set_xlim(0, primaryDimensionPercent['percentage'].max() + 5) # Clean up layout plt.tight_layout() return g # Example call with all required parameters MakePercentageFrequencyTable( dataFrame=df, primaryDimension='Education', secondaryDimension='Gender', extraAggregatedField='Household Size' )
Key Details & Explanations
- Median Calculation: We group by both the primary and secondary dimensions to compute the exact median for each subgroup (e.g., Female/College, Male/HS).
- Precise Alignment:
- We extract the y-position of each secondary category (like Female/Male on the y-axis) and the width of individual bars.
- Using Seaborn's default
dodgespacing, we calculate the center of each bar to place the median point perfectly on top.
- Secondary Axis:
ax.twiny()creates a top axis that shares the same y-axis as the bar plot, so points stay aligned vertically.- We adjust the secondary axis limits based on the median values to ensure all points are visible and properly spaced.
- Visibility: Setting
zorder=5ensures the red median points appear above the bars, making them easy to spot.
What You'll See
When you run the example:
- The original percentage bars for each Gender/Education subgroup are displayed.
- A top axis labeled "Household Size Median" shows the scale for median values.
- Red points (with value labels) are aligned exactly to the center of their corresponding bars, showing the median household size for each subgroup (e.g., 3 for Female/College, 4 for Male/HS).
内容的提问来源于stack exchange,提问作者dnb
相关产品推荐
相关产品推荐

