@@ -94,6 +94,98 @@ 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) ->
119+ array-likeThe forward function for the transform
120+
121+ inverse: callable
122+ The inverse of the forward function. Signature as ``forward``.
123+ """
124+ super ().__init__ ()
125+ if callable (forward ) and callable (inverse ):
126+ self ._forward = forward
127+ self ._inverse = inverse
128+ else :
129+ raise ValueError ('arguments to FuncTransform must '
130+ 'be functions' )
131+
132+ def transform_non_affine (self , values ):
133+ return self ._forward (values )
134+
135+ def inverted (self ):
136+ return FuncTransform (self ._inverse , self ._forward )
137+
138+
139+ class FuncScale (ScaleBase ):
140+ """
141+ Provide an arbitrary scale with user-supplied function for the axis.
142+ """
143+
144+ name = 'function'
145+
146+ def __init__ (self , axis , functions ):
147+ """
148+ Parameters
149+ ----------
150+
151+ axis: the axis for the scale
152+
153+ functions: (callable, callable)
154+ two-tuple of the forward and inverse functions for the scale.
155+ The forward function must have an inverse and, for best behavior,
156+ be monotonic.
157+
158+ Both functions must have the signature::
159+
160+ def forward(values: array-like) ->
161+ array-likeThe forward function for the transform
162+ """
163+ forward , inverse = functions
164+ transform = FuncTransform (forward , inverse )
165+ self ._transform = transform
166+
167+ def get_transform (self ):
168+ """
169+ The transform for arbitrary scaling
170+ """
171+ return self ._transform
172+
173+ def set_default_locators_and_formatters (self , axis ):
174+ """
175+ Set the locators and formatters to the same defaults as the
176+ linear scale.
177+ """
178+ axis .set_major_locator (AutoLocator ())
179+ axis .set_major_formatter (ScalarFormatter ())
180+ axis .set_minor_formatter (NullFormatter ())
181+ # update the minor locator for x and y axis based on rcParams
182+ if (axis .axis_name == 'x' and rcParams ['xtick.minor.visible' ]
183+ or axis .axis_name == 'y' and rcParams ['ytick.minor.visible' ]):
184+ axis .set_minor_locator (AutoMinorLocator ())
185+ else :
186+ axis .set_minor_locator (NullLocator ())
187+
188+
97189class LogTransformBase (Transform ):
98190 input_dims = 1
99191 output_dims = 1
@@ -557,6 +649,7 @@ def limit_range_for_scale(self, vmin, vmax, minpos):
557649 'log' : LogScale ,
558650 'symlog' : SymmetricalLogScale ,
559651 'logit' : LogitScale ,
652+ 'function' : FuncScale ,
560653 }
561654
562655
0 commit comments