Visualization Module

Visualization Module

Provides plotting functions for ray tracing and detector analysis. Functions are organized into single-axis functions (for composability) and composite figure builders.

Modules

common : Shared utilities and styling raytracing_plots : Ray path and surface visualization detector_plots : Detector and beam analysis visualization

Examples

Single-axis functions for custom layouts:

>>> import matplotlib.pyplot as plt
>>> from surface_roughness.visualization import (
...     plot_ray_paths_projection,
...     plot_ray_endpoints_scatter,
...     plot_detection_counts,
... )
>>> fig, axes = plt.subplots(1, 2)
>>> plot_ray_paths_projection(axes[0], ray_history, projection="xz")
>>> plot_ray_endpoints_scatter(axes[1], rays, projection="xy")

Composite figures for quick visualization:

>>> from surface_roughness.visualization import (
...     create_ray_overview_figure,
...     create_detector_scan_figure,
... )
>>> fig = create_ray_overview_figure(rays, surface)
>>> fig = create_detector_scan_figure(angles, counts, intensities, total)
lsurf.visualization.get_color_mapping(values, cmap_name='viridis', vmin=None, vmax=None)[source]

Create color mapping for values.

Parameters:
  • values (ndarray) – Values to map to colors.

  • cmap_name (str) – Matplotlib colormap name.

  • vmin (float, optional) – Value range. If None, uses data min/max.

  • vmax (float, optional) – Value range. If None, uses data min/max.

Returns:

  • colors (ndarray) – RGBA colors for each value.

  • norm (Normalize) – Normalization object.

  • sm (ScalarMappable) – ScalarMappable for colorbar.

Return type:

tuple[ndarray, Normalize, _ScalarMappable]

lsurf.visualization.get_projection_config(projection)[source]

Get axis indices and labels for xy/xz/yz projections.

Parameters:

projection (str) – Projection plane: ‘xy’, ‘xz’, or ‘yz’.

Returns:

  • idx1 (int) – First coordinate index (0=x, 1=y, 2=z).

  • idx2 (int) – Second coordinate index.

  • xlabel (str) – Label for first axis.

  • ylabel (str) – Label for second axis.

Return type:

tuple[int, int, str, str]

lsurf.visualization.wavelength_to_color(wavelength_m)[source]

Convert wavelength (in meters) to approximate visible color.

Parameters:

wavelength_m (float or ndarray) – Wavelength in meters.

Returns:

color – RGB color tuple(s) in [0, 1] range.

Return type:

tuple or ndarray

Notes

Uses simplified visible spectrum approximation. Wavelengths outside visible range return gray.

lsurf.visualization.setup_axis_grid(ax, xlabel='', ylabel='', title='', grid=True)[source]

Apply standard axis formatting.

Parameters:
  • ax (Axes) – Matplotlib axes.

  • xlabel (str) – Axis labels.

  • ylabel (str) – Axis labels.

  • title (str) – Axis title.

  • grid (bool) – Whether to show grid.

lsurf.visualization.add_colorbar(ax, mappable, label='', orientation='vertical')[source]

Add colorbar to axes.

Parameters:
  • ax (Axes) – Matplotlib axes.

  • mappable (ScalarMappable) – Object with color mapping.

  • label (str) – Colorbar label.

  • orientation (str) – ‘vertical’ or ‘horizontal’.

Returns:

Matplotlib colorbar object.

Return type:

colorbar

lsurf.visualization.create_figure(nrows=1, ncols=1, figsize=None, constrained_layout=True, **kwargs)[source]

Create figure with standard settings.

Parameters:
  • nrows (int) – Number of subplot rows and columns.

  • ncols (int) – Number of subplot rows and columns.

  • figsize (tuple, optional) – Figure size. Defaults to scaled DEFAULT_FIGSIZE.

  • constrained_layout (bool) – Use constrained layout.

  • **kwargs – Additional arguments to plt.subplots.

Returns:

  • fig (Figure) – Matplotlib figure.

  • axes (Axes or ndarray) – Axes object(s).

Return type:

tuple[Figure, Axes | ndarray]

lsurf.visualization.save_figure(fig, path, dpi=150, bbox_inches='tight', **kwargs)[source]

Save figure with standard settings.

Parameters:
  • fig (Figure) – Matplotlib figure.

  • path (str) – Output path.

  • dpi (int) – Resolution.

  • bbox_inches (str) – Bounding box setting.

  • **kwargs – Additional arguments to savefig.

lsurf.visualization.plot_ray_paths_projection(ax, ray_history, projection='xz', max_rays=100, color_by='wavelength', alpha=0.6, linewidth=0.5, show_colorbar=True)[source]

Plot ray paths as a 2D projection on given axis.

Parameters:
  • ax (Axes) – Matplotlib axes to draw on.

  • ray_history (List[RayBatch]) – List of ray batches at different time steps.

  • projection (str) – Projection plane: ‘xy’, ‘xz’, or ‘yz’.

  • max_rays (int) – Maximum rays to plot for performance.

  • color_by (str) – Color rays by: ‘wavelength’, ‘intensity’, ‘generation’, ‘index’.

  • alpha (float) – Line transparency.

  • linewidth (float) – Line width.

  • show_colorbar (bool) – Whether to add colorbar.

Returns:

sm – ScalarMappable for external colorbar, or None.

Return type:

ScalarMappable or None

lsurf.visualization.plot_ray_endpoints_scatter(ax, rays, projection='xy', color_by='intensity', alpha=0.5, size=5, show_colorbar=True)[source]

Plot ray endpoint positions as scatter plot.

Parameters:
  • ax (Axes) – Matplotlib axes.

  • rays (RayBatch) – Ray batch.

  • projection (str) – Plane: ‘xy’, ‘xz’, ‘yz’.

  • color_by (str) – Color by: ‘intensity’, ‘wavelength’, ‘generation’, ‘time’.

  • alpha (float) – Point transparency.

  • size (float) – Point size.

  • show_colorbar (bool) – Whether to add colorbar.

Returns:

sm – For external colorbar.

Return type:

ScalarMappable or None

lsurf.visualization.plot_ray_endpoints_histogram(ax, rays, projection='xy', bins=50, cmap='hot')[source]

Plot 2D histogram of ray endpoint density.

Parameters:
  • ax (Axes) – Matplotlib axes.

  • rays (RayBatch) – Ray batch.

  • projection (str) – Plane: ‘xy’, ‘xz’, ‘yz’.

  • bins (int) – Number of histogram bins.

  • cmap (str) – Colormap name.

lsurf.visualization.plot_surface_profile(ax, surface, x_range=(-200, 200), y=0.0, n_points=1000, color='blue', linewidth=2.0, label='Surface')[source]

Plot surface height profile along x-axis.

Parameters:
  • ax (Axes) – Matplotlib axes.

  • surface (Surface) – Surface object with _surface_z method.

  • x_range (tuple) – (x_min, x_max) range.

  • y (float) – Y-coordinate for profile.

  • n_points (int) – Number of sample points.

  • color (str) – Line color.

  • linewidth (float) – Line width.

  • label (str) – Legend label.

lsurf.visualization.plot_bounce_points(ax, bounce_positions, bounce_number=1, color=None, size=20, alpha=0.7, projection='xz', label=None)[source]

Plot ray bounce points on surface.

Parameters:
  • ax (Axes) – Matplotlib axes.

  • bounce_positions (ndarray) – (N, 3) array of bounce positions.

  • bounce_number (int) – Bounce index (for color selection).

  • color (str, optional) – Override color.

  • size (float) – Marker size.

  • alpha (float) – Transparency.

  • projection (str) – Coordinate projection (‘xz’, ‘xy’, ‘yz’).

  • label (str, optional) – Legend label.

lsurf.visualization.plot_incoming_rays(ax, rays, surface, projection='xz', color='gold', alpha=0.3, linewidth=0.5, max_rays=100)[source]

Plot incoming ray segments from origin to surface intersection.

Parameters:
  • ax (Axes) – Matplotlib axes.

  • rays (RayBatch) – Ray batch before intersection.

  • surface (Surface) – Surface for intersection calculation.

  • projection (str) – Coordinate projection.

  • color (str) – Ray color.

  • alpha (float) – Transparency.

  • linewidth (float) – Line width.

  • max_rays (int) – Maximum rays to plot.

lsurf.visualization.plot_reflected_rays(ax, rays, length=100.0, projection='xz', color='cyan', alpha=0.3, linewidth=0.5, max_rays=100)[source]

Plot reflected ray segments from current position.

