Python新手求助:基于Matplotlib绘制滚动二维直方图
Hey there! Let’s work through this 2D histogram issue step by step—since you’re new to Python, I’ll break everything down clearly so you can follow along.
First, let’s clarify what you’re aiming for: you have 1500 (X,Y,Z) points, and you want to bin the data by X and Y, then visualize a Z-derived statistic (like mean, sum, or count) for each bin. Your existing code starts to use np.histogram2d, which is exactly the right tool—we just need to finish it up and add the plotting part.
Let’s Build the Solution
1. Import Required Libraries
First, make sure you have these imported (they’re standard for this kind of work):
import numpy as np import matplotlib.pyplot as plt
2. Prepare Your Data (or Use a Test Set)
Replace the sample data below with your actual x, y, z arrays:
# Simulate 1500 data points (swap this with your real data!) np.random.seed(42) # For reproducible test data x = np.random.normal(0, 1, 1500) y = np.random.normal(0, 1, 1500) z = x**2 + y**2 + np.random.normal(0, 0.5, 1500)
3. Calculate Binned Z Statistics
You started with np.histogram2d—here’s how to complete it to get meaningful Z values per bin. Let’s assume you want the mean Z value for each X-Y bin (adjust if you want sum or something else):
bin_size = 20 # Adjust this based on your data's range (try 10-30 to start) # Calculate sum of Z values per bin (using Z as weights) z_sum, y_edges, x_edges = np.histogram2d(y, x, bins=(bin_size, bin_size), weights=z) # Calculate number of points per bin (to compute mean later) bin_counts, _, _ = np.histogram2d(y, x, bins=(bin_size, bin_size)) # Compute mean Z per bin, avoid division by zero (set empty bins to NaN) z_mean = np.divide(z_sum, bin_counts, out=np.full_like(z_sum, np.nan), where=bin_counts != 0)
- Note: The order
(y, x)inhistogram2dmeans the output array is shaped[y_bins, x_bins]—we’ll match this when plotting. - Using
np.dividewithwhereprevents errors from empty bins (they’ll show up as blank in the plot, which is cleaner than 0 or infinity).
4. Plot the 2D Histogram
Now let’s visualize the binned Z mean with matplotlib:
# Create a figure and axis fig, ax = plt.subplots(figsize=(8, 6)) # Use pcolormesh to plot the binned data (matches bin edges perfectly) im = ax.pcolormesh(x_edges, y_edges, z_mean, cmap='viridis') # Add a color bar to explain the Z values cbar = fig.colorbar(im, ax=ax) cbar.set_label('Mean Z Value') # Label your axes and add a title ax.set_xlabel('X') ax.set_ylabel('Y') ax.set_title('2D Histogram: X-Y Bins with Mean Z Value') # Show the plot plt.show()
If You Meant "Rolling/Sliding Window" Histogram
Wait, you mentioned "rolling"—if you want a sliding window (calculating Z stats over moving local regions instead of fixed bins), here’s how to do that too:
from scipy.ndimage import uniform_filter from scipy.interpolate import griddata # First, grid your raw data into a 2D array x_min, x_max = x.min(), x.max() y_min, y_max = y.min(), y.max() xi = np.linspace(x_min, x_max, bin_size) yi = np.linspace(y_min, y_max, bin_size) xi_grid, yi_grid = np.meshgrid(xi, yi) # Fill the grid with Z values (nearest neighbor interpolation works well) z_grid = griddata((x, y), z, (xi_grid, yi_grid), method='nearest') # Apply a rolling window (3x3 here—adjust size as needed) window_size = 3 rolling_z_mean = uniform_filter(z_grid, size=window_size) # Plot the rolling result fig, ax = plt.subplots(figsize=(8, 6)) im = ax.pcolormesh(xi, yi, rolling_z_mean, cmap='viridis') cbar = fig.colorbar(im, ax=ax) cbar.set_label(f'Rolling Mean Z (Window Size: {window_size}x{window_size})') ax.set_xlabel('X') ax.set_ylabel('Y') ax.set_title('Rolling 2D Histogram (Local Z Mean)') plt.show()
Quick Troubleshooting Tips
- If your plot looks stretched, add
ax.set_aspect('equal')to make X and Y scales match. - Adjust
bin_sizeto make bins larger/smaller—too small and you’ll have empty bins; too large and you’ll lose detail. - If you want sum of Z instead of mean, just use
z_sumdirectly in the plot instead ofz_mean.
内容的提问来源于stack exchange,提问作者JohnB

