Utility function for _contour_trace. In ``im`` only one part of the domain has valid values (corresponding to a subdomain where barycentric coordinates are well defined). When computing contours, we need to assign values outside of this domain. We can choose a value either smal
(im, values, colors)
| 269 | |
| 270 | |
| 271 | def _extract_contours(im, values, colors): |
| 272 | """ |
| 273 | Utility function for _contour_trace. |
| 274 | |
| 275 | In ``im`` only one part of the domain has valid values (corresponding |
| 276 | to a subdomain where barycentric coordinates are well defined). When |
| 277 | computing contours, we need to assign values outside of this domain. |
| 278 | We can choose a value either smaller than all the values inside the |
| 279 | valid domain, or larger. This value must be chose with caution so that |
| 280 | no spurious contours are added. For example, if the boundary of the valid |
| 281 | domain has large values and the outer value is set to a small one, all |
| 282 | intermediate contours will be added at the boundary. |
| 283 | |
| 284 | Therefore, we compute the two sets of contours (with an outer value |
| 285 | smaller of larger than all values in the valid domain), and choose |
| 286 | the value resulting in a smaller total number of contours. There might |
| 287 | be a faster way to do this, but it works... |
| 288 | """ |
| 289 | mask_nan = np.isnan(im) |
| 290 | im_min, im_max = ( |
| 291 | im[np.logical_not(mask_nan)].min(), |
| 292 | im[np.logical_not(mask_nan)].max(), |
| 293 | ) |
| 294 | zz_min = np.copy(im) |
| 295 | zz_min[mask_nan] = 2 * im_min |
| 296 | zz_max = np.copy(im) |
| 297 | zz_max[mask_nan] = 2 * im_max |
| 298 | all_contours1, all_values1, all_areas1, all_colors1 = [], [], [], [] |
| 299 | all_contours2, all_values2, all_areas2, all_colors2 = [], [], [], [] |
| 300 | for i, val in enumerate(values): |
| 301 | contour_level1 = measure.find_contours(zz_min, val) |
| 302 | contour_level2 = measure.find_contours(zz_max, val) |
| 303 | all_contours1.extend(contour_level1) |
| 304 | all_contours2.extend(contour_level2) |
| 305 | all_values1.extend([val] * len(contour_level1)) |
| 306 | all_values2.extend([val] * len(contour_level2)) |
| 307 | all_areas1.extend( |
| 308 | [_polygon_area(contour.T[1], contour.T[0]) for contour in contour_level1] |
| 309 | ) |
| 310 | all_areas2.extend( |
| 311 | [_polygon_area(contour.T[1], contour.T[0]) for contour in contour_level2] |
| 312 | ) |
| 313 | all_colors1.extend([colors[i]] * len(contour_level1)) |
| 314 | all_colors2.extend([colors[i]] * len(contour_level2)) |
| 315 | if len(all_contours1) <= len(all_contours2): |
| 316 | return all_contours1, all_values1, all_areas1, all_colors1 |
| 317 | else: |
| 318 | return all_contours2, all_values2, all_areas2, all_colors2 |
| 319 | |
| 320 | |
| 321 | def _add_outer_contour( |
no test coverage detected