@@ -46,6 +46,41 @@ def matplotlib_cmap_to_fury_lut(cmap, value_range=(-1, 1), n_colors=256):
4646 return lut
4747
4848
49+ def _split_streamline_by_bounds (sl : np .ndarray ,
50+ cl : np .ndarray ,
51+ x_min , x_max , y_min , y_max , z_min , z_max ):
52+ """
53+ Returns lists of segments (points) and colors, one per contiguous in-bounds run.
54+ No straight 'bridging' lines will be drawn between disjoint segments.
55+ """
56+ # in-bounds mask
57+ within = (
58+ (sl [:, 0 ] >= x_min ) & (sl [:, 0 ] <= x_max ) &
59+ (sl [:, 1 ] >= y_min ) & (sl [:, 1 ] <= y_max ) &
60+ (sl [:, 2 ] >= z_min ) & (sl [:, 2 ] <= z_max )
61+ )
62+
63+ if not np .any (within ):
64+ return [], []
65+
66+ # find starts/ends of True runs
67+ w = within .astype (np .int8 )
68+ # transitions: +1 = False->True (start), -1 = True->False (end+1)
69+ trans = np .diff (np .pad (w , (1 , 1 ), constant_values = 0 ))
70+ starts = np .where (trans == + 1 )[0 ]
71+ ends = np .where (trans == - 1 )[0 ] # each end is exclusive index
72+
73+ segs , cols = [], []
74+ for s , e in zip (starts , ends ):
75+ seg = sl [s :e ] # e is exclusive
76+ col = cl [s :e ]
77+ if len (seg ) > 0 :
78+ segs .append (seg )
79+ cols .append (col )
80+
81+ return segs , cols
82+
83+
4984def show_streamlines (
5085 streamlines_xyz : list [np .ndarray ],
5186 color_values : list [np .ndarray ],
@@ -107,48 +142,49 @@ def show_streamlines(
107142
108143 # --- Cropping
109144 print (
110- f"Cropping streamlines within bounds: { crop_bounds } "
111- if crop_bounds
112- else "No cropping applied."
145+ f"Cropping streamlines within bounds: { crop_bounds } "
146+ if crop_bounds
147+ else "No cropping applied."
113148 )
149+
114150 if crop_bounds is not None :
115151 z_min , z_max = crop_bounds [2 ]
116152 y_min , y_max = crop_bounds [1 ]
117153 x_min , x_max = crop_bounds [0 ]
118154
119155 new_streamlines = []
120156 new_color_values = []
121- color_idx = 0
122157
123- for sl in streamlines_xyz :
124- n_pts = len (sl )
125- cl = color_values [color_idx : color_idx + n_pts ]
158+ # If color_values was provided flattened, keep track with a cursor.
159+ # But later code expects lists, so we’ll convert to lists here.
160+ # Detect if flat (ndarray) or already list-like:
161+ flat_input = not isinstance (color_values , (list , tuple ))
126162
163+ color_cursor = 0
164+ for sl in streamlines_xyz :
127165 sl = np .asarray (sl )
128- cl = np .asarray (cl )
129-
130- within = (
131- (sl [:, 0 ] >= x_min )
132- & (sl [:, 0 ] <= x_max )
133- & (sl [:, 1 ] >= y_min )
134- & (sl [:, 1 ] <= y_max )
135- & (sl [:, 2 ] >= z_min )
136- & (sl [:, 2 ] <= z_max )
166+ if flat_input :
167+ n_pts = len (sl )
168+ cl = np .asarray (color_values [color_cursor :color_cursor + n_pts ])
169+ color_cursor += n_pts
170+ else :
171+ # color_values is parallel to streamlines_xyz
172+ # pull next color array by index; we’ll iterate with zip below if you prefer
173+ raise ValueError ("color_values should be a flat 1D array before cropping." )
174+
175+ segs , cols = _split_streamline_by_bounds (
176+ sl , cl , x_min , x_max , y_min , y_max , z_min , z_max
137177 )
178+ if segs :
179+ new_streamlines .extend (segs )
180+ new_color_values .extend (cols )
138181
139- if np .any (within ): # Keep only remaining points
140- new_sl = sl [within ]
141- new_cl = cl [within ]
142- if len (new_sl ) > 0 :
143- new_streamlines .append (new_sl )
144- new_color_values .append (new_cl )
182+ streamlines_xyz = new_streamlines
183+ color_values = new_color_values # now a list aligned with streamlines
145184
146- color_idx += n_pts
185+ if not streamlines_xyz :
186+ raise ValueError ("❌ No streamlines intersect the crop box." )
147187
148- streamlines_xyz = new_streamlines
149- color_values = (
150- np .concatenate (new_color_values ) if new_color_values else np .array ([])
151- )
152188
153189 # --- Downsample and filter
154190 downsampled_streamlines = []
@@ -218,6 +254,7 @@ def show_streamlines(
218254 scene = fury .window .Scene ()
219255 colors = flat_colors # per-vertex scalars
220256
257+
221258 # --- Render according to mode
222259 if mode == "tube" :
223260 actor = fury .actor .streamtube (
0 commit comments