Quick start: geometry and one radial profile¶

    ## Author

    [Rafael S. de Souza](https://rafaelsdesouza.com.br/)

    ## Learning goals

    - provide support and centres
  • inspect centre assignment and both coordinates

  • compute a centre-conditioned profile

      ## Keywords
    
      support mask, supplied centres, radial profile
    
      ## Summary
    
      Construct two coordinates on a connected irregular mask and measure a scalar field.
    
      ## Resources
    
      - [Open in Colab](https://colab.research.google.com/github/RafaelSdeSouza/radialpaths/blob/v0.1.0/examples/01_quickstart.ipynb)
      - [Documentation](https://rafaelsdesouza.com.br/radialpaths/docs/)
      - [Source](https://github.com/RafaelSdeSouza/radialpaths)
      - Paper/preprint: bibliographic link pending
      - [Citation metadata](https://github.com/RafaelSdeSouza/radialpaths/blob/v0.1.0/CITATION.cff)
    
      In Colab, the setup cell installs the immutable RadialPaths 0.1.0 tag.
      In a local checkout, it imports the source tree directly.
from pathlib import Path
import subprocess
import sys

if "google.colab" in sys.modules:
    subprocess.check_call([
        sys.executable, "-m", "pip", "install", "-q",
        "radialpaths[plot] @ git+https://github.com/RafaelSdeSouza/radialpaths.git@v0.1.0",
    ])
else:
    source = Path("src") if Path("src/radialpaths").exists() else Path("../src")
    if str(source.resolve()) not in sys.path:
        sys.path.insert(0, str(source.resolve()))

import matplotlib.pyplot as plt
import numpy as np
from radialpaths import build_geometry, radial_profile

plt.rcParams.update({"font.size": 10, "axes.titlesize": 11, "axes.linewidth": 0.8})

Define the formal inputs¶

True pixels are traversable. Supplied centres use NumPy (row, column) order and must lie inside the connected support.

yy, xx = np.indices((81, 111), dtype=float)
support = ((xx - 52) / 43) ** 2 + ((yy - 40) / 27) ** 2 <= 1
support |= ((xx - 82) / 18) ** 2 + ((yy - 49) / 16) ** 2 <= 1
centres = [(37, 30), (47, 76)]
geometry = build_geometry(support, centres)

intensity = np.full(support.shape, np.nan)
intensity[support] = np.exp(-geometry.centre_distance[support] / 14)
intensity[support] += 0.08 * xx[support] / support.shape[1]
profile = radial_profile(intensity, geometry, coordinate="rho_X")
print(geometry.rho_D.dtype, geometry.rho_X.dtype)
print(profile.median.shape, "centre profiles by", profile.n_bins, "bins")
float64 float64
(2, 30) centre profiles by 30 bins
fig, axes = plt.subplots(1, 4, figsize=(12.2, 3.0), constrained_layout=True)
for ax, field, title in zip(
    axes,
    [intensity, geometry.labels, geometry.rho_D, geometry.rho_X],
    ["Registered intensity", "Centre-associated regions", r"Relative depth $\rho_D$", r"Progression $\rho_X$"],
):
    ax.imshow(field, cmap="cividis", origin="upper", vmin=0, vmax=1)
    ax.contour(support, [0.5], colors="#30363b", linewidths=0.8)
    ax.scatter(np.asarray(centres)[:, 1], np.asarray(centres)[:, 0], c=["#0072B2", "#D55E00"], edgecolors="white", s=35)
    ax.set(title=title, xticks=[], yticks=[])
plt.show()
No description has been provided for this image
fig, ax = plt.subplots(figsize=(5.2, 3.2))
for centre_index, values in enumerate(profile.median):
    ax.plot(profile.radius, values, lw=2, label=f"Centre {centre_index + 1}")
ax.set(xlabel=r"Normalized progression $\rho_X$", ylabel="Median intensity")
ax.spines[["top", "right"]].set_visible(False)
ax.legend(frameon=False)
plt.show()
No description has been provided for this image

The support and centres fix the geometry. Changing the registered intensity values does not recompute centre assignment or either coordinate.