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