Parameters:
  • ax (Axes) – Matplotlib axes.

  • rays (RayBatch) – Reflected ray batch.

  • length (float) – Length of ray segments to draw.

  • projection (str) – Coordinate projection.

  • color (str) – Ray color.

  • alpha (float) – Transparency.

  • linewidth (float) – Line width.

  • max_rays (int) – Maximum rays to plot.

lsurf.visualization.plot_multi_bounce_paths(ax, ray_paths, projection='xz', reflected_color='cyan', refracted_color='orange', alpha=0.3, linewidth=0.5, max_paths=100)[source]

Plot multi-bounce ray paths from trace_rays_multi_bounce output.

Parameters:
  • ax (Axes) – Matplotlib axes.

  • ray_paths (dict) – Dictionary with ‘reflected_paths’ and/or ‘refracted_paths’ lists.

  • projection (str) – Coordinate projection.

  • reflected_color (str) – Color for reflected paths.

  • refracted_color (str) – Color for refracted paths.

  • alpha (float) – Transparency.

  • linewidth (float) – Line width.

  • max_paths (int) – Maximum paths to plot.

lsurf.visualization.create_ray_overview_figure(rays, surface, reflected_rays=None, bounce_points=None, figsize=(16, 10), x_range=(-500, 500), title='Ray Tracing Overview', save_path=None)[source]

Create comprehensive ray tracing overview figure.

Parameters:
  • rays (RayBatch) – Initial rays.

  • surface (Surface) – Wave surface.

  • reflected_rays (RayBatch, optional) – Reflected rays.

  • bounce_points (List[ndarray], optional) – List of bounce position arrays per bounce.

  • figsize (tuple) – Figure size.

  • x_range (tuple) – X-axis range.

  • title (str) – Figure title.

  • save_path (str, optional) – Path to save figure.

Returns:

Matplotlib figure.

Return type:

Figure

lsurf.visualization.plot_production_ray_overview(original_rays, surface, config, output_path, timestamp, max_bounces=2)[source]

Create production simulation ray overview with surface bounce points.

Shows incoming rays, bounce points on wave surface (colored by bounce number), and reflected rays toward recording sphere.

Parameters:
  • original_rays (RayBatch) – Original rays before tracing.

  • surface (Surface) – The wave surface (e.g., CurvedWaveSurface).

  • config (dict) – Simulation configuration with keys: - grazing_angle: Beam grazing angle in degrees - beam_radius: Beam radius in meters - earth_radius: Earth radius in meters - recording_altitude: Recording sphere altitude in meters - source_distance: Source distance in meters

  • output_path (str) – Directory to save figure.

  • timestamp (str) – Timestamp for filename.

  • max_bounces (int) – Maximum number of bounces to visualize (default: 2).

Returns:

Matplotlib figure.

Return type:

Figure

lsurf.visualization.plot_wave_surface_detail(reflected_rays, surface, x_range=(-200, 200), figsize=(12, 6), save_path=None)[source]

Plot wave surface detail with ray intersection points.

Parameters:
  • reflected_rays (RayBatch) – Batch of reflected rays.

  • surface (Surface) – The surface object (must have _surface_z method).

  • x_range (tuple) – X-axis range for plotting.

  • figsize (tuple) – Figure size (width, height).

  • save_path (str, optional) – Path to save figure.

Returns:

Matplotlib figure.

Return type:

Figure

lsurf.visualization.plot_ray_paths_with_surface(rays, reflected_rays, surface, detector_distance=1000.0, source_distance=1000.0, refracted_rays=None, ray_paths=None, figsize=(16, 10), save_path=None)[source]

Plot full ray paths (incoming, reflected, and refracted) with wave surface.

Parameters:
  • rays (RayBatch) – Initial ray batch (before interaction).

  • reflected_rays (RayBatch) – Reflected ray batch (after interaction).

  • surface (Surface) – The surface object.

  • detector_distance (float) – Detector distance in meters.

  • source_distance (float) – Source distance in meters (unused, for API compatibility).

  • refracted_rays (RayBatch, optional) – Refracted ray batch (after interaction).

  • ray_paths (dict, optional) – Dictionary with ray path data from trace_rays_multi_bounce containing: - ‘reflected_paths’: list of Nx3 arrays, one per ray - ‘refracted_paths’: list of Nx3 arrays for refracted rays - ‘reflected_final_dirs’: final direction for each reflected path - ‘refracted_final_dirs’: final direction for each refracted path

  • figsize (tuple) – Figure size.

  • save_path (str, optional) – Path to save figure.

Returns:

Matplotlib figure.

Return type:

Figure

lsurf.visualization.plot_fresnel_reflection(incident_rays, reflected_rays, refracted_rays, surface_normal, surface_angle_deg, n1, n2, wavelength, fresnel_func=None, figsize=(16, 10), save_path=None)[source]

Create comprehensive Fresnel reflection visualization.

Shows ray paths, intensity distributions, Fresnel curves, and energy summary.

Parameters:
  • incident_rays (RayBatch) – Original incident rays.

  • reflected_rays (RayBatch) – Reflected rays from surface interaction.

  • refracted_rays (RayBatch, optional) – Refracted (transmitted) rays.

  • surface_normal (tuple) – Surface normal vector (nx, ny, nz).

  • surface_angle_deg (float) – Surface tilt angle in degrees.

  • n1 (float) – Refractive index of incident medium.

  • n2 (float) – Refractive index of transmission medium.

  • wavelength (float) – Optical wavelength in meters.

  • fresnel_func (callable, optional) – Function to compute Fresnel coefficients: fresnel_func(n1, n2, cos_theta, pol). If not provided, uses surface_roughness.utilities.fresnel.fresnel_coefficients.

  • figsize (tuple) – Figure size.

  • save_path (str, optional) – Path to save figure.

Returns:

Matplotlib figure with 6 subplots.

Return type:

Figure

lsurf.visualization.plot_brewster_validation(angles_theory_deg, R_s_theory, R_p_theory, angles_sim_deg, R_s_sim, R_p_sim, n1, n2, brewster_angle_deg, brewster_sim_deg, wavelength, num_rays_per_angle=1000, figsize=(16, 10), save_path=None)[source]

Create Brewster angle validation visualization.

Compares theoretical Fresnel curves with ray-traced simulation results.

Parameters:
  • angles_theory_deg (ndarray) – Theory angle array in degrees.

  • R_s_theory (ndarray) – Theoretical s-polarization reflectance.

  • R_p_theory (ndarray) – Theoretical p-polarization reflectance.

  • angles_sim_deg (ndarray) – Simulation angle array in degrees.

  • R_s_sim (ndarray) – Simulated s-polarization reflectance.

  • R_p_sim (ndarray) – Simulated p-polarization reflectance.

  • n1 (float) – Refractive index of incident medium.

  • n2 (float) – Refractive index of transmission medium.

  • brewster_angle_deg (float) – Theoretical Brewster angle in degrees.

  • brewster_sim_deg (float) – Simulated Brewster angle (minimum R_p) in degrees.

  • wavelength (float) – Optical wavelength in meters.

  • num_rays_per_angle (int) – Number of rays used per angle in simulation.

  • figsize (tuple) – Figure size.

  • save_path (str, optional) – Path to save figure.

Returns:

Matplotlib figure with validation plots.

Return type:

Figure

lsurf.visualization.plot_polarization_vector_components(recorded_rays, bins=50, figsize=(18, 6), save_path=None, vmin=None, vmax=None, cmap='RdBu_r', projection='angular')[source]

Plot 3D polarization vector components at the detection surface.

Creates three subfigures showing the average X (horizontal), Y (vertical), and Z (depth) components of the polarization vector binned by position.

Parameters:
  • recorded_rays (RecordedRays) – Recorded rays at the detection sphere, must have polarization_vectors.

  • bins (int) – Number of bins in each dimension for the 2D histogram.

  • figsize (tuple) – Figure size (width, height).

  • save_path (str, optional) – Path to save figure.

  • vmin (float, optional) – Minimum value for colormap. Default is symmetric around 0.

  • vmax (float, optional) – Maximum value for colormap. Default is symmetric around 0.

  • cmap (str) – Colormap name. Default ‘RdBu_r’ is diverging (good for signed values).

  • projection (str) – Type of projection for binning: - ‘angular’: Use elevation and azimuth angles - ‘spatial’: Use X and Y positions on detection surface

Returns:

Matplotlib figure with three subplots.

Return type:

Figure

Notes

The polarization vector represents the electric field direction at each ray. For unpolarized light scattered from a wavy surface: - X component: Horizontal polarization - Y component: Vertical polarization - Z component: Along depth/propagation direction

Each bin shows the intensity-weighted average polarization component.

lsurf.visualization.plot_polarization_ellipse(recorded_rays, bins=30, figsize=(12, 10), save_path=None, projection='angular', arrow_scale=1.0)[source]

