Don't min() and max() on your axes when you already know what the extents are. Since I demonstrate the use of a parametric n, just base your extent tuple on that.
import numpy as np
import matplotlib.gridspec
import matplotlib.pyplot as plt
import matplotlib.ticker
import scipy.special
from scipy.ndimage import gaussian_filter
def make_coords(n: int = 250) -> tuple[
np.ndarray, # r
np.ndarray, # theta
tuple[int, int, int, int], # axis extents
]:
# regular cartesian dimensions
ser = slice(-n, 1+n)
yx = np.mgrid[ser, ser]
y, x = yx
extent = x.min()-n, x.max()n, y.min()-n, y.max()n
# irregular polar dimensions based on cartesian dimensions
r = np.linalg.norm(yx, axis=0)
theta = np.arctan2(y, x)
return r, theta, extent
def make_fake(
r: np.ndarray, theta: np.ndarray,
rand: np.random.Generator | None = None,
) -> np.ndarray:
if rand is None:
rand = np.random.default_rng()
# generate some fake data
p0 = (
np.cos(3*theta) * np.sin(np.sqrt(r))
)**6
cleanup = (1 - np.exp(-0.01*r**2))*scipy.special.erfc((r - 200)/8)
lumpy_1 = gaussian_filter(rand.random(r.shape), sigma=1)**2
lumpy_2 = gaussian_filter(rand.random(r.shape), sigma=60)
lumpy_2 -= lumpy_2.min()
p = p0 * cleanup * lumpy_1 * lumpy_2
p /= p.max()
return p
def make_hist(theta: np.ndarray, p: np.ndarray) -> np.ndarray:
"""
Not actually a histogram! This is a binned sum.
assign a bin index to each pixel, centred on integer degrees
(remember that Python's .astype(int) by itself rounds both
+0.99 and -0.99 to zero, so we have to use floor first.
cf. https://scicomp.stackexchange.com/a/40779/17869)
"""
# 0-359, integral, where e.g. [-0.5, 0.5) maps to 0
itheta = np.floor(np.rad2deg(theta) + 0.5).astype(int) % 360
# binned sum with indices in itheta and values in p
total = np.bincount(itheta.ravel(), weights=p.ravel())
return total
def plot_image(
fig: plt.Figure, ax: plt.Axes,
p: np.ndarray, extent: tuple[int, int, int, int],
) -> None:
im = ax.imshow(p, origin='lower', extent=extent)
bar = fig.colorbar(mappable=im)
ax.set_title('Sample dataset')
ax.set_xlabel('x')
ax.set_ylabel('y')
bar.set_label('z')
def plot_hist_rect(
ax: plt.Axes,
hist: np.ndarray,
) -> None:
ax.plot(hist)
ax.xaxis.set_major_locator(matplotlib.ticker.MultipleLocator(30))
ax.set_title('Binned sum')
ax.set_xlabel('bin centre angle (deg)')
ax.set_ylabel('sum')
def plot_hist_polar(
ax: plt.PolarAxes,
hist: np.ndarray,
) -> None:
ax.plot(np.deg2rad(np.arange(360)), hist)
ax.xaxis.set_major_locator(matplotlib.ticker.FixedLocator(
np.deg2rad(np.arange(0, 360, 30)),
))
ax.set_title('Binned sum')
def main() -> None:
# repeatable simulation
rand = np.random.default_rng(seed=4241)
r, theta, extent = make_coords()
p = make_fake(r=r, theta=theta, rand=rand)
hist = make_hist(theta=theta, p=p)
fig = plt.figure()
grid = matplotlib.gridspec.GridSpec(figure=fig, nrows=2, ncols=2)
plot_image(ax=fig.add_subplot(grid[0,0]), fig=fig, p=p, extent=extent)
plot_hist_polar(ax=fig.add_subplot(grid[0,1], projection='polar'), hist=hist)
plot_hist_rect(ax=fig.add_subplot(grid[1,:]), hist=hist)
fig.tight_layout()
plt.show()
if __name__ == '__main__':
main()


