| 490 | |
| 491 | |
| 492 | class SymmetricalLogTransform(Transform): |
| 493 | input_dims = output_dims = 1 |
| 494 | |
| 495 | def __init__(self, base, linthresh, linscale): |
| 496 | super().__init__() |
| 497 | if base <= 1.0: |
| 498 | raise ValueError("'base' must be larger than 1") |
| 499 | if linthresh <= 0.0: |
| 500 | raise ValueError("'linthresh' must be positive") |
| 501 | if linscale <= 0.0: |
| 502 | raise ValueError("'linscale' must be positive") |
| 503 | self.base = base |
| 504 | self.linthresh = linthresh |
| 505 | self.linscale = linscale |
| 506 | |
| 507 | def transform_non_affine(self, values): |
| 508 | linscale_adj = self.linscale / (1.0 - 1.0 / self.base) |
| 509 | log_base = np.log(self.base) |
| 510 | |
| 511 | abs_a = np.abs(values) |
| 512 | inside = abs_a <= self.linthresh |
| 513 | if np.all(inside): # Fast path: all values in linear region |
| 514 | return values * linscale_adj |
| 515 | with np.errstate(divide="ignore", invalid="ignore"): |
| 516 | out = np.sign(values) * self.linthresh * ( |
| 517 | linscale_adj - np.log(self.linthresh) / log_base + |
| 518 | np.log(abs_a) / log_base) |
| 519 | out[inside] = values[inside] * linscale_adj |
| 520 | return out |
| 521 | |
| 522 | def inverted(self): |
| 523 | return InvertedSymmetricalLogTransform(self.base, self.linthresh, |
| 524 | self.linscale) |
| 525 | |
| 526 | |
| 527 | class InvertedSymmetricalLogTransform(Transform): |
no outgoing calls
searching dependent graphs…