Plot polarization state as arrows/ellipses on the detection surface.

Shows the average polarization direction in each bin as an arrow.

Parameters:
  • recorded_rays (RecordedRays) – Recorded rays at the detection sphere, must have polarization_vectors.

  • bins (int) – Number of bins in each dimension.

  • figsize (tuple) – Figure size.

  • save_path (str, optional) – Path to save figure.

  • projection (str) – Type of projection: ‘angular’ or ‘spatial’.

  • arrow_scale (float) – Scale factor for arrow lengths.

Returns:

Matplotlib figure with polarization arrows.

Return type:

Figure

lsurf.visualization.plot_polarization_vs_elevation(recorded_rays, bins=50, figsize=(14, 5), save_path=None)[source]

Plot polarization degree as a function of ray elevation angle.

Averages over all azimuth angles to show how polarization varies with the ray angle from horizontal.

Parameters:
  • recorded_rays (RecordedRays) – Recorded rays at the detection sphere, must have polarization_vectors.

  • bins (int) – Number of elevation angle bins.

  • figsize (tuple) – Figure size (width, height).

  • save_path (str, optional) – Path to save figure.

Returns:

Matplotlib figure with polarization vs elevation plots.

Return type:

Figure

Notes

The polarization degree is computed as:

DoP = (E_x² - E_y²) / (E_x² + E_y²)

Where E_x is the horizontal component and E_y is the vertical component of the polarization vector. DoP = +1 means fully horizontal polarization, DoP = -1 means fully vertical polarization, DoP = 0 means unpolarized or 45° linear polarization.

lsurf.visualization.plot_fresnel_reflectance_curves(n1=1.0, n2=1.33, angles_deg=None, brewster_angle_deg=None, figsize=(8, 6), save_path=None)[source]

Plot Fresnel reflection coefficients R_s, R_p, and R_unpolarized vs elevation.

Creates a single-subplot figure showing how the reflection coefficients for s-polarization, p-polarization, and unpolarized light vary with elevation angle (angle above horizontal). This convention matches the measured reflectance plots for easy comparison.

Parameters:
  • n1 (float, optional) – Refractive index of incident medium (default: 1.0 for air)

  • n2 (float, optional) – Refractive index of transmitting medium (default: 1.33 for water)

  • angles_deg (ndarray, optional) – Elevation angles in degrees to compute (default: 0 to 90 in 0.5° steps)

  • brewster_angle_deg (float, optional) – Brewster angle (as incidence angle) to mark on plot. If None, computed from n1, n2.

  • figsize (tuple, optional) – Figure size in inches

  • save_path (str, optional) – Path to save figure

Returns:

Matplotlib figure

Return type:

Figure

Notes

The x-axis shows elevation angle (angle above horizontal), which relates to incidence angle as: elevation = 90° - incidence_angle.

  • Low elevation (grazing) → high incidence angle → high reflectance

  • High elevation (steep) → low incidence angle → low reflectance

Fresnel equations for reflection: - R_s = |r_s|² where r_s = (n1*cos_i - n2*cos_t) / (n1*cos_i + n2*cos_t) - R_p = |r_p|² where r_p = (n2*cos_i - n1*cos_t) / (n2*cos_i + n1*cos_t) - R_unpolarized = (R_s + R_p) / 2

Brewster angle: θ_B = arctan(n2/n1), where R_p = 0

lsurf.visualization.plot_measured_polarization_reflectance(recorded_rays, bins=50, figsize=(10, 6), save_path=None)[source]

Plot measured reflected intensity decomposed into s and p polarization.

Analyzes recorded rays to show how the reflected intensity is distributed between s-polarization (horizontal) and p-polarization (vertical) as a function of ray elevation angle. This treats the surface as an unknown reflector and measures its polarization behavior.

Parameters:
  • recorded_rays (RecordedRays) – Recorded rays with polarization vectors

  • bins (int, optional) – Number of elevation angle bins (default: 50)

  • figsize (tuple, optional) – Figure size in inches

  • save_path (str, optional) – Path to save figure

Returns:

Matplotlib figure

Return type:

Figure

Notes

For each ray, the polarization vector is decomposed into: - s-component: horizontal (perpendicular to vertical plane containing ray) - p-component: vertical (in the vertical plane containing ray)

The intensity is then weighted by |E_s|² and |E_p|² to get the intensity in each polarization state.

lsurf.visualization.get_ray_coordinates(recorded_rays, projection='angular')[source]

Convert recorded rays to coordinates for binning/plotting.

Parameters:
  • recorded_rays (RecordedRays) – Recorded rays at the detection sphere.

  • projection (str) – Type of projection for binning: - ‘angular’: Use elevation and azimuth angles - ‘spatial’: Use X and Y positions on detection surface

Returns:

  • x_coord (ndarray) – X coordinates for plotting/binning.

  • y_coord (ndarray) – Y coordinates for plotting/binning.

  • xlabel (str) – Label for x-axis.

  • ylabel (str) – Label for y-axis.

Return type:

tuple[ndarray, ndarray, str, str]

lsurf.visualization.plot_ray_paths_2d(ray_history, max_rays=100, color_by='wavelength', alpha=0.4, linewidth=0.8, figsize=(15, 5), save_path=None)[source]

Create figure with three 2D projections of ray paths.

This is a convenience function for quick visualization. For custom layouts, use plot_ray_paths_projection() on individual axes.

Parameters:
  • ray_history (List[RayBatch]) – List of ray batches at different propagation steps.

  • max_rays (int) – Maximum rays to plot (sampled uniformly if exceeded).

  • color_by (str) – Color rays by: ‘wavelength’, ‘intensity’, ‘generation’, ‘index’.

  • alpha (float) – Line transparency.

  • linewidth (float) – Line width.

  • figsize (tuple) – Figure size.

  • save_path (str, optional) – Path to save figure.

Returns:

Matplotlib figure with three subplots (XY, XZ, YZ).

Return type:

Figure

lsurf.visualization.plot_ray_endpoints(rays, plane='xy', color_by='wavelength', bins=50, figsize=(12, 5), save_path=None)[source]

Create figure with scatter and histogram of ray endpoints.

This is a convenience function for quick visualization. For custom layouts, use plot_ray_endpoints_scatter() and plot_ray_endpoints_histogram().

Parameters:
  • rays (RayBatch) – Ray batch with endpoint positions.

  • plane (str) – Projection plane: ‘xy’, ‘xz’, ‘yz’.

  • color_by (str) – Color scatter by: ‘wavelength’, ‘intensity’.

  • bins (int) – Histogram bins.

  • figsize (tuple) – Figure size.

  • save_path (str, optional) – Path to save figure.

Returns:

Matplotlib figure with scatter and histogram.

Return type:

Figure

lsurf.visualization.plot_beam_slice(ax, rays, axis='z', slice_value=0.0, slice_width=0.1, color_by='intensity', point_size=20, alpha=0.6, show_colorbar=True)[source]

Plot beam profile at a specific slice along propagation axis.

Parameters:
  • ax (Axes) – Matplotlib axes.

  • rays (RayBatch) – Ray batch.

  • axis (str) – Propagation axis: ‘x’, ‘y’, or ‘z’.

  • slice_value (float) – Position along axis to slice.

  • slice_width (float) – Width of slice.

  • color_by (str) – Color by: ‘intensity’, ‘wavelength’.

  • point_size (float) – Scatter point size.

  • alpha (float) – Transparency.

  • show_colorbar (bool) – Whether to add colorbar.

Returns:

ScalarMappable for external colorbar.

Return type:

scatter or None

lsurf.visualization.plot_wavelength_histogram(ax, rays, bins=50, alpha=0.7, color='steelblue', edgecolor='black', label=None, weight_by_intensity=False)[source]

Plot histogram of ray wavelengths.

Parameters:
  • ax (Axes) – Matplotlib axes.

  • rays (RayBatch) – Ray batch.

  • bins (int) – Number of histogram bins.

  • alpha (float) – Bar transparency.

  • color (str) – Bar color.

  • edgecolor (str) – Edge color.

  • label (str, optional) – Legend label.

  • weight_by_intensity (bool) – If True, weight histogram by ray intensities.

lsurf.visualization.plot_wavelength_intensity_histogram(ax, rays, bins=50, alpha=0.7, color='orange', edgecolor='black', label=None)[source]

Plot intensity-weighted histogram of ray wavelengths.

Deprecated: Use plot_wavelength_histogram(weight_by_intensity=True) instead.

Parameters:
  • ax (Axes) – Matplotlib axes.

  • rays (RayBatch) – Ray batch.

  • bins (int) – Number of histogram bins.

  • alpha (float) – Bar transparency.

  • color (str) – Bar color.

  • edgecolor (str) – Edge color.

  • label (str, optional) – Legend label.

