13
13
from scipy .stats import binned_statistic_2d
14
14
15
15
16
- def _add_scatter (datax , datay , to_scatter , origin , datadx , dir_vecs , dx , dy , ax ):
16
+ def _add_scatter (to_scatter , origin , dir_vecs , dx , dy , ax ):
17
17
xyz = to_scatter [0 ]["data" ] - origin
18
18
viewport = max (dx .magnitude , dy .magnitude )
19
19
radius = None
20
20
if "s" in to_scatter [0 ]["params" ]:
21
21
size = to_scatter [0 ]["params" ]["s" ]
22
22
if isinstance (size , Array ) or isinstance (size , Quantity ):
23
- radius = size .to (datax . unit .units )
23
+ radius = size .to (dx .units )
24
24
to_scatter [0 ]["params" ]["s" ] = radius
25
25
if radius is None :
26
26
# Fudge factor to select sinks close to the plane
@@ -115,65 +115,64 @@ def plane(*layers,
115
115
116
116
# Distance to the plane
117
117
xyz = dataset ["amr" ]["xyz" ] - origin
118
- diagonal = dataset ["amr" ]["dx" ] * np .sqrt (dataset .meta ["ndim" ]) * 0.5
119
- dist1 = np .sum (xyz * dir_vecs [0 ], axis = 1 )
118
+ diagonal_close = dataset ["amr" ]["dx" ] * 0.5 * np .sqrt (dataset .meta ["ndim" ])
119
+ dist_close = np .sum (xyz * dir_vecs [0 ], axis = 1 )
120
120
# Create an array of indices to allow further narrowing of the selection below
121
- global_selection = np .arange (len (dataset ["amr" ]["dx" ]))
122
-
123
- # Select cells in contact with plane
124
- select = np .ravel (np .where (np .abs (dist1 ) <= diagonal ))
125
- global_selection = global_selection [select ]
121
+ global_indices = np .arange (len (dataset ["amr" ]["dx" ]))
122
+ # Select cells in close to the plane, including factor of sqrt(ndim)
123
+ close_to_plane = np .ravel (np .where (np .abs (dist_close ) <= diagonal_close ))
124
+ indices_close_to_plane = global_indices [close_to_plane ]
126
125
127
- if len (select ) == 0 :
126
+ if len (indices_close_to_plane ) == 0 :
128
127
raise RuntimeError ("No cells were selected to construct the plane. "
129
128
"The resulting figure would be empty." )
130
129
131
- # Project coordinates onto the plane by taking dot product with axes vectors
132
- coords = xyz [select ]
133
- datax = np .inner (coords , dir_vecs [1 ])
134
- datay = np .inner (coords , dir_vecs [2 ])
135
- datadx = 0.5 * dataset ["amr" ]["dx" ][select ]
136
-
137
- # Get limits
138
- limits = {
139
- 'xmin' : np .amin (datax - datadx ).values ,
140
- 'xmax' : np .amax (datax + datadx ).values ,
141
- 'ymin' : np .amin (datay - datadx ).values ,
142
- 'ymax' : np .amax (datay + datadx ).values
143
- }
144
-
145
- # Define slice extent
146
- if dx is None :
147
- xmin = limits ['xmin' ]
148
- xmax = limits ['xmax' ]
149
- ymin = limits ['ymin' ]
150
- ymax = limits ['ymax' ]
151
- else :
130
+ xmin = None
131
+ if dx is not None :
152
132
xmin = - 0.5 * dx .magnitude
153
133
xmax = xmin + dx .magnitude
154
134
ymin = - 0.5 * dy .magnitude
155
135
ymax = ymin + dy .magnitude
156
136
# Limit selection further by using distance from center
157
- dist2 = coords - datadx * np .sqrt (dataset .meta ["ndim" ])
158
- select2 = np .ravel (
137
+ radial_distance = xyz [indices_close_to_plane ] - 0.5 * dataset ["amr" ]["dx" ][
138
+ indices_close_to_plane ] * np .sqrt (dataset .meta ["ndim" ])
139
+ radial_selection = np .ravel (
159
140
np .where (
160
- np .abs (dist2 .norm .values ) <= max (dx .magnitude , dy .magnitude ) * 0.6 *
161
- np .sqrt (2.0 )))
162
- coords = coords [select2 ]
163
- datax = datax [select2 ]
164
- datay = datay [select2 ]
165
- datadx = datadx [select2 ]
166
- global_selection = global_selection [select2 ]
141
+ np .abs (radial_distance .norm .values ) <= max (dx .magnitude , dy .magnitude ) *
142
+ 0.6 * np .sqrt (2.0 )))
143
+ indices_close_to_plane = indices_close_to_plane [radial_selection ]
144
+
145
+ # Select cells touching the plane, excluding factor of sqrt(ndim)
146
+ dist_touching = np .sum (xyz [indices_close_to_plane ] * dir_vecs [0 ], axis = 1 )
147
+ diagonal_touching = dataset ["amr" ]["dx" ][indices_close_to_plane ] * 0.5
148
+ touching_plane = np .ravel (np .where (np .abs (dist_touching ) <= diagonal_touching ))
149
+
150
+ # Project coordinates onto the plane by taking dot product with axes vectors
151
+ coords_close = xyz [indices_close_to_plane ]
152
+ datax_close = np .inner (coords_close , dir_vecs [1 ])
153
+ datay_close = np .inner (coords_close , dir_vecs [2 ])
154
+ datadx_close = diagonal_touching
155
+
156
+ if xmin is None :
157
+ xmin = (datax_close - datadx_close ).min ().values
158
+ xmax = (datax_close + datadx_close ).max ().values
159
+ ymin = (datay_close - datadx_close ).min ().values
160
+ ymax = (datay_close + datadx_close ).max ().values
161
+
162
+ datax_touching = datax_close [touching_plane ]
163
+ datay_touching = datay_close [touching_plane ]
167
164
168
165
scalar_layer = []
169
- to_binning = []
166
+ cell_variables = [] # contains the variables in cells close to the plane
167
+ to_binning = [] # a subset of cell_variables for only cells actually touching plane
170
168
for ind in range (len (to_process )):
171
169
if to_render [ind ]["mode" ] in ["vec" , "stream" ]:
172
170
if to_process [ind ].ndim < 3 :
173
- uv = to_process [ind ].array [global_selection ]
171
+ uv = to_process [ind ].array [indices_close_to_plane ]
174
172
else :
175
- uv = np .inner (to_process [ind ].array .take (global_selection , axis = 0 ),
176
- dir_vecs [1 :])
173
+ uv = np .inner (
174
+ to_process [ind ].array .take (indices_close_to_plane , axis = 0 ),
175
+ dir_vecs [1 :])
177
176
w = None
178
177
if "color" in to_render [ind ]["params" ]:
179
178
if isinstance (to_render [ind ]["params" ]["color" ], Array ):
@@ -183,14 +182,22 @@ def plane(*layers,
183
182
if w is None :
184
183
w = np .linalg .norm (uv , axis = 1 )
185
184
else :
186
- w = w .take (global_selection , axis = 0 )
187
- to_binning .append (apply_mask (uv [:, 0 ]))
188
- to_binning .append (apply_mask (uv [:, 1 ]))
189
- to_binning .append (apply_mask (w ))
185
+ w = w .take (indices_close_to_plane , axis = 0 )
186
+ vec_u = apply_mask (uv [:, 0 ])
187
+ vec_v = apply_mask (uv [:, 1 ])
188
+ vec_w = apply_mask (w )
189
+ cell_variables .append (vec_u )
190
+ cell_variables .append (vec_v )
191
+ cell_variables .append (vec_w )
190
192
scalar_layer .append (False )
193
+ to_binning .append (vec_u [touching_plane ])
194
+ to_binning .append (vec_v [touching_plane ])
195
+ to_binning .append (vec_w [touching_plane ])
191
196
else :
192
- to_binning .append (apply_mask (to_process [ind ].norm .values [global_selection ]))
197
+ var = apply_mask (to_process [ind ].norm .values [indices_close_to_plane ])
198
+ cell_variables .append (var )
193
199
scalar_layer .append (True )
200
+ to_binning .append (var [touching_plane ])
194
201
195
202
# Buffer for counts
196
203
to_binning .append (np .ones_like (to_binning [0 ]))
@@ -206,8 +213,8 @@ def plane(*layers,
206
213
ycenters = to_bin_centers (yedges )
207
214
208
215
# First histogram the cell centers into the grid bins
209
- binned , _ , _ , _ = binned_statistic_2d (x = apply_mask (datay .array ),
210
- y = apply_mask (datax .array ),
216
+ binned , _ , _ , _ = binned_statistic_2d (x = apply_mask (datay_touching .array ),
217
+ y = apply_mask (datax_touching .array ),
211
218
values = to_binning ,
212
219
statistic = "mean" ,
213
220
bins = [yedges , xedges ])
@@ -224,10 +231,11 @@ def plane(*layers,
224
231
ygrid .shape + (1 , )) * dir_vecs [2 ]
225
232
# We only need to search in the cells above a certain size
226
233
large_cells = np .ravel (
227
- np .where (datadx >= 0.25 * (min (xedges [1 ] - xedges [0 ], yedges [1 ] - yedges [0 ]))))
228
- coords = coords [large_cells ]
229
- large_cells_dx = datadx .array [large_cells ]
230
- global_indices = np .arange (len (datadx ))[large_cells ]
234
+ np .where (datadx_close >= 0.25 *
235
+ (min (xedges [1 ] - xedges [0 ], yedges [1 ] - yedges [0 ]))))
236
+ coords = coords_close [large_cells ]
237
+ large_cells_dx = datadx_close .array [large_cells ]
238
+ large_cells_indices = np .arange (len (datadx_close ))[large_cells ]
231
239
232
240
# To keep memory usage down to a minimum, we process the image one column at a time
233
241
for i in range (indices .shape [- 1 ]):
@@ -255,7 +263,7 @@ def plane(*layers,
255
263
inds = np .logical_and .reduce (
256
264
[np .abs (d ) <= large_cells_dx [column ] for d in distance_to_cell ])
257
265
index_found = inds .max (axis = - 1 )
258
- index_value = global_indices [column ][inds .argmax (axis = - 1 )]
266
+ index_value = large_cells_indices [column ][inds .argmax (axis = - 1 )]
259
267
indices [:, i ][index_found ] = index_value [index_found ]
260
268
mask [:, i ][np .logical_and (~ index_found , condition [:, i ])] = True
261
269
else :
@@ -266,13 +274,13 @@ def plane(*layers,
266
274
# Now we fill the arrays to be sent to the renderer, also constructing vectors
267
275
counter = 0
268
276
for ind in range (len (to_render )):
269
- binned [counter ][condition ] = to_binning [counter ][indices ][condition ]
277
+ binned [counter ][condition ] = cell_variables [counter ][indices ][condition ]
270
278
if scalar_layer [ind ]:
271
279
to_render [ind ]["data" ] = ma .masked_where (mask , binned [counter ], copy = False )
272
280
counter += 1
273
281
else :
274
282
for j in range (counter + 1 , counter + 3 ):
275
- binned [j ][condition ] = to_binning [j ][indices ][condition ]
283
+ binned [j ][condition ] = cell_variables [j ][indices ][condition ]
276
284
to_render [ind ]["data" ] = ma .masked_where (mask_vec ,
277
285
np .array ([
278
286
binned [counter ].T ,
@@ -293,11 +301,8 @@ def plane(*layers,
293
301
294
302
# Add scatter layer
295
303
if len (to_scatter ) > 0 :
296
- _add_scatter (datax = datax ,
297
- datay = datay ,
298
- to_scatter = to_scatter ,
304
+ _add_scatter (to_scatter = to_scatter ,
299
305
origin = origin ,
300
- datadx = datadx ,
301
306
dir_vecs = dir_vecs ,
302
307
dx = dx ,
303
308
dy = dy ,
0 commit comments