Modules
Planet Ruler API modules organized by functionality.
planet_ruler
Core Modules
Manual Limb Annotation Tool for Planet Ruler |
|
Automatic extraction of camera parameters from smartphone images. |
|
Validation functions for planet_ruler. |
|
Command-line interface for planet_ruler |
|
Geometry Module
Mathematical functions for planetary geometry calculations.
- planet_ruler.geometry.horizon_distance(r, h)[source]
Estimate the distance to the horizon (limb) given a height and radius.
- planet_ruler.geometry.limb_camera_angle(r, h)[source]
The angle the camera must tilt in theta_x or theta_y to center the limb. Complement of theta (angle of limb down from the x-y plane).
- planet_ruler.geometry.focal_length(w, fov)[source]
The size of the CCD (inferred) based on focal length and field of view.
- planet_ruler.geometry.detector_size(f, fov)[source]
The size of the CCD (inferred) based on focal length and field of view.
- planet_ruler.geometry.field_of_view(f, w)[source]
The size of the CCD (inferred) based on focal length and field of view.
- planet_ruler.geometry.intrinsic_transform(camera_coords, f=1, px=1, py=1, x0=0, y0=0)[source]
Transform from camera coordinates into image coordinates.
- Parameters:
camera_coords (np.ndarray) – Coordinates of the limb in camera space. Array has Nx4 shape where N is the number of x-axis pixels in the image.
f (float) – Focal length of the camera (m).
px (float) – The scale of x pixels.
py (float) – The scale of y pixels.
x0 (float) – The x-axis principle point (should be center of image in pixel coordinates).
y0 (float) – The y-axis principle point. (should be center of image in pixel coordinates).
- Returns:
Coordinates in image space.
- Return type:
pixel_coords (np.ndarray)
- planet_ruler.geometry.extrinsic_transform(world_coords, theta_x=0, theta_y=0, theta_z=0, origin_x=0, origin_y=0, origin_z=0)[source]
Transform from world coordinates into camera coordinates. Note that for a limb calculation we will define origin_x/y/z as the camera position – these should all be set to zero.
- Parameters:
world_coords (np.ndarray) – Coordinates of the limb in the world. Array has Nx4 shape where N is the number of x-axis pixels in the image.
theta_x (float) – Rotation around the x (horizontal lateral) axis, AKA pitch — tilts the camera up/down. (radians)
theta_y (float) – Rotation around the y (toward-limb) axis, AKA roll. When theta_z=0, acts as a pure phase shift in φ with no effect on the projected arc shape. When theta_z≠0, the z-rotation breaks that symmetry and theta_y has a genuine effect on the arc. (radians)
theta_z (float) – Rotation around the z (vertical) axis, AKA yaw. Use theta_z=π for the physically correct ∪-shaped horizon arc (near limb visible, more planet at image center). (radians)
origin_x (float) – Horizontal offset from the object in question to the camera (m).
origin_y (float) – Distance from the object in question to the camera (m).
origin_z (float) – Height difference from the object in question to the camera (m).
- Returns:
Coordinates in camera space.
- Return type:
camera_coords (np.ndarray)
- planet_ruler.geometry.limb_arc_sample(r, n_pix_x, n_pix_y, h=1, f=None, fov=None, w=None, x0=0, y0=0, theta_x=0, theta_y=0, theta_z=0, origin_x=0, origin_y=0, origin_z=0, return_full=False, num_sample=5000)[source]
Calculate the limb orientation in an image given the physical parameters of the system.
- Parameters:
n_pix_x (int) – Width of image (pixels).
n_pix_y (int) – Height of image (pixels).
r (float) – Radius of the body in question.
h (float) – Height above surface (units should match radius).
f (float) – Focal length of the camera (m).
fov (float) – Field of view, assuming square (degrees).
w (float) – detector size (float): Width of CCD (m).
x0 (float) – The x-axis principle point.
y0 (float) – The y-axis principle point.
theta_x (float) – Rotation around the x (horizontal lateral) axis, AKA pitch — tilts the camera up/down. (radians)
theta_y (float) – Rotation around the y (toward-limb) axis, AKA roll. When theta_z=0, acts as a pure phase shift in φ with no effect on the projected arc shape. When theta_z≠0, the z-rotation breaks that symmetry and theta_y has a genuine effect on the arc. (radians)
theta_z (float) – Rotation around the z (vertical) axis, AKA yaw. Use theta_z=π for the physically correct ∪-shaped horizon arc (near limb visible, more planet at image center). (radians)
origin_x (float) – Horizontal offset from the object in question to the camera (m).
origin_y (float) – Distance from the object in question to the camera (m).
origin_z (float) – Height difference from the object in question to the camera (m).
return_full (bool) – Return both the x and y coordinates of the limb in camera space. Note these will not be interpolated back on to the pixel grid.
num_sample (
int) – The number of points sampled from the simulated limb – will be interpolated onto pixel grid. [default 1000]
- Return type:
- planet_ruler.geometry.get_rotation_matrix(theta_x, theta_y, theta_z)[source]
Compute combined rotation matrix from Euler angles. Extracted from extrinsic_transform for reuse.
- Returns:
3x3 rotation matrix
- Return type:
R
- planet_ruler.geometry.limb_arc(r, n_pix_x, n_pix_y, h=1, f=None, fov=None, w=None, x0=0, y0=0, theta_x=0, theta_y=0, theta_z=0, origin_x=0, origin_y=0, origin_z=0, return_full=False, x_coords=None, **kwargs)[source]
Calculate limb position analytically at each pixel x-coordinate.
No sampling or interpolation - directly solves for phi at each column. This eliminates edge artifacts and is sometimes faster than sampling methods.
Mathematical approach: 1. Limb is parameterized by angle phi around circle 2. For each x_pixel, solve: x_pixel = f(phi) for phi 3. This reduces to: a·cos(phi) + b·sin(phi) = c 4. Standard analytical solution exists!
- Parameters:
n_pix_x (int) – Width of image (pixels).
n_pix_y (int) – Height of image (pixels).
r (float) – Radius of the body in question.
h (float) – Height above surface (units should match radius).
f (float) – Focal length of the camera (m).
fov (float) – Field of view, assuming square (degrees).
w (float) – detector size (float): Width of CCD (m).
x0 (float) – The x-axis principle point.
y0 (float) – The y-axis principle point.
theta_x (float) – Rotation around the x (horizontal lateral) axis, AKA pitch — tilts the camera up/down. (radians)
theta_y (float) – Rotation around the y (toward-limb) axis, AKA roll. When theta_z=0, acts as a pure phase shift in φ with no effect on the projected arc shape. When theta_z≠0, the z-rotation breaks that symmetry and theta_y has a genuine effect on the arc. (radians)
theta_z (float) – Rotation around the z (vertical) axis, AKA yaw. Use theta_z=π for the physically correct ∪-shaped horizon arc (near limb visible, more planet at image center). (radians)
origin_x (float) – Horizontal offset from the object in question to the camera (m).
origin_y (float) – Distance from the object in question to the camera (m).
origin_z (float) – Height difference from the object in question to the camera (m).
return_full (bool) – Return both the x and y coordinates of the limb in camera space. Note these will not be interpolated back on to the pixel grid.
x_coords (
Optional[ndarray]) – Optional array of x-coordinates to compute (default: all pixels). For sparse computation (e.g., manual annotation), pass only the x-coordinates where you have data. Dramatically speeds up fitting when only a few points are annotated.
- Returns:
- Array of y-coordinates for each x-pixel column
Length matches len(x_coords) if provided, else n_pix_x
- Return type:
y_pixel
- planet_ruler.geometry.limb_arc_sagitta(u, theta_x, f_px, r, h)[source]
Exact projected sagitta of the planetary limb arc at pixel offset u.
- Derivation (perspective geometry, theta_y=0, theta_z=pi for ∪-arc):
The camera is at altitude h above a sphere of radius r. In camera coordinates the visible horizon is the set of tangent points satisfying X·r̂ = r²/(r+h). After rotation R_x(theta_x)·R_z(pi) the horizon circle projects as a conic; solving the x-pixel equation for the azimuth angle phi and back-substituting for the y-pixel yields the closed form below.
The formula is verified to machine precision against limb_arc() for theta_x ∈ {-alpha, 0, alpha, 2*alpha} and is invariant to theta_y (verified to 2.7e-7 px residuals for theta_y ∈ {0, 0.01, 0.05, 0.1}).
- At theta_x=0 this reduces exactly to
s(u) = kappa * (sqrt(f_px**2 + u**2) - f_px)
where kappa = sqrt(h*(2r+h)) / r = 1/K. Consequently, the OLS fit s = s0 - c*A(u) (A = sqrt(f²+u²) - f) recovers K = 1/|c| with zero residual — the fundamental reason the hyperbola model is exact at theta_x=0.
- Parameters:
u (
ndarray) – Horizontal pixel offsets from the image centre (u = x - x0).theta_x (
float) – Camera tilt in radians (0 = horizontal, positive = looking down toward the horizon).f_px (
float) – Focal length in pixels (f_mm / sensor_width_mm * n_pix_x).r (
float) – Planetary radius [m].h (
float) – Camera altitude above surface [m].
- Return type:
- Returns:
Sagitta at each u [pixels]. Positive values are below the arc apex for ∪-arcs (theta_z=pi).
- Exact formulas:
kappa = sqrt(h * (2*r + h)) / r g(u) = sqrt(f_px**2 + u**2 * (cos(theta_x)**2 - kappa**2*sin(theta_x)**2)) s(u) = (f_px**2 + u**2*cos(theta_x)*(cos(theta_x) + kappa*sin(theta_x)) - f_px*g(u))
/ ((f_px*sin(theta_x) + cos(theta_x)*g(u)/kappa) * (kappa*sin(theta_x) + cos(theta_x)))
Image Processing Module
Computer vision and image analysis functions.
- planet_ruler.image.load_image(filepath)[source]
Load a 3 or 4-channel image from filepath into an array.
- planet_ruler.image.directional_gradient_blur(image, sigma_base=2.0, streak_length=20, decay_rate=0.2, normalize_gradients=True)[source]
Blur along gradient directions to create smooth ‘streaks’ toward edges.
For each pixel, follow its gradient direction outward, averaging pixels along that ray with exponential decay. This: - Smooths noisy/weak gradients (striations with inconsistent directions) - Strengthens coherent gradients (limb where all gradients align) - Creates smooth ‘valleys’ guiding optimizer toward strong edges
- Parameters:
image (np.ndarray) – Input image (H x W or H x W x 3)
sigma_base (float) – Initial gradient smoothing for direction estimation
streak_length (int) – How far to follow gradient direction (pixels)
decay_rate (float) – Exponential decay rate (higher = faster decay)
normalize_gradients (bool) –
True: Use unit vectors (direction only) - RECOMMENDED All pixels sample same distance regardless of gradient strength. Consistent, predictable behavior.
False: Use full gradient magnitude as direction Strong gradients sample further. Can create artifacts.
- Returns:
Blurred gradient magnitude field grad_angle (np.ndarray): Gradient angle field
- Return type:
blurred_grad_mag (np.ndarray)
- Note: This is UNI-directional (samples in one direction only).
Use bidirectional_gradient_blur() to preserve peak locations.
- planet_ruler.image.bilinear_interpolate(array, y, x)[source]
Bilinear interpolation for 2D array at non-integer coordinates.
- Parameters:
array – 2D array to sample from
y – Arrays of y and x coordinates (can be non-integer)
x – Arrays of y and x coordinates (can be non-integer)
- Returns:
Interpolated values at (y, x) positions
- planet_ruler.image.bidirectional_gradient_blur(image, sigma_base=2.0, streak_length=20, decay_rate=0.2, normalize_gradients=True)[source]
Blur in BOTH directions along gradient (forward and backward).
This creates symmetric streaks on both sides of edges, preserving the location of gradient maxima while smoothing the field.
- Parameters:
image – Input image
sigma_base – Initial smoothing for gradient estimation
streak_length – How far to sample in each direction
decay_rate – Exponential decay (higher = faster falloff)
normalize_gradients – Use unit vectors (direction only) vs full magnitude
- Returns:
Smoothed gradient magnitude field grad_angle: Original gradient angle field
- Return type:
blurred_mag
- planet_ruler.image.gradient_break(im_arr, log=False, y_min=0, y_max=-1, window_length=None, polyorder=1, deriv=0, delta=1)[source]
Scan each vertical line of an image for the maximum change in brightness gradient – usually corresponds to a horizon.
- Parameters:
im_arr (np.ndarray) – Image array.
log (bool) – Use the log(gradient). Sometimes good for smoothing.
y_min (int) – Minimum y-position to consider.
y_max (int) – Maximum y-position to consider.
window_length (int) – Width of window to apply smoothing for each vertical. Larger means less noise but less sensitivity.
polyorder (int) – Polynomial order for smoothing.
deriv (int) – Derivative level for smoothing.
delta (int) – Delta for smoothing.
- Returns:
image array (np.ndarray)
- class planet_ruler.image.MaskSegmenter(image, method='sam', downsample_factor=1, interactive=True, **backend_kwargs)[source]
Bases:
objectMethod-agnostic mask-based segmentation.
Supports pluggable backends (SAM, custom algorithms, etc.) with optional downsampling and interactive classification.
- class planet_ruler.image.SegmentationBackend[source]
Bases:
objectBase class for segmentation backends.
- class planet_ruler.image.SAMBackend(model_size='vit_b')[source]
Bases:
SegmentationBackendSegment Anything Model backend.
- class planet_ruler.image.CustomBackend(segment_fn)[source]
Bases:
SegmentationBackendCustom user-provided segmentation backend.
- planet_ruler.image.smooth_limb(y, method='rolling-median', window_length=50, polyorder=1, deriv=0, delta=1)[source]
Smooth the limb position values.
- Parameters:
y (np.ndarray) – Y-locations of the string for each column.
method (str) – Smoothing method. Must be one of [‘bin-interpolate’, ‘savgol’, ‘rolling-mean’, ‘rolling-median’].
window_length (int) – The length of the filter window (i.e., the number of coefficients). If mode is ‘interp’, window_length must be less than or equal to the size of x.
polyorder (float) – The order of the polynomial used to fit the samples. polyorder must be less than window_length.
deriv (int) – The order of the derivative to compute. This must be a non-negative integer. The default is 0, which means to filter the data without differentiating.
delta (int) – The spacing of the samples to which the filter will be applied. This is only used if deriv > 0. Default is 1.0.
- Returns:
Y-locations of the smoothed string for each column.
- Return type:
position (np.ndarray)
- planet_ruler.image.fill_nans(limb)[source]
Fill NaNs for the limb position values.
- Parameters:
limb (np.ndarray) – Y-locations of the limb on the image.
- Returns:
Y-locations of the limb on the image.
- Return type:
limb (np.ndarray)
- planet_ruler.image.gradient_field(image, kernel_smoothing=5.0, directional_smoothing=50, directional_decay_rate=0.15)[source]
Pre-compute gradient field AND its derivatives for fast sub-pixel interpolation. Uses directional blur for enhanced edge detection.
- Parameters:
image (
ndarray) – Input imagekernel_smoothing (
float) – Sigma for initial gradient direction estimationdirectional_smoothing (
int) – Distance to sample in each direction (±pixels). Set to 0 to bypass directional smoothing entirely.directional_decay_rate (
float) – Exponential decay rate for directional blur
- Returns:
- Dictionary containing gradient field components:
grad_mag: Gradient magnitude array
grad_angle: Gradient angle array
grad_sin: Sin of gradient angle (for interpolation)
grad_cos: Cos of gradient angle (for interpolation)
grad_mag_dy, grad_mag_dx: Derivatives of gradient magnitude
grad_sin_dy, grad_sin_dx: Derivatives of sine component
grad_cos_dy, grad_cos_dx: Derivatives of cosine component
image_height, image_width: Dimensions
- Return type:
Observation Module
High-level observation classes and workflows.
- class planet_ruler.observation.PlanetObservation(image_filepath)[source]
Bases:
objectBase class for planet observations.
- Parameters:
image_filepath (str) – Path to image file.
- crop_image(update_parameters=True)[source]
Interactively crop the observation image with automatic parameter scaling.
Opens a GUI tool allowing the user to select a rectangular region to crop. If the observation has camera parameters (e.g., LimbObservation), they are automatically scaled to match the cropped region.
Note: The principal point may end up outside the cropped region bounds (negative coordinates). This is geometrically valid - it means the camera’s optical axis was pointing at a location not visible in the cropped image.
- Parameters:
update_parameters (
bool) – If True and parameters exist, scale them for the crop- Returns:
For method chaining
- Return type:
self
Example
>>> obs = LimbObservation("airplane.jpg", "config.yaml") >>> obs.crop_image() # Opens interactive crop tool >>> obs.detect_limb() >>> obs.fit_arc()
Notes
Works for any PlanetObservation subclass
For LimbObservation: automatically scales detector_size, principal_point, etc.
Principal point can be outside cropped bounds (mathematically valid)
- class planet_ruler.observation.LimbObservation(image_filepath, fit_config, limb_detection='manual', minimizer='differential-evolution')[source]
Bases:
PlanetObservationObservation of a planet’s limb (horizon).
- Parameters:
- __init__(image_filepath, fit_config, limb_detection='manual', minimizer='differential-evolution')[source]
- analyze(detect_limb_kwargs=None, fit_method='arc', fit_method_kwargs=None, fit_stages=None)[source]
Perform complete limb analysis: detection + fitting in one call.
- Parameters:
detect_limb_kwargs (
Optional[dict]) – Optional kwargs for detect_limb().fit_method (
str) – Single-stage method – “arc” (default), “gradient”, or “sagitta”. Ignored when fit_stages is provided.fit_method_kwargs (
Optional[dict]) – Optional kwargs for the chosen fit method.fit_stages (
Optional[List[dict]]) – If provided, run fit_limb(fit_stages) (multi-stage orchestrator).
- Returns:
For method chaining.
- Return type:
self
- property radius_km: float
Get the fitted planetary radius in kilometers.
- Returns:
Planetary radius in km, or 0 if not fitted
- Return type:
- property altitude_km: float
Get the observer altitude in kilometers.
- Returns:
Observer altitude in km, or 0 if not fitted
- Return type:
- property focal_length_mm: float
Get the camera focal length in millimeters.
- Returns:
Focal length in mm, or 0 if not fitted
- Return type:
- property radius_uncertainty: float
Get parameter uncertainty for radius.
Automatically selects best method based on minimizer: - differential_evolution: Uses population spread (fast, exact) - dual_annealing/basinhopping: Uses Hessian approximation (fast, approximate)
- Returns:
Radius uncertainty in km (1-sigma), or 0 if not available
- Return type:
- parameter_uncertainty(parameter, method='auto', scale_factor=1.0, confidence_level=0.68, **kwargs)[source]
Get uncertainty for any fitted parameter.
- Parameters:
parameter (
str) – Parameter name (e.g., ‘r’, ‘h’, ‘f’, ‘theta_x’)method (
Literal['auto','hessian','profile','bootstrap']) – Uncertainty method - ‘auto’: Choose based on minimizer (recommended) - ‘hessian’: Fast Hessian approximation - ‘profile’: Slow but accurate profile likelihood - ‘bootstrap’: Multiple fits (very slow)scale_factor (
float) – Scale result (e.g., 1000.0 for m→km)confidence_level (
float) – Confidence level (0.68=1σ, 0.95=2σ)**kwargs – Additional arguments passed to uncertainty calculator
- Return type:
- Returns:
dict with ‘uncertainty’, ‘method’, ‘confidence_level’, ‘additional_info’
Examples
# Radius uncertainty in km (1-sigma) obs.parameter_uncertainty(‘r’, scale_factor=1000.0)
# Altitude uncertainty in km (2-sigma / 95% CI) obs.parameter_uncertainty(‘h’, scale_factor=1000.0, confidence_level=0.95)
# Focal length uncertainty in mm (using profile likelihood) obs.parameter_uncertainty(‘f’, scale_factor=1000.0, method=’profile’)
- reset_params()[source]
Restore init_parameter_values to the original loaded values (cold start).
- Return type:
- plot_3d(**kwargs)[source]
Create 3D visualization of the planetary geometry.
- Parameters:
**kwargs – Arguments passed to plot_3d_solution
- Return type:
- load_fit_config(fit_config)[source]
Load the fit configuration from file, setting all parameters to their initial values. Missing values are filled with defaults.
- register_limb(limb)[source]
Register a detected limb.
- Parameters:
limb (np.ndarray) – Limb vector (y pixel coordinates).
- Return type:
- detect_limb(detection_method=None, log=False, y_min=0, y_max=-1, window_length=501, polyorder=1, deriv=0, delta=1, segmentation_method='sam', downsample_factor=1, interactive=True, **segmentation_kwargs)[source]
Use the instance-defined method to find the limb in our observation. Kwargs are passed to the method.
- Parameters:
detection_method (literal) –
- Detection method. Must be one of
manual
gradient-break
gradient-field
segmentation
Default (None) uses the class attribute self.limb_detection.
log (bool) – Use the log(gradient). Sometimes good for smoothing.
y_min (int) – Minimum y-position to consider.
y_max (int) – Maximum y-position to consider.
window_length (int) – Width of window to apply smoothing for each vertical. Larger means less noise but less sensitivity.
polyorder (int) – Polynomial order for smoothing.
deriv (int) – Derivative level for smoothing.
delta (int) – Delta for smoothing.
segmentation_method (str) – Model used for segmentation. Must be one of [‘sam’].
downsample_factor (int) – Downsampling used for segmentation.
interactive (bool) – Prompts user to verify segmentation via annotation tool.
segmentation_kwargs (dict) – Kwargs passed to segmentation engine.
- Return type:
- smooth_limb(fill_nan=True, **kwargs)[source]
Apply the smooth_limb function to current observation.
- fit_sagitta(n_sigma=2.0, bias_correct=False, uncertainty='both')[source]
Estimate planetary radius using the sagitta (arc-height) method.
Runs SagittaFitter: a 2-D L-BFGS-B optimizer over (kappa, theta_x) using the exact projected-sagitta formula. Updates self.init_parameter_values and self.parameter_limits so that a subsequent fit_arc/fit_gradient stage warm-starts from the result automatically.
- Parameters:
n_sigma (
float) – Radius bound width in sigma units.bias_correct (
bool) – If True and y0 is provided, correct for camera tilt bias using the apex y-offset to estimate theta_x, then refine kappa via 1-D minimization.uncertainty (
str) – Bound-width method — “ols” (cheap, single pass), “jackknife” (leave-one-out), or “both” (quadrature sum, default).
- Returns:
For method chaining.
- Return type:
self
- fit_arc(loss_function='l2', minimizer=None, minimizer_preset='balanced', minimizer_kwargs=None, max_iter=15000, seed=0, verbose=False, n_jobs=1, _dashboard=None)[source]
Fit the planet limb arc using a pixel-space cost function.
Requires a detected limb (call detect_limb() first, or register_limb()). Reads self.init_parameter_values as the initial guess and writes fitted free-parameter values back so a chained call warm-starts automatically.
- Parameters:
loss_function (
Literal['l2','l1','log-l1']) – “l2” (default), “l1”, or “log-l1”.minimizer (
Optional[Literal['differential-evolution','dual-annealing','basinhopping','scipy-minimize','shgo']]) – Minimizer name. Defaults to self.minimizer.minimizer_preset (
Literal['fast','balanced','robust','super_robust','scipy-default']) – Preset config.minimizer_kwargs (
Optional[Dict]) – Override specific minimizer kwargs.max_iter (
int) – Maximum iterations.seed (
int) – Random seed.verbose (
bool) – Print progress.n_jobs (
int) – Parallel workers. Effective only for differential-evolution and shgo; emits a UserWarning for other minimizers._dashboard – Internal — FitDashboard instance passed by fit_limb.
- Returns:
For method chaining.
- Return type:
self
- fit_gradient(resolution_stages=None, minimizer=None, minimizer_preset='balanced', minimizer_kwargs=None, image_smoothing=None, kernel_smoothing=5.0, directional_smoothing=50, directional_decay_rate=0.15, prefer_direction=None, max_iter=15000, max_iter_per_stage=None, seed=0, verbose=False, n_jobs=1, _dashboard=None)[source]
Fit using gradient field alignment, optionally with coarse-to-fine stages.
Does not require a pre-detected limb; operates directly on the image. Multi-resolution stages warm-start from the previous stage automatically.
- Parameters:
resolution_stages (
Union[List[int],Literal['auto'],None]) – Downsampling factors, e.g. [4, 2, 1] (coarse→fine). None → single full-resolution stage. “auto” → inferred from image size.minimizer (
Optional[Literal['differential-evolution','dual-annealing','basinhopping','scipy-minimize','shgo']]) – Minimizer name. Defaults to self.minimizer.minimizer_preset (
Literal['fast','balanced','robust','super_robust','scipy-default']) – Preset config.minimizer_kwargs (
Optional[Dict]) – Override specific minimizer kwargs.image_smoothing (
Optional[float]) – Gaussian blur sigma applied before optimisation (removes high-frequency artifacts; original image restored after).kernel_smoothing (
float) – Gradient field kernel size.directional_smoothing (
int) – Directional sampling distance along gradients.directional_decay_rate (
float) – Exponential decay for directional samples.prefer_direction (
Optional[Literal['up','down']]) – “up” (dark sky / bright planet), “down”, or None.max_iter (
int) – Total maximum iterations (split across stages if multi-res).max_iter_per_stage (
Optional[List[int]]) – Explicit per-stage iteration budget.seed (
int) – Random seed.verbose (
bool) – Print progress.n_jobs (
int) – Parallel workers. Effective only for differential-evolution and shgo; emits a UserWarning for other minimizers.
- Returns:
For method chaining.
- Return type:
self
- fit_limb(stages, dashboard=False, dashboard_kwargs=None, target_planet='earth', n_jobs=1)[source]
Run a multi-stage fit by sequentially calling fit_sagitta / fit_arc / fit_gradient.
Resets self.stage_results before running so the list reflects only this call. Individual fit_* calls accumulate into stage_results without resetting.
- Parameters:
stages (
List[dict]) – Ordered list of stage dicts, each with a “method” key (“sagitta”, “arc”, or “gradient”) plus kwargs for that method.dashboard (
bool) – Show a live FitDashboard during optimization.dashboard_kwargs (
Optional[Dict]) – Extra kwargs forwarded to FitDashboard.__init__.target_planet (
str) – Planet name for dashboard reference radius.n_jobs (
int) – Parallel workers forwarded to each arc/gradient stage. Effective only for differential-evolution and shgo.
- Returns:
For method chaining.
- Return type:
self
Example:
obs.fit_limb([ {"method": "sagitta", "n_sigma": 2.0}, {"method": "arc", "minimizer": "basinhopping", "minimizer_preset": "robust"}, ])
- planet_ruler.observation.package_results(observation)[source]
Consolidate the results of a fit to see final vs. initial values.
- Parameters:
observation (object) – Instance of LimbObservation (must have used differential evolution minimizer).
- Returns:
- DataFrame of results including
fit value
initial value
parameter
- Return type:
results (pd.DataFrame)
Annotation Module
Interactive manual limb detection and annotation.
Manual Limb Annotation Tool for Planet Ruler
Allows users to click points on a horizon image and generate a sparse target for fitting with the existing planet_ruler pipeline.
- class planet_ruler.annotate.ToolTip(widget, text)[source]
Bases:
objectSimple tooltip that appears on hover.
- planet_ruler.annotate.create_tooltip(widget, text)[source]
Helper function to create tooltip for a widget.
- class planet_ruler.annotate.TkLimbAnnotator(image_path, image=None, initial_stretch=1.0, initial_zoom=None, output_dir=None)[source]
Bases:
objectTkinter-based interactive tool for manually annotating planet limbs.
Features: - Zoom with scroll wheel (fit large images in window) - Vertical stretch buttons (stretch pixels vertically for precision) - Scrollable canvas for navigating - Click to add points, right-click to undo - Save/load points to JSON - Generate sparse target array for CostFunction
- __init__(image_path, image=None, initial_stretch=1.0, initial_zoom=None, output_dir=None)[source]
Initialize the annotation tool.
- Parameters:
image_path (str) – Path to the image to annotate
image (np.ndarray) – Optionally the already loaded image
initial_stretch (float) – Initial vertical stretch factor
initial_zoom (float) – Initial zoom level (None = auto-fit)
output_dir (str or Path, optional) – Directory for saved JSON files. Defaults to the same directory as image_path.
- class planet_ruler.annotate.TkMaskSelector(image, masks, initial_zoom=None)[source]
Bases:
objectInteractive mask classification tool for segmentation results.
Works with ANY segmentation method - completely backend-agnostic. Allows users to classify masks as ‘planet’, ‘sky’, or ‘exclude’ for horizon detection. Aligns with Planet Ruler’s educational philosophy of transparency over black-box automation.
- Parameters:
image (
ndarray) – Original image array (H x W x 3)masks (
list) – List of masks in any of these formats: - List of np.ndarray (boolean H x W arrays) - List of dicts with ‘mask’ or ‘segmentation’ key - Mixed formats are OKinitial_zoom (
Optional[float]) – Initial zoom level (None = auto-fit to window)
- planet_ruler.annotate.load_limb_points_from_json(json_path, return_metadata=False)[source]
Load limb points from JSON and convert to sparse target array.
- Parameters:
- Returns:
Sparse target array with limb y-coordinates tuple: (target, metadata) if return_metadata=True
- Return type:
np.ndarray
Example
>>> # Simple usage - just get the target array >>> target = load_limb_points_from_json("image_limb_points.json") >>> >>> # Use with LimbObservation >>> from planet_ruler.observation import LimbObservation >>> obs = LimbObservation("image.jpg", "config.yaml") >>> target = load_limb_points_from_json("image_limb_points.json") >>> obs.register_limb(target) >>> obs.fit_limb() >>> >>> # Get metadata too (for validation) >>> target, metadata = load_limb_points_from_json( ... "image_limb_points.json", ... return_metadata=True ... ) >>> print(f"Loaded {metadata['n_points']} points from {metadata['image_path']}")
Camera Module
Automatic camera parameter extraction from EXIF data.
Automatic extraction of camera parameters from smartphone images. Uses EXIF data and a phone camera database.
- planet_ruler.camera.match_camera_module(camera_data, focal_length_mm, aperture=None)[source]
Match specific camera module for multi-camera phones.
Uses focal length as primary matcher, aperture as secondary confirmation. Falls back to main camera if no match found.
- planet_ruler.camera.get_focal_length_35mm_equiv(exif_data)[source]
Get 35mm equivalent focal length (more reliable for phones).
- planet_ruler.camera.get_image_orientation_from_exif(exif_data=None)[source]
Determine orientation from EXIF Orientation tag only.
- planet_ruler.camera.get_image_orientation_from_dimensions(width, height)[source]
Determine orientation from image dimensions (heuristic).
- planet_ruler.camera.apply_orientation_correction(params, exif_data=None)[source]
Apply orientation correction to camera parameters.
This modifies params in-place and returns it. Call this RIGHT BEFORE each return statement in extract_camera_parameters().
- planet_ruler.camera.calculate_sensor_dimensions(focal_length_mm, focal_length_35mm)[source]
Calculate sensor dimensions from focal length ratio. Uses the relationship: focal_length_mm / sensor_width = focal_length_35mm / 36mm
- planet_ruler.camera.get_sensor_statistics_by_type(camera_type)[source]
Calculate sensor dimension statistics for a given camera type. Returns median, min, and max for sensor width and height.
- planet_ruler.camera.infer_camera_type(exif_data)[source]
Try to infer camera type from EXIF data even if exact model unknown.
- planet_ruler.camera.extract_camera_parameters(image_path)[source]
Automatically extract all camera parameters from any camera image. Handles phones, point-and-shoot cameras, DSLRs, mirrorless, etc.
- Returns:
- Camera parameters including:
focal_length_mm: focal length in millimeters
sensor_width_mm: sensor width in millimeters
sensor_height_mm: sensor height in millimeters
sensor_width_min: minimum sensor width (if using type statistics)
sensor_width_max: maximum sensor width (if using type statistics)
image_width_px: image width in pixels
image_height_px: image height in pixels
camera_model: detected camera model
camera_type: ‘phone’, ‘compact’, ‘dslr’, ‘mirrorless’, or ‘unknown’
confidence: ‘high’, ‘medium’, or ‘low’
- Return type:
- planet_ruler.camera.get_gps_altitude(image_path)[source]
Extract GPS altitude from EXIF data if available.
- Returns:
Altitude in meters, or None if not available
- Return type:
- planet_ruler.camera.sample_param_from_bounds(lo, hi, ref=None, perturbation_factor=1.0, seed=None)[source]
Sample a parameter initial value uniformly from a sub-interval of [lo, hi].
Each side of the interval is scaled proportionally toward
refby(1 - perturbation_factor), preserving asymmetry in the original bounds. Withperturbation_factor=1.0the full [lo, hi] range is used; with 0.0 onlyrefis returned.- Example: lo=0.7, hi=1.2, ref=1.0, perturbation_factor=0.5
new_lo = 1.0 - (1.0 - 0.7) * 0.5 = 0.85 new_hi = 1.0 + (1.2 - 1.0) * 0.5 = 1.10
Uses a local Random instance to avoid polluting global random state.
- Parameters:
lo (
float) – Lower bound of search interval (inclusive)hi (
float) – Upper bound of search interval (inclusive)ref (
Optional[float]) – Reference value toward which bounds are scaled. Defaults to the midpoint (lo + hi) / 2, which is exact for symmetric bounds.perturbation_factor (
float) – 1.0 = full [lo, hi]; 0.0 = ref only. (default: 1.0)
- Return type:
- planet_ruler.camera.init_params_from_bounds(param_limits, perturbation_factor=1.0, seed=None, ref_values=None, params=None)[source]
Sample initial values for parameters uniformly from their search bounds.
Each parameter is sampled via
sample_param_from_bounds(). A single seeded RNG advances sequentially through a fixed parameter ordering so that each parameter’s draw is independent of which other parameters are included, and results are fully reproducible given the same seed.- Parameters:
param_limits (
Dict[str,List[float]]) – Dict mapping parameter name → [lo, hi].perturbation_factor (
float) – Passed tosample_param_from_bounds(). 1.0 (default) samples the full [lo, hi] range; 0.0 returns ref only.ref_values (
Optional[Dict[str,float]]) – Optional dict of reference values used as the proportional centre for each parameter. Defaults to the midpoint of each parameter’s bounds when not provided.params (
Optional[List[str]]) – Optional list of parameter names to sample. When None, all keys present inparam_limitsare sampled in the fixed order below (unknown names are appended at the end).
- Return type:
- Returns:
Dict mapping parameter name → sampled initial value.
- planet_ruler.camera.get_initial_radius(planet='earth')[source]
Return the known radius for a planet (metres), or 10,000 km for unknown planets.
- Return type:
- planet_ruler.camera.check_planet_ruler_crop_metadata(image_path)[source]
Check for crop metadata in sidecar JSON file.
- planet_ruler.camera.create_config_from_image(image_path, altitude_m=None, planet='earth', limits_preset='balanced', param_tolerances=None, param_tolerance=None)[source]
Create a complete planet_ruler configuration from an image. Works with any camera - phones, point-and-shoot, DSLRs, etc.
- Parameters:
image_path (
str) – Path to the imagealtitude_m (
Optional[float]) – Altitude in meters (REQUIRED if not in GPS data)planet (
str) – Planet name for initial radius guess (default: ‘earth’)limits_preset (
str) – How tightly to constrain camera/altitude parameters."tight"— trust EXIF and GPS data; small search windows."balanced"— default; moderate windows for most photos."loose"— wide windows; use when metadata reliability is uncertain. Altitude (h) bounds are automatically tightened when GPS altitude is detected, regardless of preset.param_tolerances (
Optional[Dict[str,float]]) – Per-parameter fractional tolerance overrides, e.g.{"h": 0.30}to widen the altitude window without changing other parameters. Keys:"f","w","h".param_tolerance (
Optional[float]) – Deprecated. Passlimits_presetinstead. A deprecation warning is raised; the value is ignored and"balanced"is used.
- Returns:
Configuration ready for planet_ruler
- Return type:
- Raises:
ValueError – If altitude cannot be determined from GPS and not provided manually
ValueError – If
limits_presetis not a recognised preset name.
Notes
For uncertainty quantification, consider running multiple times (multi-start optimization)
Theta parameters (orientation) always span ±π; they have no prior
r bounds scale with the preset around the planet init radius
Fitting Module
Parameter optimization and cost function handling.
- planet_ruler.fit.unpack_parameters(params, template)[source]
Turn a list of parameters back into a dict.
- planet_ruler.fit.pack_parameters(params, template)[source]
Turn a dict of parameters (or defaults) into a list.
- class planet_ruler.fit.BaseFitter[source]
Bases:
ABCCommon interface for planet-ruler fitting strategies.
Each subclass encapsulates one strategy and returns a stage-result dict from .fit(). The dict always contains:
updated_init – {param: value} updates to warm-start the next stage updated_limits – {param: [lo, hi]} tighter bounds for the next stage status – “ok” | “flat_arc” | “too_few_points” | “error” warnings – list[str]
- class planet_ruler.fit.BaseCostFunction(target, function, free_parameters, init_parameter_values)[source]
Bases:
objectShared evaluation logic for all cost function variants.
- class planet_ruler.fit.L2CostFunction(target, function, free_parameters, init_parameter_values, loss_function='l2')[source]
Bases:
BaseCostFunctionCost function for l2, l1, and log-l1 loss against a detected limb.
- class planet_ruler.fit.GradientFieldCostFunction(target, function, free_parameters, init_parameter_values, loss_function='gradient_field', kernel_smoothing=5.0, directional_smoothing=30, directional_decay_rate=0.15, prefer_direction=None)[source]
Bases:
BaseCostFunctionCost function using gradient field flux alignment.
- class planet_ruler.fit.LimbFitter(target, free_parameters, init_parameter_values, parameter_limits, loss_function, minimizer, minimizer_kwargs, max_iter=15000, seed=0, verbose=False, kernel_smoothing=5.0, directional_smoothing=50, directional_decay_rate=0.15, prefer_direction=None, n_jobs=1)[source]
Bases:
BaseFitterImage-space fitter using a pixel-level cost function and a scipy minimizer.
Accepts one target (image for gradient_field, limb array for l2/l1/log-l1) at a fixed resolution. The caller is responsible for downsampling and parameter scaling before instantiation.
minimizer_kwargs must already have preset values resolved by the caller.
- planet_ruler.fit.estimate_radius_via_sagitta(limb, h, f_px, x0=None, y0=None, sigma_px='auto', n_sigma=1.0, bias_correct=False, uncertainty='ols')[source]
Estimate planetary radius from a sparse limb arc using OLS on the sagitta.
Fits K = r / sqrt(h*(2r+h)) by regressing observed sagittae against the exact hyperbola model A(u) = sqrt(f_px^2 + u^2) - f_px.
- Parameters:
limb (
ndarray) – 1-D array of length n_pix_x; NaN where not annotated.h (
float) – Observer altitude in metres.f_px (
float) – Focal length in pixels.x0 (
Optional[float]) – Optional override for apex x-coordinate (auto-detected if None).y0 (
Optional[float]) – Image vertical centre in pixels, required for bias_correct=True.sigma_px (
float|str) – Annotation noise in pixels, or “auto” to derive from RMS residuals.n_sigma (
float) – Bound width in sigma units.bias_correct (
bool) – If True and y0 is provided, correct for camera tilt bias using the apex y-offset to estimate theta_x, then refine kappa via 1-D minimization.uncertainty (
str) – “ols” | “jackknife” | “both”. Controls which K_sigma drives bounds.
- Returns:
- r, r_low, r_high, r_sigma, K, K_sigma, K_sigma_jack,
n_points, residual_rms, arc_angle_deg, x_apex, y_apex, theta_x_est, status, warnings.
- Return type:
dict with keys
- class planet_ruler.fit.SagittaFitter(limb, h, f_px, y0, free_parameters, init_parameter_values, parameter_limits, sigma_px='auto', n_sigma=1.0, uncertainty='jackknife', bias_correct=False)[source]
Bases:
BaseFitter2-D optimizer over (kappa, theta_x) using the exact projected-sagitta formula.
Accurate to < 0.05 km for all tested camera tilts. Fits only r and theta_x; other free_parameters are handled by a subsequent LimbFitter stage.
- planet_ruler.fit.calculate_parameter_uncertainty(observation, parameter='r', method='auto', uncertainty_type='std', scale_factor=1.0)[source]
Calculate parameter uncertainty from fitting results.
Provides a flexible interface for uncertainty estimation that works with different optimization methods and uncertainty metrics.
- Parameters:
observation – LimbObservation object with completed fit
parameter (str) – Parameter name to calculate uncertainty for (default: “r”)
method (str) – Uncertainty calculation method: - “auto”: Automatically detect method from fit results - “differential_evolution”: Use DE population posteriors - “bootstrap”: Use bootstrap resampling (future implementation) - “hessian”: Use Hessian-based uncertainty (future implementation)
uncertainty_type (str) – Type of uncertainty measure: - “std”: Standard deviation of parameter distribution - “ptp”: Peak-to-peak range (max - min) - “iqr”: Interquartile range (75th - 25th percentile) - “ci”: Confidence interval (returns dict with bounds)
scale_factor (float) – Scale factor to apply to results (e.g., 1000 for km units)
- Returns:
- Dictionary containing uncertainty information:
”value”: Fitted parameter value (scaled)
”uncertainty”: Uncertainty estimate (scaled)
”method”: Method used for uncertainty calculation
”type”: Type of uncertainty measure used
”raw_data”: Raw parameter samples if available
- Return type:
- Raises:
ValueError – If uncertainty method is not supported or data is insufficient
AttributeError – If observation doesn’t have required fit results
- planet_ruler.fit.format_parameter_result(uncertainty_result, units='')[source]
Format parameter uncertainty results for display.
- planet_ruler.fit.unpack_diff_evol_posteriors(observation)[source]
Extract the final state population of a differential evolution minimization and organize as a DataFrame.
- Parameters:
observation (object) – Instance of LimbObservation (must have used differential evolution minimizer).
- Returns:
Population (rows) and properties (columns).
- Return type:
population (pd.DataFrame)
Uncertainty Module
Parameter uncertainty estimation using multiple methods.
- planet_ruler.uncertainty.calculate_parameter_uncertainty(observation, parameter, method='auto', scale_factor=1.0, confidence_level=0.68, n_bootstrap=20, **kwargs)[source]
Calculate uncertainty for a fitted parameter using appropriate method.
Automatically selects best method based on minimizer used: - differential_evolution: Population spread (fast, exact) - dual_annealing/basinhopping: Hessian approximation (fast, approximate) - any: Profile likelihood or bootstrap (slow, accurate)
- Parameters:
observation – LimbObservation instance with completed fit
parameter (
str) – Parameter name (e.g., ‘r’, ‘h’, ‘f’)method (
Literal['auto','hessian','profile','bootstrap']) – Uncertainty estimation method - ‘auto’: Choose based on minimizer and available data - ‘hessian’: Inverse Hessian at optimum (fast) - ‘profile’: Profile likelihood (slow but accurate) - ‘bootstrap’: Multiple fits with different seeds (slow)scale_factor (
float) – Scale result (e.g., 1000.0 to convert m→km)confidence_level (
float) – Confidence level (0.68=1σ, 0.95=2σ)n_bootstrap (
int) – Number of bootstrap iterations
- Returns:
‘uncertainty’: The uncertainty value
’method’: Method used
’confidence_level’: Confidence level
’additional_info’: Method-specific details
- Return type:
dict with keys
Plotting Module
Visualization and plotting functions.
- planet_ruler.plot.plot_image(im_arr, gradient=False, show=True)[source]
Display an image using matplotlib.pyplot.imshow.
- planet_ruler.plot.plot_limb(y, show=True, c='y', s=10, alpha=0.2)[source]
Display the limb (usually on top of an image).
- planet_ruler.plot.plot_3d_solution(r, h=1, zoom=1, savefile=None, legend=True, vertical_axis='z', azim=None, roll=None, x_axis=False, y_axis=True, z_axis=False, **kwargs)[source]
Plot a limb solution in 3D.
- Parameters:
r (float) – Radius of the body in question.
h (float) – Height above surface (units should match radius).
zoom (float) – Shrink the height according to a zoom factor to make viewing easier.
savefile (str) – Path to optionally save figure.
legend (bool) – Display the legend.
vertical_axis (str) – Which axis will be used as the vertical (x, y, or z).
azim (float) – Viewing azimuth.
roll (float) – Viewing roll.
x_axis (bool) – Plot the x-axis.
y_axis (bool) – Plot the y-axis.
z_axis (bool) – Plot the z-axis.
kwargs – Absorbs other solution kwargs that don’t matter for physical space.
- Return type:
- planet_ruler.plot.plot_topography(image)[source]
Display the full limb, including the section not seen in the image.
- Parameters:
image (np.ndarray) – Image array.
- Return type:
- planet_ruler.plot.plot_gradient_field_at_limb(y_pixels, image, image_smoothing=None, kernel_smoothing=5.0, directional_smoothing=50, directional_decay_rate=0.15, sample_spacing=50, arrow_scale=20)[source]
Visualize gradient field along a proposed limb curve.
- Parameters:
y_pixels (np.ndarray) – Y-coordinates of limb at each x-position
image (np.ndarray) – Input image (H x W x 3 or H x W)
image_smoothing (int) – For gradient_field - Gaussian blur sigma applied to image before gradient computation. Removes high-frequency artifacts (crater rims, striations) that could mislead optimization. Different from kernel_smoothing.
kernel_smoothing (float) – Initial smoothing for gradient direction estimation
directional_smoothing (int) – How far to sample along gradients
directional_decay_rate (float) – Exponential decay rate for sampling
sample_spacing (int) – Sample every N pixels along x-axis
arrow_scale (float) – Scale factor for arrow lengths
- Returns:
Matplotlib figure and axis objects
- Return type:
fig, ax
- planet_ruler.plot.compare_blur_methods(image, y_pixels=None)[source]
Compare gradient magnitude with different blur methods.
- Parameters:
image – Input image
y_pixels – Optional limb curve to overlay
- planet_ruler.plot.compare_gradient_fields(y_pixels_list, labels, image, image_smoothing=None, kernel_smoothing=5.0, directional_smoothing=30, directional_decay_rate=0.15)[source]
Compare gradient alignment for multiple proposed limbs.
- Parameters:
y_pixels_list (list) – List of y-coordinate arrays (different limb proposals)
labels (list) – Labels for each limb
image (np.ndarray) – Input image
kernel_smoothing (float) – Initial smoothing for gradient direction estimation
directional_smoothing (int) – How far to sample along gradients
directional_decay_rate (float) – Exponential decay rate for sampling
- planet_ruler.plot.plot_diff_evol_posteriors(observation, show_points=False, log=True)[source]
Extract and display the final state population of a differential evolution minimization.
- planet_ruler.plot.plot_full_limb(observation, x_min=None, x_max=None, y_min=None, y_max=None)[source]
Display the full limb, including the section not seen in the image.
- planet_ruler.plot.plot_residuals(observation, show_sparse_markers=True, marker_size=10, alpha=0.6, figsize=(16, 6), show_image=False, image_alpha=0.4, band_size=30)[source]
Plot residuals between the fitted limb and the detected target limb.
- Parameters:
observation – Instance of LimbObservation that has been fitted.
show_sparse_markers (
bool) – Use larger markers for sparse data.marker_size (
int) – Size of markers for sparse data.alpha (
float) – Transparency of residual markers/line.figsize (
tuple) – Figure size (width, height).show_image (
bool) – Show straightened image strip as background.image_alpha (
float) – Transparency of background image.band_size (
int) – Size of band around residuals to plot (in pixels)
- Return type:
- planet_ruler.plot.plot_gradient_field_quiver(image, step=2, scale=0.15, limb_y=None, roi_height=None, image_smoothing=None, kernel_smoothing=5.0, directional_smoothing=50, directional_decay_rate=0.15, downsample_factor=32, figsize=(16, 10), cmap='hot')[source]
Plot gradient field as quiver (arrow) plot.
- Parameters:
image (
ndarray) – Input image array.step (
int) – Spacing between arrows (every Nth pixel).limb_y (
Optional[ndarray]) – Optional limb curve to overlay (y-coordinates).roi_height (
Optional[int]) – If provided, only show ±roi_height pixels around limb.image_smoothing (
Optional[int]) – For gradient_field - Gaussian blur sigma applied to image before gradient computation. Removes high-frequency artifacts (crater rims, striations) that could mislead optimization. Different from kernel_smoothing.kernel_smoothing (
float) – Sigma for initial gradient direction estimation.directional_smoothing (
int) – Distance for directional blur sampling.directional_decay_rate (
float) – Exponential decay for directional blur.downsample_factor (
int) – Downsample image by this factor before computing gradients. Values > 1 reduce resolution (e.g., 2 = half resolution, 4 = quarter). Useful for visualizing gradient field at different optimization stages.figsize (
tuple) – Figure size (width, height).cmap (
str) – Colormap for gradient magnitude.
- Return type:
- planet_ruler.plot.plot_segmentation_masks(observation)[source]
Display all the classes/masks generated by the segmentation.
- planet_ruler.plot.plot_sam_masks(masks, labels=None, colors=None, alpha=0.5, image=None, figsize=(16, 10), title=None, show=True)[source]
Plot multiple SAM segmentation masks as separate labeled objects with legend.
- Parameters:
masks (list) – List of SAM mask dictionaries with ‘segmentation’ keys containing boolean arrays. Can also be a list of boolean arrays directly.
labels (list) – Labels for each mask (for legend). If None, uses “Mask 0”, “Mask 1”, etc.
colors (list) – Colors for each mask. If None, uses a default color cycle.
alpha (float) – Transparency of mask overlays (0=transparent, 1=opaque).
image (np.ndarray) – Optional background image to display under masks.
figsize (tuple) – Figure size in inches.
title (str) – Optional title for the plot.
show (bool) – Whether to display the plot immediately.
- Returns:
(fig, ax) matplotlib figure and axis objects.
- Return type:
Example
>>> masks = [{'segmentation': planet_mask}, {'segmentation': sky_mask}] >>> fig, ax = plot_sam_masks( ... masks, ... labels=['Planet', 'Sky'], ... colors=['yellow', 'cyan'], ... image=observation.image ... )
Validation Module
Configuration validation and consistency checking.
Validation functions for planet_ruler.
- planet_ruler.validation.validate_limb_config(config, strict=True)[source]
Validate that a planet_ruler configuration is internally consistent.
Checks: 1. Initial parameter values are within their specified limits 2. Theta parameter limits are wide enough (avoid r-h coupling issues) 3. Radius limits span reasonable range for robust optimization
- Parameters:
- Raises:
AssertionError – If strict=True and validation fails
- Return type:
Example
>>> config = { ... 'init_parameter_values': {'r': 6371000, 'theta_x': 0.1}, ... 'parameter_limits': {'r': [1e6, 1e8], 'theta_x': [-3.14, 3.14]} ... } >>> validate_config(config) # Passes
Command-Line Interface
CLI tools for command-line access to planet_ruler.
Command-line interface for planet_ruler
This module provides a simple CLI for measuring planetary radii from horizon photographs.
Demo Module
Example scenarios and configuration management.