lsurf.visualization.plot_detection_counts(ax, detector_angles_deg, detection_counts, color='blue', marker='o', linewidth=2, markersize=8, label=None)[source]

Plot detection counts vs detector angle.

Parameters:
  • ax (Axes) – Matplotlib axes.

  • detector_angles_deg (ndarray) – Detector angles in degrees.

  • detection_counts (ndarray) – Number of rays detected.

  • color (str) – Line color.

  • marker (str) – Marker style.

  • linewidth (float) – Line width.

  • markersize (float) – Marker size.

  • label (str, optional) – Legend label.

lsurf.visualization.plot_detection_efficiency(ax, detector_angles_deg, detected_intensities, total_source_intensity, color='magenta', marker='o', linewidth=2, markersize=8, label=None)[source]

Plot detection efficiency vs detector angle.

Parameters:
  • ax (Axes) – Matplotlib axes.

  • detector_angles_deg (ndarray) – Detector angles in degrees.

  • detected_intensities (ndarray) – Total intensity detected.

  • total_source_intensity (float) – Total source intensity.

  • color (str) – Line color.

  • marker (str) – Marker style.

  • linewidth (float) – Line width.

  • markersize (float) – Marker size.

  • label (str, optional) – Legend label.

lsurf.visualization.plot_mean_arrival_time(ax, detector_angles_deg, mean_times, std_times=None, detection_counts=None, color='cyan', marker='o', linewidth=2, markersize=8, label=None)[source]

Plot mean arrival time vs detector angle.

Parameters:
  • ax (Axes) – Matplotlib axes.

  • detector_angles_deg (ndarray) – Detector angles in degrees.

  • mean_times (ndarray) – Mean arrival times in seconds.

  • std_times (ndarray, optional) – Standard deviation of arrival times.

  • detection_counts (ndarray, optional) – For masking invalid data.

  • color (str) – Line color.

  • marker (str) – Marker style.

  • linewidth (float) – Line width.

  • markersize (float) – Marker size.

  • label (str, optional) – Legend label.

lsurf.visualization.plot_timing_distribution(ax, all_time_distributions, detector_angles_deg, log_scale=True, show_legend=True, max_curves=10)[source]

Plot arrival time distributions for multiple detector positions.

Parameters:
  • ax (Axes) – Matplotlib axes.

  • all_time_distributions (list) – List of (times, intensities, angles) tuples for each detector.

  • detector_angles_deg (ndarray) – Detector angles in degrees.

  • log_scale (bool) – Whether to use log scales.

  • show_legend (bool) – Whether to show legend.

  • max_curves (int) – Maximum number of curves to plot.

lsurf.visualization.plot_arrival_angle_distribution(ax, detector_angles_deg, mean_angles, std_angles=None, detection_counts=None, color='magenta', marker='o', linewidth=2, markersize=8)[source]

Plot mean arrival angle vs detector position.

Parameters:
  • ax (Axes) – Matplotlib axes.

  • detector_angles_deg (ndarray) – Detector position angles.

  • mean_angles (ndarray) – Mean arrival angles to normal.

  • std_angles (ndarray, optional) – Standard deviation.

  • detection_counts (ndarray, optional) – For masking invalid data.

  • color (str) – Line color.

  • marker (str) – Marker style.

  • linewidth (float) – Line width.

  • markersize (float) – Marker size.

lsurf.visualization.plot_angular_histogram(ax, all_time_distributions, detection_counts, bins=50, color='purple', alpha=0.7)[source]

Plot histogram of all arrival angles.

Parameters:
  • ax (Axes) – Matplotlib axes.

  • all_time_distributions (list) – List of (times, intensities, angles) tuples.

  • detection_counts (ndarray) – Detection counts per position.

  • bins (int) – Number of histogram bins.

  • color (str) – Bar color.

  • alpha (float) – Transparency.

lsurf.visualization.create_wavelength_figure(rays, bins=50, figsize=(10, 5), title='Wavelength Distribution', save_path=None)[source]

Create figure with wavelength histograms.

Parameters:
  • rays (RayBatch) – Ray batch.

  • bins (int) – Histogram bins.

  • figsize (tuple) – Figure size.

  • title (str) – Figure title.

  • save_path (str, optional) – Save path.

Returns:

Matplotlib figure.

Return type:

Figure

lsurf.visualization.create_beam_profile_figure(rays, axis='z', num_slices=5, figsize=(15, 4), title=None, save_path=None)[source]

Create figure showing beam profile at multiple slices.

Parameters:
  • rays (RayBatch) – Ray batch.

  • axis (str) – Propagation axis.

  • num_slices (int) – Number of slices.

  • figsize (tuple) – Figure size.

  • title (str, optional) – Figure title.

  • save_path (str, optional) – Save path.

Returns:

Matplotlib figure.

Return type:

Figure

lsurf.visualization.create_detector_scan_figure(detector_angles_deg, detection_counts, detected_intensities, total_source_intensity, mean_arrival_times=None, std_arrival_times=None, mean_angles_to_normal=None, std_angles_to_normal=None, all_time_distributions=None, figsize=(16, 12), title='Detector Scan Results', save_path=None)[source]

Create comprehensive detector scan figure.

Parameters:
  • detector_angles_deg (ndarray) – Detector angles in degrees.

  • detection_counts (ndarray) – Number of rays detected.

  • detected_intensities (ndarray) – Total intensity detected.

  • total_source_intensity (float) – Source intensity.

  • mean_arrival_times (ndarray, optional) – Mean arrival times.

  • std_arrival_times (ndarray, optional) – Std of arrival times.

  • mean_angles_to_normal (ndarray, optional) – Mean arrival angles.

  • std_angles_to_normal (ndarray, optional) – Std of arrival angles.

  • all_time_distributions (list, optional) – Timing data.

  • figsize (tuple) – Figure size.

  • title (str) – Figure title.

  • save_path (str, optional) – Save path.

Returns:

Matplotlib figure.

Return type:

Figure

lsurf.visualization.plot_detector_scan_results(detector_angles_deg, detection_counts, detected_intensities, reflected_rays, surface, total_source_intensity, mean_arrival_times=None, std_arrival_times=None, mean_angles_to_normal=None, std_angles_to_normal=None, all_time_distributions=None, detector_distance=1000.0, detector_radius=5.0, water_normal=None, figsize=(24, 14), save_path=None)[source]

Create comprehensive detector scan visualization with multiple subplots.

This is the full production visualization with all panels including the wave surface and ray visualizations.

Parameters:
  • detector_angles_deg (ndarray) – Detector angles in degrees (0-90).

  • detection_counts (ndarray) – Number of rays detected at each position.

  • detected_intensities (ndarray) – Total intensity detected at each position.

  • reflected_rays (RayBatch) – Batch of reflected rays.

  • surface (Surface) – The surface object (must have _surface_z method).

  • total_source_intensity (float) – Total intensity of source rays.

  • mean_arrival_times (ndarray, optional) – Mean arrival time at each detector position.

  • std_arrival_times (ndarray, optional) – Standard deviation of arrival times.

  • mean_angles_to_normal (ndarray, optional) – Mean angle to normal at each detector.

  • std_angles_to_normal (ndarray, optional) – Standard deviation of angles.

  • all_time_distributions (list, optional) – List of (times, intensities, angles) tuples for each detector.

  • detector_distance (float) – Distance to detector in meters.

  • detector_radius (float) – Detector radius in meters.

  • water_normal (ndarray) – Normal vector for water surface.

  • figsize (tuple) – Figure size (width, height).

  • save_path (str, optional) – Path to save figure.

Returns:

Matplotlib figure with comprehensive visualization.

Return type:

Figure

lsurf.visualization.plot_statistics_evolution(stats_history, figsize=(15, 10), save_path=None)[source]

Create figure showing evolution of ray statistics over propagation.

This is a convenience function for visualizing how beam properties change during propagation.

Parameters:
  • stats_history (List[RayStatistics]) – List of RayStatistics objects at different propagation steps.

  • figsize (tuple) – Figure size.

  • save_path (str, optional) – Path to save figure.

Returns:

Matplotlib figure with statistics evolution.

Return type:

Figure

lsurf.visualization.plot_beam_profile(rays, axis='z', num_slices=5, figsize=(15, 4), save_path=None)[source]

Create figure showing beam profile at multiple slices.

This is an alias for create_beam_profile_figure for backward compatibility.

Parameters:
  • rays (RayBatch) – Ray batch.

  • axis (str) – Propagation axis: ‘x’, ‘y’, ‘z’.

  • num_slices (int) – Number of slices to show.

  • figsize (tuple) – Figure size.

  • save_path (str, optional) – Path to save figure.

