| 2851 | return self.tick_values(vmin, vmax) |
| 2852 | |
| 2853 | def tick_values(self, vmin, vmax): |
| 2854 | # Construct a set of uniformly-spaced "on-screen" locations. |
| 2855 | ymin, ymax = self.linear_width * np.arcsinh(np.array([vmin, vmax]) |
| 2856 | / self.linear_width) |
| 2857 | ys = np.linspace(ymin, ymax, self.numticks) |
| 2858 | zero_dev = abs(ys / (ymax - ymin)) |
| 2859 | if ymin * ymax < 0: |
| 2860 | # Ensure that the zero tick-mark is included, if the axis straddles zero. |
| 2861 | ys = np.hstack([ys[(zero_dev > 0.5 / self.numticks)], 0.0]) |
| 2862 | |
| 2863 | # Transform the "on-screen" grid to the data space: |
| 2864 | xs = self.linear_width * np.sinh(ys / self.linear_width) |
| 2865 | zero_xs = (ys == 0) |
| 2866 | |
| 2867 | # Round the data-space values to be intuitive base-n numbers, keeping track of |
| 2868 | # positive and negative values separately and carefully treating the zero value. |
| 2869 | with np.errstate(divide="ignore"): # base ** log(0) = base ** -inf = 0. |
| 2870 | if self.base > 1: |
| 2871 | pows = (np.sign(xs) |
| 2872 | * self.base ** np.floor(np.log(abs(xs)) / math.log(self.base))) |
| 2873 | qs = np.outer(pows, self.subs).flatten() if self.subs else pows |
| 2874 | else: # No need to adjust sign(pows), as it cancels out when computing qs. |
| 2875 | pows = np.where(zero_xs, 1, 10**np.floor(np.log10(abs(xs)))) |
| 2876 | qs = pows * np.round(xs / pows) |
| 2877 | ticks = np.array(sorted(set(qs))) |
| 2878 | |
| 2879 | return ticks if len(ticks) >= 2 else np.linspace(vmin, vmax, self.numticks) |
| 2880 | |
| 2881 | |
| 2882 | class LogitLocator(MaxNLocator): |