@@ -94,6 +94,96 @@ def get_transform(self):
9494 return IdentityTransform ()
9595
9696
97+ class FuncTransform (Transform ):
98+ """
99+ A simple transform that takes and arbitrary function for the
100+ forward and inverse transform.
101+ """
102+
103+ input_dims = 1
104+ output_dims = 1
105+ is_separable = True
106+ has_inverse = True
107+
108+ def __init__ (self , forward , inverse ):
109+ """
110+ Parameters
111+ ----------
112+
113+ forward: callable
114+ The forward function for the transform. This function must have
115+ an inverse and, for best behavior, be monotonic.
116+ It must have the signature::
117+
118+ def forward(values: array-like) -> array-like
119+
120+ inverse: callable
121+ The inverse of the forward function. Signature as ``forward``.
122+ """
123+ super ().__init__ ()
124+ if callable (forward ) and callable (inverse ):
125+ self ._forward = forward
126+ self ._inverse = inverse
127+ else :
128+ raise ValueError ('arguments to FuncTransform must '
129+ 'be functions' )
130+
131+ def transform_non_affine (self , values ):
132+ return self ._forward (values )
133+
134+ def inverted (self ):
135+ return FuncTransform (self ._inverse , self ._forward )
136+
137+
138+ class FuncScale (ScaleBase ):
139+ """
140+ Provide an arbitrary scale with user-supplied function for the axis.
141+ """
142+
143+ name = 'function'
144+
145+ def __init__ (self , axis , functions ):
146+ """
147+ Parameters
148+ ----------
149+
150+ axis: the axis for the scale
151+
152+ functions: (callable, callable)
153+ two-tuple of the forward and inverse functions for the scale.
154+ The forward function must have an inverse and, for best behavior,
155+ be monotonic.
156+
157+ Both functions must have the signature::
158+
159+ def forward(values: array-like) -> array-like
160+ """
161+ forward , inverse = functions
162+ transform = FuncTransform (forward , inverse )
163+ self ._transform = transform
164+
165+ def get_transform (self ):
166+ """
167+ The transform for arbitrary scaling
168+ """
169+ return self ._transform
170+
171+ def set_default_locators_and_formatters (self , axis ):
172+ """
173+ Set the locators and formatters to the same defaults as the
174+ linear scale.
175+ """
176+ axis .set_major_locator (AutoLocator ())
177+ axis .set_major_formatter (ScalarFormatter ())
178+ axis .set_minor_formatter (NullFormatter ())
179+ # update the minor locator for x and y axis based on rcParams
180+ if (axis .axis_name == 'x' and rcParams ['xtick.minor.visible' ]
181+ or axis .axis_name == 'y' and rcParams ['ytick.minor.visible' ]):
182+ axis .set_minor_locator (AutoMinorLocator ())
183+ else :
184+ axis .set_minor_locator (NullLocator ())
185+
186+
97187class LogTransformBase (Transform ):
98188 input_dims = 1
99189 output_dims = 1
@@ -557,6 +647,7 @@ def limit_range_for_scale(self, vmin, vmax, minpos):
557647 'log' : LogScale ,
558648 'symlog' : SymmetricalLogScale ,
559649 'logit' : LogitScale ,
650+ 'function' : FuncScale ,
560651 }
561652
562653
0 commit comments