|
23 | 23 | from matplotlib.ticker import ( |
24 | 24 | NullFormatter, ScalarFormatter, LogFormatterSciNotation, LogitFormatter, |
25 | 25 | Locator, NullLocator, LogLocator, AutoLocator, AutoMinorLocator, |
26 | | - SymmetricalLogLocator, LogitLocator) |
| 26 | + SymmetricalLogLocator, AsinhLocator, LogitLocator) |
27 | 27 | from matplotlib.transforms import Transform, IdentityTransform |
28 | 28 |
|
29 | 29 |
|
@@ -458,6 +458,34 @@ def get_transform(self): |
458 | 458 | return self._transform |
459 | 459 |
|
460 | 460 |
|
| 461 | +class AsinhTransform(Transform): |
| 462 | + input_dims = output_dims = 1 |
| 463 | + |
| 464 | + def __init__(self, linear_width): |
| 465 | + super().__init__() |
| 466 | + self.linear_width = linear_width |
| 467 | + |
| 468 | + def transform_non_affine(self, a): |
| 469 | + return self.linear_width * np.arcsinh(a / self.linear_width) |
| 470 | + |
| 471 | + def inverted(self): |
| 472 | + return InvertedAsinhTransform(self.linear_width) |
| 473 | + |
| 474 | + |
| 475 | +class InvertedAsinhTransform(Transform): |
| 476 | + input_dims = output_dims = 1 |
| 477 | + |
| 478 | + def __init__(self, linear_width): |
| 479 | + super().__init__() |
| 480 | + self.linear_width = linear_width |
| 481 | + |
| 482 | + def transform_non_affine(self, a): |
| 483 | + return self.linear_width * np.sinh(a / self.linear_width) |
| 484 | + |
| 485 | + def inverted(self): |
| 486 | + return AsinhTransform(self.linear_width) |
| 487 | + |
| 488 | + |
461 | 489 | class AsinhScale(ScaleBase): |
462 | 490 | """ |
463 | 491 | A quasi-logarithmic scale based on the inverse hyperbolic sine (asinh) |
@@ -494,89 +522,12 @@ def __init__(self, axis, *, linear_width=1.0, **kwargs): |
494 | 522 | self.linear_width = linear_width |
495 | 523 |
|
496 | 524 | def get_transform(self): |
497 | | - return self.AsinhTransform(self.linear_width) |
| 525 | + return AsinhTransform(self.linear_width) |
498 | 526 |
|
499 | 527 | def set_default_locators_and_formatters(self, axis): |
500 | | - axis.set(major_locator=AsinhScale.AsinhLocator(self.linear_width), |
| 528 | + axis.set(major_locator=AsinhLocator(self.linear_width), |
501 | 529 | major_formatter='{x:.3g}') |
502 | 530 |
|
503 | | - class AsinhTransform(Transform): |
504 | | - input_dims = output_dims = 1 |
505 | | - |
506 | | - def __init__(self, linear_width): |
507 | | - super().__init__() |
508 | | - self.linear_width = linear_width |
509 | | - |
510 | | - def transform_non_affine(self, a): |
511 | | - return self.linear_width * np.arcsinh(a / self.linear_width) |
512 | | - |
513 | | - def inverted(self): |
514 | | - return AsinhScale.InvertedAsinhTransform(self.linear_width) |
515 | | - |
516 | | - class InvertedAsinhTransform(Transform): |
517 | | - input_dims = output_dims = 1 |
518 | | - |
519 | | - def __init__(self, linear_width): |
520 | | - super().__init__() |
521 | | - self.linear_width = linear_width |
522 | | - |
523 | | - def transform_non_affine(self, a): |
524 | | - return self.linear_width * np.sinh(a / self.linear_width) |
525 | | - |
526 | | - def inverted(self): |
527 | | - return AsinhScale.AsinhTransform(self.linear_width) |
528 | | - |
529 | | - class AsinhLocator(Locator): |
530 | | - """ |
531 | | - An axis tick locator specialized for the arcsinh scale |
532 | | -
|
533 | | - This is very unlikely to have any use beyond the AsinhScale class. |
534 | | - """ |
535 | | - def __init__(self, linear_width, numticks=12): |
536 | | - """ |
537 | | - Parameters |
538 | | - ---------- |
539 | | - linear_width : float |
540 | | - The scale parameter defining the extent |
541 | | - of the quasi-linear region. |
542 | | - numticks : int, default: 12 |
543 | | - The approximate number of major ticks that will fit |
544 | | - along the entire axis |
545 | | - """ |
546 | | - super().__init__() |
547 | | - self.linear_width = linear_width |
548 | | - self.numticks = numticks |
549 | | - |
550 | | - def __call__(self): |
551 | | - dmin, dmax = self.axis.get_data_interval() |
552 | | - return self.tick_values(dmin, dmax) |
553 | | - |
554 | | - def tick_values(self, vmin, vmax): |
555 | | - # Construct a set of "on-screen" locations |
556 | | - # that are uniformly spaced: |
557 | | - ymin, ymax = self.linear_width * np.arcsinh(np.array([vmin, vmax]) / self.linear_width) |
558 | | - ys = np.linspace(ymin, ymax, self.numticks) |
559 | | - if (ymin * ymax) < 0: |
560 | | - # Ensure that the zero tick-mark is included, |
561 | | - # if the axis stradles zero |
562 | | - ys = np.hstack([ys, 0.0]) |
563 | | - |
564 | | - # Transform the "on-screen" grid to the data space: |
565 | | - xs = self.linear_width * np.sinh(ys / self.linear_width) |
566 | | - zero_xs = (xs == 0) |
567 | | - |
568 | | - # Round the data-space values to be intuitive decimal numbers: |
569 | | - decades = ( |
570 | | - np.where(xs >= 0, 1, -1) * |
571 | | - np.power(10, np.where(zero_xs, 1.0, |
572 | | - np.floor(np.log10(np.abs(xs) |
573 | | - + zero_xs*1e-6)))) |
574 | | - ) |
575 | | - qs = decades * np.round(xs / decades) |
576 | | - |
577 | | - return np.array(sorted(set(qs))) |
578 | | - |
579 | | - |
580 | 531 | class LogitTransform(Transform): |
581 | 532 | input_dims = output_dims = 1 |
582 | 533 |
|
|
0 commit comments