Returns:

Matplotlib figure.

Return type:

Figure

lsurf.visualization.plot_wavelength_distribution(rays, bins=50, figsize=(10, 6), save_path=None)[source]

Create figure showing wavelength distribution of rays.

This is a convenience function for quick visualization. For custom layouts, use plot_wavelength_histogram() on a single axis.

Parameters:
  • rays (RayBatch) – Ray batch.

  • bins (int) – Number of histogram bins.

  • figsize (tuple) – Figure size.

  • save_path (str, optional) – Path to save figure.

Returns:

Matplotlib figure with wavelength histogram.

Return type:

Figure

lsurf.visualization.create_ocean_simulation_figures(original_rays, surface, recorded_rays, reflected_rays, refracted_rays, config, output_dir, timestamp)[source]

Create complete visualization suite for ocean wave simulation.

Generates 8 figures: 1. Ray paths overview (full scale and surface detail) 2. Recorded rays statistics (6-panel figure) 3. Intensity vs angle (log scale, fraction) 4. Intensity vs angle (linear scale, fraction) 5. Intensity density (log scale, ns⁻¹) 6. Intensity density (linear scale, ns⁻¹) 7. 3D visualization 8. Energy conservation check

Parameters:
  • original_rays (RayBatch) – Initial input rays before interaction

  • surface (CurvedWaveSurface) – The ocean surface model

  • recorded_rays (RecordedRays) – Rays detected at the recording sphere

  • reflected_rays (RayBatch) – Reflected rays from surface

  • refracted_rays (RayBatch) – Refracted rays into water

  • config (dict) – Simulation configuration parameters

  • output_dir (str) – Directory for output files

  • timestamp (str) – Timestamp string for filenames

lsurf.visualization.plot_geometry_schematic(source_position, beam_direction, grazing_angle_deg, detector_altitude, intersection_points, reflected_directions, n_rays_to_show=20, save_path=None)[source]

Plot a schematic overview of the simulation geometry.

Shows side view (x-z plane) with source, rays, ocean surface, and detector sphere.

Parameters:
  • source_position (tuple) – Source (x, y, z) position in meters

  • beam_direction (tuple or ndarray) – Beam direction unit vector

  • grazing_angle_deg (float) – Grazing angle in degrees

  • detector_altitude (float) – Detector sphere radius in meters

  • intersection_points (ndarray, shape (N, 3)) – XYZ coordinates of surface intersections

  • reflected_directions (ndarray, shape (N, 3)) – Direction vectors of reflected rays

  • n_rays_to_show (int) – Number of rays to display

  • save_path (str, optional) – Path to save figure

Returns:

fig – The created figure

Return type:

matplotlib.figure.Figure

lsurf.visualization.plot_ocean_intersections_top_view(intersection_points, wave_surface=None, n_bins=100, save_path=None)[source]

Plot top-down heatmap of where rays hit the ocean surface.

Parameters:
  • intersection_points (ndarray, shape (N, 3)) – XYZ coordinates of surface intersections

  • wave_surface (CurvedWaveSurface, optional) – The ocean surface for context (not currently used)

  • n_bins (int) – Number of bins for the 2D histogram

  • save_path (str, optional) – Path to save figure

Returns:

fig – The created figure

Return type:

matplotlib.figure.Figure

lsurf.visualization.plot_3d_intersection_scatter(intersection_points, save_path=None)[source]

3D scatter plot of ocean surface intersection points with equal axes.

Parameters:
  • intersection_points (ndarray, shape (N, 3)) – XYZ coordinates of surface intersections

  • save_path (str, optional) – Path to save figure

Returns:

fig – The created figure

Return type:

matplotlib.figure.Figure

lsurf.visualization.plot_pareto_front(pareto_result, time_threshold_ns=10.0, source_power=1.0, save_path=None)[source]

Plot the Pareto front of energy density vs time spread.

Parameters:
  • pareto_result (dict) – Result from compute_pareto_front()

  • time_threshold_ns (float) – Detector time resolution threshold (ns)

  • source_power (float) – Input source power for normalization (W)

  • save_path (str, optional) – Path to save figure

Returns:

fig – The created figure, or None if no data

Return type:

matplotlib.figure.Figure or None

lsurf.visualization.plot_energy_density_map(peak_result, recorded_rays, source_power=1.0, detector_center=None, save_path=None)[source]

Plot energy density map on detector sphere with peak location marked.

Parameters:
  • peak_result (dict) – Result from find_peak_energy_density()

  • recorded_rays (RecordedRays) – Recorded rays for overlay

  • source_power (float) – Input source power for normalization (W)

  • detector_center (array-like, optional) – Center of detector sphere (not used currently)

  • save_path (str, optional) – Path to save figure

Returns:

fig – The created figure

Return type:

matplotlib.figure.Figure

lsurf.visualization.plot_mollweide_detector_projection(recorded_rays, save_path=None)[source]

Mollweide projection showing where rays intersect the detector sphere.

Parameters:
  • recorded_rays (RecordedRays) – Recorded rays on detection sphere

  • save_path (str, optional) – Path to save figure

Returns:

fig – The created figure

Return type:

matplotlib.figure.Figure

lsurf.visualization.plot_time_spread_comparison(pareto_result, source_position, beam_direction, divergence_angle_rad, detector_altitude, surface=None, n_top=10, source_power=1.0, time_threshold_ns=10.0, save_path=None)[source]

Compare ray-traced time spread with single-bounce geometric estimate.

The geometric estimate assumes a single reflection (source → surface → detector). Ray-traced values may exceed this if rays take multi-bounce paths due to atmospheric refraction causing rays to return to the surface multiple times.

Parameters:
  • pareto_result (dict) – Result from compute_pareto_front()

  • source_position (tuple) – Source (x, y, z) position in meters

  • beam_direction (tuple) – Beam direction unit vector

  • divergence_angle_rad (float) – Beam half-angle divergence in radians

  • detector_altitude (float) – Detector sphere radius in meters

  • surface (Surface, optional) – Surface object for geometric estimate. If None, uses flat surface at z=0.

  • n_top (int) – Number of top intensity bins to analyze

  • source_power (float) – Input source power for normalization (W)

  • time_threshold_ns (float) – Time threshold for highlighting (ns)

  • save_path (str, optional) – Path to save figure

Returns:

fig – The created figure

Return type:

matplotlib.figure.Figure

lsurf.visualization.plot_arrival_time_distributions(recorded_rays, pareto_result, n_top=10, bins=50, time_threshold_ns=10.0, save_path=None)[source]

Plot arrival time histograms for the top N intensity bins.

Shows the actual distribution of arrival times (not just percentiles) for each of the highest energy density detector bins.

Parameters:
  • recorded_rays (RecordedRays) – Recorded rays on detection sphere

  • pareto_result (dict) – Result from compute_pareto_front()

  • n_top (int) – Number of top intensity bins to plot

  • bins (int) – Number of histogram bins

  • time_threshold_ns (float) – Time threshold to mark on plots (ns)

  • save_path (str, optional) – Path to save figure

Returns:

fig – The created figure, or None if no data

Return type:

matplotlib.figure.Figure or None

lsurf.visualization.plot_time_spread_geometry_side(ax, result, source_position, detector_position, scale=1000.0)[source]

Plot side view (X-Z plane) of time spread geometry.

Parameters:
  • ax (Axes) – Matplotlib axes to plot on.

  • result (TimeSpreadResult) – Time spread estimation result.

  • source_position (tuple) – (x, y, z) source position in meters.

  • detector_position (tuple) – (x, y, z) detector position in meters.

  • scale (float) – Scale factor for display (default 1000 for km).

lsurf.visualization.plot_beam_footprint_top(ax, result, source_position, detector_position, grazing_angle_deg=None)[source]

Plot top view (X-Y plane) of beam footprint.

Parameters:
  • ax (Axes) – Matplotlib axes to plot on.

  • result (TimeSpreadResult) – Time spread estimation result.

  • source_position (tuple) – (x, y, z) source position in meters.

  • detector_position (tuple) – (x, y, z) detector position in meters.

  • grazing_angle_deg (float, optional) – Grazing angle for display in info box.

lsurf.visualization.plot_arrival_time_histogram(ax, result, threshold_ns=10.0)[source]

Plot histogram of arrival times for edge rays.

Parameters:
  • ax (Axes) – Matplotlib axes to plot on.

  • result (TimeSpreadResult) – Time spread estimation result.

  • threshold_ns (float) – Time threshold to mark on plot.

lsurf.visualization.plot_footprint_arrival_times(ax, result)[source]

Plot footprint colored by arrival time.

