如何在堆叠柱状图中指定X轴标签显示间隔(每3个月)
Solution for Stacked Monthly Catch Bar Chart by Size Code
Hey Helen, let's tackle this step by step—your goal is totally achievable with pandas and matplotlib. Here's a detailed breakdown of how to get that stacked bar chart with readable X-axis labels:
1. Data Preprocessing First
First, we need to clean up the date data and aggregate the catch by month and size code. Let's start with that:
import pandas as pd import matplotlib.pyplot as plt # Convert Date column to datetime (critical for time-based grouping) df['Date'] = pd.to_datetime(df['Date']) # Create a 'Month' column that represents the first day of each month (keeps datetime format) df['Month'] = df['Date'].dt.to_period('M').dt.to_timestamp() # Aggregate total weight by Month and Size.Code, then pivot to wide format for stacking aggregated_df = df.groupby(['Month', 'Size.Code'])['Weight'].sum().unstack(fill_value=0)
Quick Notes:
- Using
to_period('M').dt.to_timestamp()ensures our monthly data is ordered correctly (no messy string sorting). unstack()turns Size.Code values into columns—this is what lets matplotlib create stacked bars automatically.
2. Plot the Stacked Bar Chart
Now let's build the chart with the X-axis label spacing you want:
fig, ax = plt.subplots(figsize=(14, 7)) # Plot stacked bars directly from the aggregated dataframe aggregated_df.plot(kind='bar', stacked=True, ax=ax, colormap='viridis') # Customize X-axis labels to show every 3 months # Get all tick positions and their corresponding labels all_ticks = ax.get_xticks() all_labels = [date.strftime('%Y-%m') for date in aggregated_df.index] # Only keep labels every 3 months, leave others blank visible_labels = [label if i % 3 == 0 else '' for i, label in enumerate(all_labels)] ax.set_xticklabels(visible_labels, rotation=45, ha='right') # Add titles and labels for clarity ax.set_title('10-Year Monthly Catch by Size Code', fontsize=16) ax.set_xlabel('Month', fontsize=12) ax.set_ylabel('Total Catch Weight', fontsize=12) # Move legend outside the plot to avoid overlapping bars ax.legend(title='Size Code', bbox_to_anchor=(1.02, 1), loc='upper left') plt.tight_layout() plt.show()
3. If You Want Separate Charts for Each Vessel
If you need individual stacked charts for each Vessel.Pln, wrap the plotting code in a loop:
# Get all unique vessel identifiers unique_vessels = df['Vessel.Pln'].unique() for vessel in unique_vessels: # Filter data for the current vessel vessel_data = df[df['Vessel.Pln'] == vessel] # Aggregate catch for this vessel vessel_agg = vessel_data.groupby(['Month', 'Size.Code'])['Weight'].sum().unstack(fill_value=0) # Create plot fig, ax = plt.subplots(figsize=(12, 6)) vessel_agg.plot(kind='bar', stacked=True, ax=ax, colormap='viridis') # Apply the same 3-month label spacing all_labels = [date.strftime('%Y-%m') for date in vessel_agg.index] visible_labels = [label if i % 3 == 0 else '' for i, label in enumerate(all_labels)] ax.set_xticklabels(visible_labels, rotation=45, ha='right') # Customize titles for each vessel ax.set_title(f'Monthly Catch by Size Code - Vessel {vessel}', fontsize=14) ax.set_xlabel('Month', fontsize=12) ax.set_ylabel('Total Catch Weight', fontsize=12) ax.legend(title='Size Code', bbox_to_anchor=(1.02, 1), loc='upper left') plt.tight_layout() plt.show()
Key Tips to Avoid Issues:
- Handle Missing Data: If you have missing dates or weights, add
df = df.dropna(subset=['Date', 'Weight'])anddf['Weight'] = pd.to_numeric(df['Weight'], errors='coerce')to clean the data first. - Adjust Figure Size: Tweak the
figsizeparameter if your labels still feel crowded—wider figures work better for long time periods. - Color Customization: Replace
colormap='viridis'with any matplotlib colormap you prefer (e.g., 'tab20' for distinct colors).
内容的提问来源于stack exchange,提问作者helen.h
相关产品推荐
相关产品推荐

