|
12 | 12 | importnumpyasnp
|
13 | 13 |
|
14 | 14 | importmatplotlibasmpl
|
15 |
| -from .import_api,cbook |
16 |
| -from .colorsimportBoundaryNorm |
| 15 | +from .import_api,cbook,cm |
17 | 16 | from .cmimportScalarMappable
|
18 | 17 | from .pathimportPath
|
19 | 18 | from .transformsimport (BboxBase,Bbox,IdentityTransform,Transform,TransformedBbox,
|
@@ -1346,35 +1345,16 @@ def format_cursor_data(self, data):
|
1346 | 1345 | --------
|
1347 | 1346 | get_cursor_data
|
1348 | 1347 | """
|
1349 |
| -ifnp.ndim(data)==0andisinstance(self,ScalarMappable): |
| 1348 | +ifisinstance(self,ScalarMappable): |
| 1349 | +# Internal classes no longer inherit from ScalarMappable, and this |
| 1350 | +# block should never be executed by the internal API |
| 1351 | + |
1350 | 1352 | # This block logically belongs to ScalarMappable, but can't be
|
1351 |
| -# implemented in itbecause mostScalarMappable subclasses inherit |
1352 |
| -# from Artist first and from ScalarMappable second, so |
| 1353 | +# implemented in itin case customScalarMappable subclasses |
| 1354 | +#inheritfrom Artist first and from ScalarMappable second, so |
1353 | 1355 | # Artist.format_cursor_data would always have precedence over
|
1354 | 1356 | # ScalarMappable.format_cursor_data.
|
1355 |
| -n=self.cmap.N |
1356 |
| -ifnp.ma.getmask(data): |
1357 |
| -return"[]" |
1358 |
| -normed=self.norm(data) |
1359 |
| -ifnp.isfinite(normed): |
1360 |
| -ifisinstance(self.norm,BoundaryNorm): |
1361 |
| -# not an invertible normalization mapping |
1362 |
| -cur_idx=np.argmin(np.abs(self.norm.boundaries-data)) |
1363 |
| -neigh_idx=max(0,cur_idx-1) |
1364 |
| -# use max diff to prevent delta == 0 |
1365 |
| -delta=np.diff( |
1366 |
| -self.norm.boundaries[neigh_idx:cur_idx+2] |
1367 |
| - ).max() |
1368 |
| - |
1369 |
| -else: |
1370 |
| -# Midpoints of neighboring color intervals. |
1371 |
| -neighbors=self.norm.inverse( |
1372 |
| - (int(normed*n)+np.array([0,1]))/n) |
1373 |
| -delta=abs(neighbors-data).max() |
1374 |
| -g_sig_digits=cbook._g_sig_digits(data,delta) |
1375 |
| -else: |
1376 |
| -g_sig_digits=3# Consistent with default below. |
1377 |
| -returnf"[{data:-#.{g_sig_digits}g}]" |
| 1357 | +returnself.colorizer._format_cursor_data(data) |
1378 | 1358 | else:
|
1379 | 1359 | try:
|
1380 | 1360 | data[0]
|
@@ -1417,6 +1397,126 @@ def set_mouseover(self, mouseover):
|
1417 | 1397 | mouseover=property(get_mouseover,set_mouseover)# backcompat.
|
1418 | 1398 |
|
1419 | 1399 |
|
| 1400 | +classColorizingArtist(Artist): |
| 1401 | +def__init__(self,norm=None,cmap=None): |
| 1402 | +""" |
| 1403 | + Parameters |
| 1404 | + ---------- |
| 1405 | + norm : `.Normalize` (or subclass thereof) or str or None |
| 1406 | + The normalizing object which scales data, typically into the |
| 1407 | + interval ``[0, 1]``. |
| 1408 | + If a `str`, a `.Normalize` subclass is dynamically generated based |
| 1409 | + on the scale with the corresponding name. |
| 1410 | + If *None*, *norm* defaults to a *colors.Normalize* object which |
| 1411 | + initializes its scaling based on the first data processed. |
| 1412 | + cmap : str or `~matplotlib.colors.Colormap` |
| 1413 | + The colormap used to map normalized data values to RGBA colors. |
| 1414 | + """ |
| 1415 | + |
| 1416 | +Artist.__init__(self) |
| 1417 | + |
| 1418 | +self._A=None |
| 1419 | +ifisinstance(norm,cm.Colorizer): |
| 1420 | +self._colorizer=norm |
| 1421 | +else: |
| 1422 | +self._colorizer=cm.Colorizer(cmap,norm) |
| 1423 | + |
| 1424 | +self._id_colorizer=self.colorizer.callbacks.connect('changed',self.changed) |
| 1425 | +self.callbacks=cbook.CallbackRegistry(signals=["changed"]) |
| 1426 | + |
| 1427 | +defset_array(self,A): |
| 1428 | +""" |
| 1429 | + Set the value array from array-like *A*. |
| 1430 | +
|
| 1431 | + Parameters |
| 1432 | + ---------- |
| 1433 | + A : array-like or None |
| 1434 | + The values that are mapped to colors. |
| 1435 | +
|
| 1436 | + The base class `.VectorMappable` does not make any assumptions on |
| 1437 | + the dimensionality and shape of the value array *A*. |
| 1438 | + """ |
| 1439 | +ifAisNone: |
| 1440 | +self._A=None |
| 1441 | +return |
| 1442 | +A=cm._ensure_multivariate_data(self.colorizer.cmap.n_variates,A) |
| 1443 | + |
| 1444 | +A=cbook.safe_masked_invalid(A,copy=True) |
| 1445 | +ifnotnp.can_cast(A.dtype,float,"same_kind"): |
| 1446 | +ifA.dtype.fieldsisNone: |
| 1447 | +raiseTypeError(f"Image data of dtype{A.dtype} cannot be " |
| 1448 | +f"converted to float") |
| 1449 | +else: |
| 1450 | +forkeyinA.dtype.fields: |
| 1451 | +ifnotnp.can_cast(A[key].dtype,float,"same_kind"): |
| 1452 | +raiseTypeError(f"Image data of dtype{A.dtype} cannot be " |
| 1453 | +f"converted to a sequence of floats") |
| 1454 | +self._A=A |
| 1455 | +self.colorizer.autoscale_None(A) |
| 1456 | + |
| 1457 | +defget_array(self): |
| 1458 | +""" |
| 1459 | + Return the array of values, that are mapped to colors. |
| 1460 | +
|
| 1461 | + The base class `.VectorMappable` does not make any assumptions on |
| 1462 | + the dimensionality and shape of the array. |
| 1463 | + """ |
| 1464 | +returnself._A |
| 1465 | + |
| 1466 | +@property |
| 1467 | +defcolorizer(self): |
| 1468 | +returnself._colorizer |
| 1469 | + |
| 1470 | +@colorizer.setter |
| 1471 | +defcolorizer(self,colorizer): |
| 1472 | +self._set_colorizer(colorizer) |
| 1473 | + |
| 1474 | +def_set_colorizer(self,colorizer): |
| 1475 | +ifisinstance(colorizer,cm.Colorizer): |
| 1476 | +ifself._AisnotNone: |
| 1477 | +ifnotcolorizer.cmap.n_variates==self.colorizer.cmap.n_variates: |
| 1478 | +raiseValueError('The new Colorizer object must have the same' |
| 1479 | +' number of variates as the existing data.') |
| 1480 | +else: |
| 1481 | +self.colorizer.callbacks.disconnect(self._id_colorizer) |
| 1482 | +self._colorizer=colorizer |
| 1483 | +self._id_colorizer=colorizer.callbacks.connect('changed', |
| 1484 | +self.changed) |
| 1485 | +self.changed() |
| 1486 | +else: |
| 1487 | +raiseValueError('Only a Colorizer object can be set to colorizer.') |
| 1488 | + |
| 1489 | +def_get_colorizer(self): |
| 1490 | +""" |
| 1491 | + Function to get the colorizer. |
| 1492 | + Useful in edge cases where you want a standalone variable with the colorizer, |
| 1493 | + but also want the colorizer to update if the colorizer on the artist changes. |
| 1494 | +
|
| 1495 | + used in `contour.ContourLabeler.label_colorizer` |
| 1496 | + """ |
| 1497 | +returnself._colorizer |
| 1498 | + |
| 1499 | +defchanged(self): |
| 1500 | +""" |
| 1501 | + Call this whenever the mappable is changed to notify all the |
| 1502 | + callbackSM listeners to the 'changed' signal. |
| 1503 | + """ |
| 1504 | +self.callbacks.process('changed') |
| 1505 | +self.stale=True |
| 1506 | + |
| 1507 | +defformat_cursor_data(self,data): |
| 1508 | +""" |
| 1509 | + Return a string representation of *data*. |
| 1510 | +
|
| 1511 | + Uses the colorbar's formatter to format the data. |
| 1512 | +
|
| 1513 | + See Also |
| 1514 | + -------- |
| 1515 | + get_cursor_data |
| 1516 | + """ |
| 1517 | +returnself.colorizer._format_cursor_data(data) |
| 1518 | + |
| 1519 | + |
1420 | 1520 | def_get_tightbbox_for_layout_only(obj,*args,**kwargs):
|
1421 | 1521 | """
|
1422 | 1522 | Matplotlib's `.Axes.get_tightbbox` and `.Axis.get_tightbbox` support a
|
|