Parameters:
  • ax (Axes) – Matplotlib axes to plot on.

  • result (TimeSpreadResult) – Time spread estimation result.

lsurf.visualization.plot_time_spread_vs_divergence(ax, divergences_deg, time_spreads_ns, threshold_ns=10.0, source_altitude=None, grazing_angle_deg=None, detector_altitude=None)[source]

Plot time spread as function of beam divergence.

Parameters:
  • ax (Axes) – Matplotlib axes to plot on.

  • divergences_deg (ndarray) – Array of divergence angles in degrees.

  • time_spreads_ns (ndarray) – Corresponding time spreads in nanoseconds.

  • threshold_ns (float) – Time threshold to mark on plot.

  • source_altitude (float, optional) – Parameters for title display.

  • grazing_angle_deg (float, optional) – Parameters for title display.

  • detector_altitude (float, optional) – Parameters for title display.

lsurf.visualization.create_time_spread_schematic(result, source_position, detector_position, grazing_angle_deg=None, save_path=None)[source]

Create composite figure showing time spread geometry.

Parameters:
  • result (TimeSpreadResult) – Time spread estimation result.

  • source_position (tuple) – (x, y, z) source position in meters.

  • detector_position (tuple) – (x, y, z) detector position in meters.

  • grazing_angle_deg (float, optional) – Grazing angle for display.

  • save_path (str, optional) – Path to save figure.

Returns:

fig – Matplotlib figure.

Return type:

Figure

lsurf.visualization.create_arrival_time_figure(result, threshold_ns=10.0, save_path=None)[source]

Create composite figure showing arrival time distribution.

Parameters:
  • result (TimeSpreadResult) – Time spread estimation result.

  • threshold_ns (float) – Time threshold to mark on plot.

  • save_path (str, optional) – Path to save figure.

Returns:

fig – Matplotlib figure.

Return type:

Figure

lsurf.visualization.plot_ray_trajectories(ax, trajectories, source_altitude=0.0, show_straight_lines=True, show_earth_surface=True, duct_center=0.0, duct_width=0.0, xlim=None, ylim=None, cmap='turbo', linewidth=1.5, impact_parameter_keys=False, use_colorbar=False)[source]

Plot ray trajectories on a single axis.

Parameters:
  • ax (matplotlib.axes.Axes) – Axes to plot on.

  • trajectories (dict) – Dictionary mapping initial angle (degrees) or impact parameter (meters) to trajectory array. Each trajectory is shape (N, 2) with [x, z] in meters.

  • source_altitude (float) – Source altitude in meters (for straight line reference).

  • show_straight_lines (bool) – If True, show dashed straight-line references.

  • show_earth_surface (bool) – If True, show Earth’s curved surface.

  • xlim (tuple, optional) – X-axis limits in km.

  • ylim (tuple, optional) – Y-axis limits in km.

  • cmap (str) – Colormap for ray colors.

  • linewidth (float) – Line width for trajectories.

  • impact_parameter_keys (bool) – If True, dictionary keys are impact parameters in meters (not angles).

  • use_colorbar (bool) – If True, use colorbar instead of legend (better for many rays).

Returns:

sm – ScalarMappable for colorbar if use_colorbar=True, else None.

Return type:

ScalarMappable or None

Examples

>>> fig, ax = plt.subplots()
>>> plot_ray_trajectories(ax, trajectories, source_altitude=0)
>>> plt.show()
lsurf.visualization.plot_refractive_index_profile(ax, atmosphere, max_altitude_km=100.0, n_points=500, color='b', linewidth=2.0, annotate_sea_level=True, wavelength=5.32e-07)[source]

Plot refractive index vs altitude profile.

Parameters:
  • ax (matplotlib.axes.Axes) – Axes to plot on.

  • atmosphere (MaterialField) – Atmosphere material with n_at_altitude method.

  • max_altitude_km (float) – Maximum altitude in km.

  • n_points (int) – Number of points for profile.

  • color (str) – Line color.

  • linewidth (float) – Line width.

  • annotate_sea_level (bool) – If True, annotate the sea level value.

  • wavelength (float) – Wavelength in meters for spectral atmospheres (default: 532nm).

Examples

>>> fig, ax = plt.subplots()
>>> plot_refractive_index_profile(ax, atmosphere)
>>> plt.show()
lsurf.visualization.plot_trajectory_offset(ax, trajectories, source_altitude=0.0, cmap='turbo', linewidth=1.5, xlim=None)[source]

Plot angular deviation from initial ray direction vs horizontal distance.

Shows how much the ray direction has changed from its initial launch angle as it propagates through the atmosphere. Atmospheric refraction typically bends rays downward (toward higher n), resulting in negative angular offsets.

Parameters:
  • ax (matplotlib.axes.Axes) – Axes to plot on.

  • trajectories (dict) – Dictionary mapping initial angle (degrees) to trajectory array. Each trajectory is shape (N, 2) with columns [x, z] in meters.

  • source_altitude (float) – Source altitude in meters (unused, kept for API compatibility).

  • cmap (str) – Colormap for ray colors.

  • linewidth (float) – Line width for curves.

  • xlim (tuple, optional) – X-axis limits in km.

Examples

>>> fig, ax = plt.subplots()
>>> plot_trajectory_offset(ax, trajectories, source_altitude=0)
>>> plt.show()
lsurf.visualization.plot_horizontal_ray_deviation(ax, trajectories, cmap='turbo', linewidth=1.5, xlim=None, use_colorbar=False)[source]

Plot angular deviation from initial direction for rays with varying impact parameters.

For rays that start at different altitudes (impact parameters), this shows how each ray bends relative to its initial direction as it propagates through the atmosphere. Atmospheric refraction typically bends rays downward.

Parameters:
  • ax (matplotlib.axes.Axes) – Axes to plot on.

  • trajectories (dict) – Dictionary mapping impact parameter (meters) to trajectory array. Each trajectory is shape (N, 2) with columns [x, z] in meters.

  • cmap (str) – Colormap for ray colors.

  • linewidth (float) – Line width for curves.

  • xlim (tuple, optional) – X-axis limits in km.

  • use_colorbar (bool) – If True, skip legend (colorbar added externally).

Examples

>>> fig, ax = plt.subplots()
>>> plot_horizontal_ray_deviation(ax, trajectories)
>>> plt.show()
lsurf.visualization.create_atmospheric_refraction_figure(trajectories, atmosphere, title='Atmospheric Refraction', source_altitude=0.0, xlim=None, ylim=None, show_earth_surface=True, show_straight_lines=True, duct_center=0.0, duct_width=0.0, figsize=(14, 5))[source]

Create a two-panel figure with ray trajectories and refractive index profile.

Parameters:
  • trajectories (dict) – Dictionary mapping initial angle (degrees) to trajectory array. Each trajectory is shape (N, 2) with columns [x, z] in meters.

  • atmosphere (MaterialField) – Atmosphere material with n_at_altitude method.

  • title (str) – Title for the trajectory plot.

  • source_altitude (float) – Source altitude in meters.

  • xlim (tuple, optional) – X-axis limits in km for trajectory plot.

  • ylim (tuple, optional) – Y-axis limits in km for trajectory plot.

  • show_earth_surface (bool) – If True, show Earth’s curved surface in trajectory plot.

  • show_straight_lines (bool) – If True, show dashed straight-line references.

  • figsize (tuple) – Figure size (width, height) in inches.

Returns:

fig – The created figure.

Return type:

matplotlib.figure.Figure

Examples

>>> fig = create_atmospheric_refraction_figure(
...     trajectories, atmosphere,
...     title="Exponential Atmosphere",
...     xlim=(0, 1000), ylim=(0, 100),
... )
>>> plt.savefig("refraction.png")
lsurf.visualization.create_atmospheric_refraction_figure_with_offset(trajectories, atmosphere, title='Atmospheric Refraction', source_altitude=0.0, xlim=None, ylim=None, show_earth_surface=True, show_straight_lines=True, duct_center=0.0, duct_width=0.0, figsize=(16, 10), horizontal_rays=False)[source]

Create a four-panel figure with trajectories, offset, and refractive index.

Panels: - Top-left: Ray trajectories (refracted vs straight-line) - Top-right: Refractive index profile vs altitude - Bottom: Altitude offset between refracted and straight paths

Parameters:
  • trajectories (dict) – Dictionary mapping initial angle (degrees) to trajectory array. Each trajectory is shape (N, 2) with columns [x, z] in meters.

  • atmosphere (MaterialField) – Atmosphere material with n_at_altitude method.

  • title (str) – Title for the figure.

  • source_altitude (float) – Source altitude in meters.

  • xlim (tuple, optional) – X-axis limits in km for trajectory plot.

  • ylim (tuple, optional) – Y-axis limits in km for trajectory plot.

  • show_earth_surface (bool) – If True, show Earth’s curved surface in trajectory plot.

  • show_straight_lines (bool) – If True, show dashed straight-line references.

  • figsize (tuple) – Figure size (width, height) in inches.

  • horizontal_rays (bool) – If True, use plot for horizontal rays with varying impact parameters. If False (default), use plot for rays with varying initial angles.

