stentfit.core.plotting
Functions
|
Randomly subsample rows so a plot draws at most |
|
Draw a point cloud as an interactive 3D scatter and save it as HTML. |
|
Build the x/y/z arrays to draw every skeleton edge as one Plotly line trace. |
|
Draw the 3D skeleton graph as edges and node-type markers, save as HTML. |
Draw the final 3D skeleton overlaid on a sparse stent surface cloud, as HTML. |
|
|
Draw every fitted spline curve in 3D, each in its own color, as HTML. |
|
Draw the ring-boundary dip detection profile and save it as HTML. |
|
Draw one ring's auto-tune convergence (or a quality summary) and save it as HTML. |
|
Draw one ring's flat 2D skeleton over its surface points, with any |
|
Render one ring's current 2D skeleton via |
|
Unroll 3D points onto the (z, arc) plane, recomputing angle from x/y. |
|
Insert a NaN wherever an unrolled curve jumps across the arc seam. |
|
Decode one Plotly-exported array back into a plain numpy array. |
|
Re-extract the tuning data plotted in a saved ring convergence HTML file. |
|
Circular distance between two hues in |
|
Resolve the convergence-plot file and ring ID for the k-th ring band. |
|
Draw the unrolled 2D splines over the stent cloud, with per-ring tuning |
|
Build a 3D tube mesh of every fitted spline and save it as GLB + HTML. |
Module Contents
- stentfit.core.plotting._downsample_df(df: pandas.DataFrame, max_display: int | None, random_state: int = 0) pandas.DataFrame[source]
Randomly subsample rows so a plot draws at most
max_displaypoints.- Parameters:
df – Rows to subsample.
max_display – Maximum rows to keep.
Noneor a value at least as large aslen(df)returnsdfunchanged.random_state – Seed for the row sampling, for repeatable plots.
- Returns:
dfitself, or a randommax_display-row subset of it.
- stentfit.core.plotting.plot_points_3d_html(df: pandas.DataFrame, id_col: str, out_path: str, color_col: str | None = None, max_display: int = 40000, title: str = '', point_size: float = 1, categorical: bool = False) str[source]
Draw a point cloud as an interactive 3D scatter and save it as HTML.
dfis downsampled tomax_displaypoints first, so large clouds stay responsive in the browser. Coloring has three modes: nocolor_coldraws every point in one flat color;color_colwithcategorical=Truedraws one trace per label with its own legend entry;color_colwithoutcategoricaldraws a single trace with a continuous colorbar.- Parameters:
df – Point cloud with at least
x,y,z, andid_colcolumns.id_col – Column shown as the point ID on hover.
out_path – File path the HTML view is written to.
color_col – Column used to color the points.
Nonedisables coloring.max_display – Maximum number of points drawn, downsampled if
dfis larger.title – Plot title. The shown/total point count is appended automatically.
point_size – Marker size for the scatter points.
categorical – Treat
color_colas discrete labels instead of a continuous value.
- Returns:
out_path, for chaining into a caller’s own return value.
- stentfit.core.plotting._skeleton_edge_segments(skeleton_df: pandas.DataFrame) tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray][source]
Build the x/y/z arrays to draw every skeleton edge as one Plotly line trace.
Each edge contributes its two endpoints followed by a
NaN, which breaks the line so Plotly draws many disconnected segments from a singleScatter3dtrace instead of one per edge. Each undirected edge (neighbor_idsis stored both ways) is only emitted once.- Parameters:
skeleton_df – Skeleton graph with
skeleton_point_id,x,y,z, andneighbor_idscolumns.- Returns:
(xe, ye, ze)coordinate arrays,NaN-separated, ready to pass straight togo.Scatter3d(mode='lines').
- stentfit.core.plotting.plot_skeleton_html(skeleton_df: pandas.DataFrame, out_path: str, title: str = 'Skeleton', max_display: int = 40000) str[source]
Draw the 3D skeleton graph as edges and node-type markers, save as HTML.
Every edge is drawn once as a single line trace (
_skeleton_edge_segments()); nodes are downsampled tomax_displayand colored bynode_type(line,junction,endpoint,isolated), each as its own legend-toggleable trace.- Parameters:
skeleton_df – Skeleton graph with
x,y,z,skeleton_point_id,degree,node_type, andneighbor_idscolumns.out_path – File path the HTML view is written to.
title – Plot title.
max_display – Maximum number of nodes drawn, downsampled if
skeleton_dfis larger. Edges are always drawn in full.
- Returns:
out_path, for chaining into a caller’s own return value.
- stentfit.core.plotting.plot_skeleton_with_cloud_html(skeleton_df: pandas.DataFrame, stent_df: pandas.DataFrame, out_path: str, max_cloud: int = 40000) str[source]
Draw the final 3D skeleton overlaid on a sparse stent surface cloud, as HTML.
Both the surface cloud and the skeleton nodes are downsampled to
max_cloudpoints; skeleton edges are always drawn in full (_skeleton_edge_segments()). The cloud is drawn faint and small so the skeleton stays the clear focal point.- Parameters:
skeleton_df – Final 3D skeleton graph with
x,y,z,skeleton_point_id, andneighbor_idscolumns.stent_df – Stent surface point cloud with
x,y,z, andpoint_idcolumns.out_path – File path the HTML view is written to.
max_cloud – Maximum number of points drawn for the surface cloud and for the skeleton nodes, each downsampled independently.
- Returns:
out_path, for chaining into a caller’s own return value.
- stentfit.core.plotting.plot_splines_html(splines: list, out_path: str, n_eval: int = 100) str[source]
Draw every fitted spline curve in 3D, each in its own color, as HTML.
Each spline is evaluated at
n_evalpoints along its parameter range (scipy.interpolate.splev); a curve with no fitted spline (the polyline fallback fromfit_curve_spline()) is drawn from its raw control points instead.Noneentries (curves where fitting produced nothing) are skipped.- Parameters:
splines – Per-curve fit results from
fit_skeleton_splines().out_path – File path the HTML view is written to.
n_eval – Number of points each spline is evaluated at for drawing.
- Returns:
out_path, for chaining into a caller’s own return value.
- stentfit.core.plotting.plot_ring_dips_html(ring_res: dict, out_path: str) str[source]
Draw the ring-boundary dip detection profile and save it as HTML.
Plots the smoothed points-per-slice curve along z, marks the candidate dips and the depth cutoff used to filter them, shades each detected ring as an alternating background band labelled
ring i, and draws a vertical line at each boundary that was actually used to cut the stent into rings.- Parameters:
ring_res – Dict returned by
find_rings(); must havedip_z_centers,dip_counts_smoothed,dip_indices,dip_depth_thresh, and optionallyn_bands/boundary_z.out_path – File path the HTML view is written to.
- Returns:
out_path, for chaining into a caller’s own return value.
- stentfit.core.plotting.plot_thickness_diagnostics_html(df_thick: pandas.DataFrame, r: numpy.ndarray, out_path: str, strut_thickness: float) str[source]
- stentfit.core.plotting.plot_ring_convergence_html(history: pandas.DataFrame | None, out_path: str, ring_id: int, quality_report: dict | None = None, pps: float | None = None, dil_px: int | None = None) str[source]
Draw one ring’s auto-tune convergence (or a quality summary) and save it as HTML.
Three cases: with a non-empty
history(fromtune_skeleton_params()), draws thetotal/defect/qualityerror trajectory across tuning steps. Without a history but with aquality_report, draws a bar chart of the defect counts instead (used for the fixed-params, no-auto-tune case). With neither, draws a placeholder noting auto-tune was off.- Parameters:
history – Per-step tuning history from
tune_skeleton_params().Noneor empty falls back to the quality-summary or placeholder case.out_path – File path the HTML view is written to.
ring_id – Ring identifier, used in the plot title.
quality_report – Dict from
check_skeleton_quality(), used for the quality-summary bar chart whenhistoryis unavailable.pps –
pixels_per_strutused, shown in the quality-summary title if given.dil_px –
dilate_pxused, shown in the quality-summary title if given.
- Returns:
out_path, for chaining into a caller’s own return value.
- stentfit.core.plotting.plot_ring_skeleton_2d_html(arc: numpy.ndarray, z: numpy.ndarray, surface_arc: numpy.ndarray, surface_z: numpy.ndarray, out_path: str, ring_label: str, ring_band: tuple[float, float] | None = None, changed_idx: numpy.ndarray | None = None, quality_report: dict | None = None, title: str = '') str[source]
Draw one ring’s flat 2D skeleton over its surface points, with any flagged defects overlaid, and save it as HTML.
The surface points are cropped to
ring_bandfirst, if given, so a ring skeletonised with a z-halo is shown next to only its own surface band. Whenquality_reportis passed, its bad connections, loops, and empty regions are drawn as markers, tagged with the nearest skeleton point’s index so they line up with the manual-edit prompts. Whenchanged_idxis passed, those skeleton points are highlighted, useful for showing what a manual edit changed.- Parameters:
arc – Flat arc-coordinates of the ring’s 2D skeleton.
z – Flat z-coordinates of the ring’s 2D skeleton.
surface_arc – Flat arc-coordinates of the ring’s surface points.
surface_z – Flat z-coordinates of the ring’s surface points.
out_path – File path the HTML view is written to.
ring_label – Ring label used in the default title.
ring_band –
(z_lo, z_hi)the surface points are cropped to.Noneshows every surface point passed in.changed_idx – Skeleton point indices to highlight as changed.
quality_report – Dict from
check_skeleton_quality(); itsbad_edge_xy,loop_points_xy, andempty_xyare drawn as defect markers, and the issue count is appended to the title.title – Plot title.
ring_labeland the issue count are used if empty.
- Returns:
out_path, for chaining into a caller’s own return value.
- stentfit.core.plotting._render_ring_2d(ring_2d: dict, label: str, plots_dir: str, changed_idx: numpy.ndarray | None = None, suffix: str | None = None) str[source]
Render one ring’s current 2D skeleton via
plot_ring_skeleton_2d_html().Used by the interactive edit loop to preview a tentative edit: with
suffix='edited', the file is named<label>_edited_<rec['n_edits']>.htmlinstead of<label>.html, so each edit gets its own preview without overwriting the original.- Parameters:
ring_2d – Per-ring 2D skeletons, keyed by
label.label – Ring label to render (e.g.
"ring_01").plots_dir – Folder the HTML view is written into.
changed_idx – Skeleton point indices to highlight as changed.
suffix –
'edited'names the file after the ring’s current edit count instead of its plain label.
- Returns:
Path to the written HTML file.
- stentfit.core.plotting._to_arc_z(x: numpy.ndarray, y: numpy.ndarray, z: numpy.ndarray, r_mid: float) tuple[numpy.ndarray, numpy.ndarray][source]
Unroll 3D points onto the (z, arc) plane, recomputing angle from x/y.
Unlike
open_stent_to_plane(), which reads athetacolumn directly, this recomputes it fromx/yviaarctan2— used for spline points, which only have xyz coordinates.- Parameters:
x – X-coordinates.
y – Y-coordinates.
z – Z-coordinates.
r_mid – Mid-wall radius, used to convert angle to arc length.
- Returns:
(z, arc)coordinate arrays.
- stentfit.core.plotting._break_seam(z_ax: numpy.ndarray, arc: numpy.ndarray, thresh: float) tuple[numpy.ndarray, numpy.ndarray][source]
Insert a NaN wherever an unrolled curve jumps across the arc seam.
A curve that crosses the seam (e.g. from
+circumference/2back to-circumference/2) would otherwise be drawn as one long spurious line all the way across the plot. Any gap inarcwider thanthreshis cut by inserting aNaNat that point in both arrays.- Parameters:
z_ax – Z-coordinates (or another axial coordinate) of the unrolled curve.
arc – Arc-coordinates of the unrolled curve.
thresh – Minimum arc jump between consecutive points that counts as a seam crossing.
- Returns:
(z_ax, arc), each with aNaNinserted at every seam crossing.
- stentfit.core.plotting._plotly_decode(o: dict | list) numpy.ndarray[source]
Decode one Plotly-exported array back into a plain numpy array.
Plotly’s HTML export sometimes stores array data compactly as base64-encoded typed arrays (a dict with
bdata/dtype, optionallyshape) instead of a plain JSON list. This reverses that encoding; anything else is passed straight tonp.asarray.- Parameters:
o – A trace’s raw
x/yvalue from the parsed Plotly JSON — either a typed-array dict or a plain list.- Returns:
The decoded array.
- stentfit.core.plotting._load_convergence(path: str) dict | None[source]
Re-extract the tuning data plotted in a saved ring convergence HTML file.
Reads the Plotly figure written by
plot_ring_convergence_html()back off disk: finds its embeddedPlotly.newPlot(...)call with a string-aware bracket scan (so brackets inside trace names don’t confuse it), parses that JSON, and pulls out either thetotal/defect/qualitytrajectory traces (auto-tune on) or the single quality-summary bar trace (auto-tune off), decoding any typed-array values via_plotly_decode(). Used to redraw those tuning plots as small matplotlib strips inplot_skeleton_splines_2d(), without needing the original tuning history in memory.- Parameters:
path – Path to a
ring_XX_convergence.htmlfile.- Returns:
Noneif the file can’t be read or parsed. Otherwise a dict withkindset to'convergence'(plustotal/defect/qualityas(x, y)arrays) or'quality_bar'(plusx,y,colors).
- stentfit.core.plotting._hue_gap(a: float, b: float) float[source]
Circular distance between two hues in
[0, 1).Hue wraps around (0 and 1 are the same color), so a plain difference would overstate the gap between hues on opposite sides of the wrap.
- Parameters:
a – First hue, in
[0, 1).b – Second hue, in
[0, 1).
- Returns:
The shorter of the two distances around the circle.
- stentfit.core.plotting._band_conv(k: int, ring_order: list | None, n_bands: int, conv_files: list[str], conv_dir: str) tuple[str | None, int | None][source]
Resolve the convergence-plot file and ring ID for the k-th ring band.
If
ring_orderis available and matchesn_bands, the file path is built directly from the k-th ring’s ID. Otherwise, falls back to indexing intoconv_files(sorted by filename) and parsing the ring ID back out of that file’s name.- Parameters:
k – Index of the ring band, in axial order.
ring_order – Ring IDs in axial order, from
detect_rings()/skeletonize_rings_2d().Noneor a length mismatch falls back toconv_files.n_bands – Total number of ring bands.
conv_files – Sorted list of
ring_XX_convergence.htmlpaths, used as the fallback.conv_dir – Folder the convergence files live in, used to build the path when
ring_orderis available.
- Returns:
(path, ring_id), or(None, None)if neither source could resolve this band.
- stentfit.core.plotting.plot_skeleton_splines_2d(skeleton_curves: list[list[int]], skeleton_splines: list[dict | None], stent_df: pandas.DataFrame, r_mid: float, circumference: float, ring_edges: numpy.ndarray | None, ring_order: list | None, output_dir: str, stent_name: str) dict[source]
Draw the unrolled 2D splines over the stent cloud, with per-ring tuning plots stacked above their band, and save it as a static PNG + HTML.
Curves are colored with a greedy rotating palette so any two curves that share a point differ in hue. Ring boundaries are read from
stent_features.jsonif present (elsering_edges, else derived fromstent_df’sring_idgroups) and drawn as vertical dashed lines; each ring’s saved convergence/quality-summary HTML (plot_ring_convergence_html()) is parsed back out (_load_convergence()) and redrawn as a small matplotlib strip above that ring’s band. The figure is saved as a PNG, embedded as a self-contained HTML page, and also shown inline.- Parameters:
skeleton_curves – Grouped point-id curves, from
group_skeleton_curves().skeleton_splines – Per-curve fit results, from
fit_skeleton_splines().stent_df – Stent surface point cloud, drawn as a grey underlay.
r_mid – Mid-wall radius, used to unroll splines and the cloud to (z, arc) coordinates.
circumference – Full circumference at
r_mid, used to detect and break the seam when unrolling each spline.ring_edges – Z-boundaries between rings, used if
stent_features.jsonhas noring_boundaries.ring_order – Ring IDs in axial order, used to match each band to its convergence file.
Nonefalls back to parsing the ring ID from each convergence file’s name.output_dir – Folder the PNG/HTML are written into, and where
stent_features.jsonand the per-ring convergence plots are read from.stent_name – Name used to label the plot title.
- Returns:
Dict with the paths to the written PNG and HTML (
png,html).
- stentfit.core.plotting.plot_skeleton_splines_trimesh(skeleton_splines: list[dict | None], output_dir: str, show: bool = False, tube_radius: float | None = None, sections: int = 6) trimesh.Trimesh | None[source]
Build a 3D tube mesh of every fitted spline and save it as GLB + HTML.
Each spline is evaluated (or, for the polyline fallback, taken as-is) and turned into a chain of cylinder segments, colored per-curve. The combined mesh is exported as a
.glband, where the trimesh notebook viewer supports it, as a self-contained HTML page.- Parameters:
skeleton_splines – Per-curve fit results, from
fit_skeleton_splines().output_dir – Folder the GLB and HTML are written into.
show – Open an interactive trimesh viewer window.
tube_radius – Cylinder radius for each curve.
Nonepicks it automatically as a fraction of the mesh’s bounding-box diagonal.sections – Number of sides on each cylinder’s cross-section.
- Returns:
The combined mesh, or
Noneif there were no curves to draw.