如何在含滑块组件的Matplotlib柱状图中控制坐标轴与柱状图标签?
Hey there, let's work through your scrolling bar chart problems one by one. I'll fix the label bug, lock down the Y-axis, and show you how to control label font sizes—plus a couple of small tweaks to make everything work smoothly.
1. Bug Fix: Labels Aren't Updating With the Slider
The issue here is that when you're annotating the bars, you're using channels[i] where i starts at 0 every time you redraw the chart. But when the slider is at position pos, you need to grab labels starting from pos in the channels list.
Instead of channels[i], use channels[pos + i]—this matches the current subset of bars you're displaying.
2. Request 1: Lock Y-Axis to 0-100 with Step 20
To keep the Y-axis consistent regardless of which bar group you're viewing, add these two lines inside your bar function after drawing the bars:
ax.set_ylim(0, 100) # Fix Y-axis range ax.set_yticks(np.arange(0, 101, 20)) # Set ticks every 20 units
This forces the Y-axis to stay between 0 and 100, with ticks at 0, 20, 40, 60, 80, 100 every time.
3. Request 2: Control Label Font Size
You can adjust the font size directly in the ax.annotate call by adding the fontsize parameter. For example:
ax.annotate(channels[pos+i], (xi, yi), fontsize=10)
Change 10 to any value that fits your needs (like 8 for smaller text or 12 for larger).
Bonus Fix: Match Data Lengths
I noticed your original x array had 19 elements (np.arange(1,20)), but channels has 20. This would cause a mismatch later, so I updated x to np.arange(len(channels)) to ensure all labels have corresponding bars.
Full Corrected Code
import matplotlib.pyplot as plt from matplotlib.widgets import Slider import numpy as np fig, ax = plt.subplots(figsize=(10, 6)) # Fix x array length to match channels x = np.arange(len(channels)) y = np.random.randint(0, 100, len(x)) channels = ['a','b','c','d','e','f','g','h','i','j','k','m','n','o','p','q','r','s','t','u'] N = 5 def bar(pos): pos = int(pos) ax.clear() # Calculate how many bars to show (handles the last partial group) n = N if pos + N <= len(x) else len(x) - pos X = x[pos:pos+n] Y = y[pos:pos+n] ax.bar(X, Y, width=0.7, align='edge', color='green', ecolor='black') # Annotate bars with correct labels and custom font size for i, (xi, yi) in enumerate(zip(X, Y)): ax.annotate(channels[pos+i], (xi, yi), fontsize=10) # Lock Y-axis range and ticks ax.set_ylim(0, 100) ax.set_yticks(np.arange(0, 101, 20)) # Update X-axis ticks to show current channel labels (optional but helpful) ax.set_xticks(X) ax.set_xticklabels([channels[pos+i] for i in range(n)]) # Create slider widget barpos = plt.axes([0.18, 0.05, 0.55, 0.03], facecolor="skyblue") slider = Slider(barpos, 'Channel', 0, len(x)-N, valinit=0, valstep=1) slider.on_changed(bar) # Draw initial bar group bar(0) plt.tight_layout() # Adjust layout to prevent slider overlap plt.show()
Key Changes Recap:
- Fixed label indexing to match the current slider position
- Locked Y-axis to 0-100 with 20-unit ticks
- Added
fontsizeparameter to control annotation text size - Corrected data length mismatch between
xandchannels - Added X-axis tick labels for clarity
- Used
plt.tight_layout()to avoid layout overlap
内容的提问来源于stack exchange,提问作者fishbacp