Returns:

fig – The created figure.

Return type:

matplotlib.figure.Figure

Examples

>>> fig = create_atmospheric_refraction_figure_with_offset(
...     trajectories, atmosphere,
...     title="Exponential Atmosphere",
...     xlim=(0, 1000), ylim=(0, 100),
... )
>>> plt.savefig("refraction_with_offset.png")
lsurf.visualization.plot_trajectory_comparison(results, figsize=None, suptitle='Atmospheric Model Comparison')[source]

Create a comparison figure with multiple trajectory plots.

Parameters:
  • results (list of dict) – List of result dictionaries, each containing: - ‘trajectories’: dict mapping angle to trajectory array - ‘title’: plot title - ‘xlim’: x-axis limits in km - ‘ylim’: y-axis limits in km

  • figsize (tuple, optional) – Figure size. Auto-determined if None.

  • suptitle (str) – Super title for the figure.

Returns:

fig – The created figure.

Return type:

matplotlib.figure.Figure

Examples

>>> results = [
...     {'trajectories': traj1, 'title': 'Model A', 'xlim': (0, 100), 'ylim': (0, 50)},
...     {'trajectories': traj2, 'title': 'Model B', 'xlim': (0, 100), 'ylim': (0, 50)},
... ]
>>> fig = plot_trajectory_comparison(results)
lsurf.visualization.save_atmospheric_figure(fig, filename, output_dir=None, dpi=150)[source]

Save an atmospheric refraction figure.

Parameters:
  • fig (matplotlib.figure.Figure) – Figure to save.

  • filename (str or Path) – Output filename.

  • output_dir (Path, optional) – Output directory. Created if doesn’t exist.

  • dpi (int) – Resolution in dots per inch.

Returns:

output_path – Full path to saved file.

Return type:

Path

lsurf.visualization.plot_homogeneous_absorption(alpha, distance, simulated_intensity, simulated_optical_depth, initial_intensity=1.0, save_path=None, show=True)[source]

Plot Beer-Lambert decay for homogeneous absorbing medium.

Parameters:
  • alpha (float) – Absorption coefficient in m^-1

  • distance (float) – Total propagation distance in m

  • simulated_intensity (float) – Simulated final intensity

  • simulated_optical_depth (float) – Simulated accumulated optical depth

  • initial_intensity (float) – Initial intensity (default 1.0)

  • save_path (str or Path, optional) – Path to save figure

  • show (bool) – Whether to display the figure

Returns:

The matplotlib figure

Return type:

plt.Figure

lsurf.visualization.plot_exponential_atmosphere_absorption(alpha_sea_level, scale_height, final_altitude, simulated_intensity, simulated_optical_depth, max_altitude=100000.0, save_path=None, show=True)[source]

Plot absorption profiles for exponential atmosphere.

Parameters:
  • alpha_sea_level (float) – Absorption coefficient at sea level in m^-1

  • scale_height (float) – Atmospheric scale height in m

  • final_altitude (float) – Final ray altitude in m

  • simulated_intensity (float) – Simulated final intensity

  • simulated_optical_depth (float) – Simulated accumulated optical depth

  • max_altitude (float) – Maximum altitude for plots in m

  • save_path (str or Path, optional) – Path to save figure

  • show (bool) – Whether to display the figure

Returns:

The matplotlib figure

Return type:

plt.Figure

lsurf.visualization.plot_spectral_atmosphere_absorption(get_extinction, get_optical_depth, earth_radius, ray_wavelengths, ray_positions, ray_optical_depths, wavelength_range=(3e-07, 1.5e-06), altitude_range=(0, 50000), test_altitudes=None, test_wavelengths=None, save_path=None, show=True)[source]

Plot spectral absorption characteristics.

Parameters:
  • get_extinction (callable) – Function(altitude, wavelength) -> extinction coefficient

  • get_optical_depth (callable) – Function(z1, z2, wavelength) -> optical depth

  • earth_radius (float) – Earth radius in m

  • ray_wavelengths (ndarray) – Array of ray wavelengths in m

  • ray_positions (ndarray) – Array of ray positions (N, 3)

  • ray_optical_depths (ndarray) – Array of simulated optical depths

  • wavelength_range (tuple) – (min, max) wavelength in m for plots

  • altitude_range (tuple) – (min, max) altitude in m for plots

  • test_altitudes (list, optional) – Altitudes for extinction vs wavelength plot

  • test_wavelengths (list, optional) – Wavelengths for optical depth vs altitude plot

  • save_path (str or Path, optional) – Path to save figure

  • show (bool) – Whether to display the figure

Returns:

The matplotlib figure

Return type:

plt.Figure

lsurf.visualization.plot_geometry_analysis(rings, output_path=None, figsize=(16, 14), dpi=150)[source]

Create 4-panel geometry analysis figure.

Panels: (a) Full geometry schematic (Earth + detector sphere + sample rings) (b) Zoomed view showing no-shadowing geometry with sight lines (c) Distance vs elevation curve (d) Angular width and distance vs ring index

Parameters:
  • rings (ConstantSizeDetectorRings) – Detector ring configuration

  • output_path (str or Path, optional) – If provided, save figure to this path

  • figsize (tuple) – Figure size in inches

  • dpi (int) – Resolution for saved figure

Returns:

Matplotlib figure object

Return type:

Figure

lsurf.visualization.plot_ring_side_view(rings, output_path=None, figsize=(16, 8), dpi=150)[source]

Create side view cross-section of detector rings.

Shows all rings with constant physical size and normals pointing toward origin.

Parameters:
  • rings (ConstantSizeDetectorRings) – Detector ring configuration

  • output_path (str or Path, optional) – If provided, save figure to this path

  • figsize (tuple) – Figure size in inches

  • dpi (int) – Resolution for saved figure

Returns:

Matplotlib figure object

Return type:

Figure

lsurf.visualization.plot_ring_overview(rings, ring_intensities, detected_positions=None, output_path=None, figsize=(10, 10), dpi=150)[source]

Create top-down ring overview with intensity coloring.

Parameters:
  • rings (ConstantSizeDetectorRings) – Detector ring configuration

  • ring_intensities (ndarray) – Total intensity per ring (shape: n_rings)

  • detected_positions (ndarray, optional) – Ray detection positions (N, 3) for scatter overlay

  • output_path (str or Path, optional) – If provided, save figure to this path

  • figsize (tuple) – Figure size in inches

  • dpi (int) – Resolution for saved figure

Returns:

Matplotlib figure object

Return type:

Figure

lsurf.visualization.plot_ring_azimuth_heatmap(rings, intensity_map, ray_count_map, az_min=-10.0, az_max=10.0, output_path=None, figsize=(14, 6), dpi=150)[source]

Create ring-azimuth heatmaps for intensity and ray count.

Parameters:
  • rings (ConstantSizeDetectorRings) – Detector ring configuration

  • intensity_map (ndarray) – Intensity per (ring, azimuth_bin), shape (n_rings, n_az_bins)

  • ray_count_map (ndarray) – Ray count per (ring, azimuth_bin), shape (n_rings, n_az_bins)

  • az_min (float) – Azimuth range in degrees

  • az_max (float) – Azimuth range in degrees

  • output_path (str or Path, optional) – If provided, save figure to this path

  • figsize (tuple) – Figure size in inches

  • dpi (int) – Resolution for saved figure

Returns:

Matplotlib figure object

Return type:

Figure

lsurf.visualization.plot_timing_heatmap(rings, first_arrival_map, time_spread_map, global_first_ns, az_min=-10.0, az_max=10.0, output_path=None, figsize=(14, 6), dpi=150)[source]

Create timing heatmaps (first arrival and time spread).

Parameters:
  • rings (ConstantSizeDetectorRings) – Detector ring configuration

  • first_arrival_map (ndarray) – First arrival time per bin in ns, shape (n_rings, n_az_bins)

  • time_spread_map (ndarray) – Time spread (10-90%) per bin in ns, shape (n_rings, n_az_bins)

  • global_first_ns (float) – Global first arrival time in ns (for relative timing)

  • az_min (float) – Azimuth range in degrees

  • az_max (float) – Azimuth range in degrees

  • output_path (str or Path, optional) – If provided, save figure to this path

  • figsize (tuple) – Figure size in inches

  • dpi (int) – Resolution for saved figure

Returns:

Matplotlib figure object

Return type:

Figure

lsurf.visualization.plot_per_ring_timing_distributions(rings, ring_data, az_limit=10.0, output_path=None, figsize_per_col=4.0, figsize_per_row=3.5, dpi=150)[source]

Create per-ring timing distribution histograms.

Parameters:
  • rings (ConstantSizeDetectorRings) – Detector ring configuration

  • ring_data (list of dict) – List of dicts with keys: - ring_idx: int - az_center: float (azimuth center in degrees) - times_rel_ns: ndarray (times relative to bin first arrival, ns) - intensities: ndarray (ray intensities) - dist_km: float

  • az_limit (float) – Azimuth limit for title

  • output_path (str or Path, optional) – If provided, save figure to this path

  • figsize_per_col (float) – Figure size multipliers

  • figsize_per_row (float) – Figure size multipliers

  • dpi (int) – Resolution for saved figure

Returns:

Matplotlib figure object, or None if no data

Return type:

Figure or None

lsurf.visualization.plot_spread_analysis(rings, ring_stats, output_path=None, figsize=(14, 5), dpi=150)[source]

Create per-ring spread analysis (azimuthal and timing).

Parameters:
  • rings (ConstantSizeDetectorRings) – Detector ring configuration

  • ring_stats (list of dict) – List of dicts with keys: - ring_idx: int - n_rays: int - az_std: float (azimuth std in degrees) - time_spread_ns: float - dist_km: float

  • output_path (str or Path, optional) – If provided, save figure to this path

  • figsize (tuple) – Figure size in inches

  • dpi (int) – Resolution for saved figure

Returns:

Matplotlib figure object, or None if no data

Return type:

Figure or None

lsurf.visualization.plot_polar_irradiance(rings, irradiance_map, n_azimuth_bins, output_path=None, figsize=(10, 10), dpi=150)[source]

Create polar heatmap of irradiance.

Parameters:
  • rings (ConstantSizeDetectorRings) – Detector ring configuration

  • irradiance_map (ndarray) – Irradiance per (ring, azimuth_bin), shape (n_rings, n_azimuth_bins)

  • n_azimuth_bins (int) – Number of azimuth bins

  • output_path (str or Path, optional) – If provided, save figure to this path

  • figsize (tuple) – Figure size in inches

  • dpi (int) – Resolution for saved figure

Returns:

Matplotlib figure object

Return type:

Figure

lsurf.visualization.plot_ring_time_spread_comparison(rings, ring_stats, source_position, beam_direction, divergence_angle_rad, surface=None, output_path=None, figsize=(14, 5), dpi=150)

Compare ray-traced time spread with geometric estimate.

The geometric estimate computes the path difference for rays at the edge of the divergence cone reflecting through the beam footprint on the surface.

Parameters:
  • rings (ConstantSizeDetectorRings) – Detector ring configuration

  • ring_stats (list of dict) – Per-ring statistics with time_spread_ns and dist_km

  • source_position (tuple) – Source (x, y, z) position in meters

  • beam_direction (tuple) – Beam direction unit vector

  • divergence_angle_rad (float) – Beam half-angle divergence in radians

  • surface (Surface, optional) – Ocean surface for geometric estimate. If None, uses flat surface at z=0.

  • output_path (str or Path, optional) – If provided, save figure to this path

  • figsize (tuple) – Figure size in inches

  • dpi (int) – Resolution for saved figure

Returns:

Matplotlib figure object, or None if no data

Return type:

Figure or None

lsurf.visualization.plot_constant_size_timing_analysis(rings, bin_stats, output_path=None, figsize=(16, 10), dpi=150)[source]

Plot timing analysis for constant physical size bins.

Creates a 2x2 figure: - (a) Time spread vs distance (each point is one bin) - (b) First arrival vs distance - (c) Time spread heatmap (ring vs azimuth, scaled to show structure) - (d) Number of azimuth bins per ring (shows scaling with distance)

Parameters:
  • rings (ConstantSizeDetectorRings) – Detector ring configuration

  • bin_stats (list of dict) – Results from compute_constant_size_bin_stats

  • output_path (str or Path, optional) – If provided, save figure to this path

  • figsize (tuple) – Figure size in inches

  • dpi (int) – Resolution for saved figure

Returns:

Matplotlib figure object, or None if no data

Return type:

Figure or None

lsurf.visualization.plot_constant_size_timing_distributions(rings, bin_stats, ray_positions, ray_times, ray_intensities, n_top=12, output_path=None, figsize_per_col=4.0, figsize_per_row=3.5, dpi=150)[source]

Plot timing distributions for top bins by ray count.

Parameters:
  • rings (ConstantSizeDetectorRings) – Detector ring configuration

  • bin_stats (list of dict) – Results from compute_constant_size_bin_stats

  • ray_positions (ndarray) – Raw ray data for histogram computation

  • ray_times (ndarray) – Raw ray data for histogram computation

  • ray_intensities (ndarray) – Raw ray data for histogram computation

  • n_top (int) – Number of top bins to plot

  • output_path (str or Path, optional) – If provided, save figure to this path

  • figsize_per_col (float) – Figure size multipliers

  • figsize_per_row (float) – Figure size multipliers

  • dpi (int) – Resolution for saved figure

Returns:

Matplotlib figure object, or None if no data

Return type:

Figure or None

lsurf.visualization.compute_ring_azimuth_maps(ray_positions, ray_times, ray_intensities, rings, az_min=-10.0, az_max=10.0, n_az_bins=40)[source]

Compute 2D maps of intensity, ray count, and timing by ring and azimuth.

Parameters:
  • ray_positions (ndarray) – Ray detection positions (N, 3)

  • ray_times (ndarray) – Ray detection times (N,)

  • ray_intensities (ndarray) – Ray intensities (N,)

  • rings (ConstantSizeDetectorRings) – Detector ring configuration

  • az_min (float) – Azimuth range in degrees

  • az_max (float) – Azimuth range in degrees

  • n_az_bins (int) – Number of azimuth bins

Returns:

Dictionary with keys: - intensity_map: (n_rings, n_az_bins) total intensity - ray_count_map: (n_rings, n_az_bins) ray count - first_arrival_map: (n_rings, n_az_bins) first arrival time in ns - time_spread_map: (n_rings, n_az_bins) time spread (10-90%) in ns - ray_ring_indices: (N,) ring index per ray - ray_azimuth_deg: (N,) azimuth per ray in degrees

Return type:

dict

lsurf.visualization.compute_ring_spread_stats(ray_positions, ray_times, ray_intensities, rings, az_limit=10.0, n_az_bins=40)[source]

Compute per-ring spread statistics (azimuthal and timing).

Parameters:
  • ray_positions (ndarray) – Ray detection positions (N, 3)

  • ray_times (ndarray) – Ray detection times (N,)

  • ray_intensities (ndarray) – Ray intensities (N,)

  • rings (ConstantSizeDetectorRings) – Detector ring configuration

  • az_limit (float) – Azimuth limit in degrees (filter to +/- this range)

  • n_az_bins (int) – Number of azimuth bins within the range

Returns:

Per-ring statistics with keys: ring_idx, n_rays, az_std, time_spread_ns, dist_km, total_intensity

Return type:

list of dict

lsurf.visualization.compute_constant_size_bin_stats(ray_positions, ray_times, ray_intensities, rings, az_bin_size_m=10000.0, az_range_deg=10.0, min_rays_per_bin=3)[source]

Compute timing statistics for constant physical size bins.

Each bin has approximately the same physical size: - Radial: detector_radial_size (from rings configuration) - Azimuthal: az_bin_size_m (varies in angular size with distance)

Parameters:
  • ray_positions (ndarray) – Ray detection positions (N, 3)

  • ray_times (ndarray) – Ray detection times (N,)

  • ray_intensities (ndarray) – Ray intensities (N,)

  • rings (ConstantSizeDetectorRings) – Detector ring configuration

  • az_bin_size_m (float) – Physical azimuthal bin size in meters (default: 10 km)

  • az_range_deg (float) – Azimuth range in degrees (±this value)

  • min_rays_per_bin (int) – Minimum rays required to compute statistics

Returns:

Per-bin statistics with keys: - ring_idx, az_bin_idx, n_az_bins - az_center_deg, elev_center_deg - distance_km - n_rays, total_intensity - first_arrival_ns (relative to global first) - time_spread_ns (10-90 percentile) - bin_area_m2

Return type:

list of dict

Submodules

lsurf.visualization.raytracing_plots

Ray Tracing Visualization - Individual Axis Functions

lsurf.visualization.detector_plots

Detector Visualization - Individual Axis Functions

lsurf.visualization.common

Visualization Common Utilities