@@ -150,15 +150,6 @@ ipradius: float
150150 equatorial radius iradius and polar radius ipradius.
151151 If only ipradius is specified, instead apply inverse
152152 characteristic function of sphere with radius ipradius.
153- funcy: tuple (function, dict)
154- See Python-Specific Morphs below.
155-
156- Python-Specific Morphs
157- ======================
158-
159- Some morphs in ``diffpy.morph `` are supported only in Python. Here, we detail
160- how they are used and how to call them.
161-
162153funcy: tuple (function, dict)
163154 This morph applies the function funcy[0] with parameters given in funcy[1].
164155 The function funcy[0] must be a function of both the abscissa and ordinate
@@ -172,3 +163,90 @@ funcy: tuple (function, dict)
172163 This function takes in both the abscissa and ordinate on top of three additional
173164 parameters a, b, and c. To use the funcy parameter with initial guesses
174165 a=1.0, b=2.0, c=3.0, we would pass ``funcy=(linear, {a: 1.0, b: 2.0, c: 3.0}) ``.
166+ For an example use-case, see the Python-Specific Morphs section below.
167+
168+
169+ Python-Specific Morphs
170+ ======================
171+
172+ Some morphs in ``diffpy.morph `` are supported only in Python. Here, we detail
173+ how they are used and how to call them.
174+
175+ MorphFuncy: Applying custom functions
176+ -------------------------------------
177+
178+ The ``MorphFuncy `` morph allows users to apply a custom Python function
179+ to the y-axis values of a dataset, enabling flexible and user-defined
180+ transformations.
181+
182+ In this tutorial, we walk through how to use ``MorphFuncy `` with an example
183+ transformation. Unlike other morphs that can be run from the command line,
184+ ``MorphFuncy `` requires a Python function and is therefore intended to be used
185+ through Python scripting.
186+
187+ 1. Import the necessary modules into your Python script:
188+
189+ .. code-block :: python
190+
191+ from diffpy.morph.morph_api import morph, morph_default_config
192+ import numpy as np
193+
194+ 2. Define a custom Python function to apply a transformation to the data.
195+ The function must take ``x `` and ``y `` (1D arrays of the same length)
196+ along with named parameters, and return a transformed ``y `` array of the
197+ same length.
198+ For this example, we will use a simple linear transformation that
199+ scales the input and applies an offset:
200+
201+ .. code-block :: python
202+
203+ def linear_function (x , y , scale , offset ):
204+ return (scale * x) * y + offset
205+
206+ 3. In this example, we use a sine function for the morph data and generate
207+ the target data by applying the linear transformation with known scale
208+ and offset to it:
209+
210+ .. code-block :: python
211+
212+ x_morph = np.linspace(0 , 10 , 101 )
213+ y_morph = np.sin(x_morph)
214+ x_target = x_morph.copy()
215+ y_target = np.sin(x_target) * 20 * x_target + 0.8
216+
217+ 4. Set up the morph configuration dictionary. This includes both the
218+ transformation parameters (our initial guess) and the transformation
219+ function itself:
220+
221+ .. code-block :: python
222+
223+ morph_config = morph_default_config(funcy = {" scale" : 1.2 , " offset" : 0.1 })
224+ morph_config[" function" ] = linear_function
225+
226+ # morph_config now contains:
227+ # {'funcy': {'scale': 1.2, 'offset': 0.1}, 'function': linear_function}
228+
229+ 5. Run the morph using the ``morph(...) ``. This will apply the user-defined
230+ function and refine the parameters to best align the morph data
231+ with the target data:
232+
233+ .. code-block :: python
234+
235+ morph_result = morph(x_morph, y_morph, x_target, y_target, ** morph_config)
236+
237+ 6. Extract the morphed output and the fitted parameters from the result:
238+
239+ .. code-block :: python
240+
241+ fitted_config = morph_result[" morphed_config" ]
242+ x_morph_out, y_morph_out, x_target_out, y_target_out = morph_result[" morph_chain" ].xyallout
243+
244+ fitted_params = fitted_config[" funcy" ]
245+ print (f " Fitted scale: { fitted_params[' scale' ]} " )
246+ print (f " Fitted offset: { fitted_params[' offset' ]} " )
247+
248+ As you can see, the fitted scale and offset values match the ones used
249+ to generate the target (scale=20 & offset=0.8). This example shows how
250+ ``MorphFuncy `` can be used to fit and apply custom transformations. Now
251+ it's your turn to experiment with other custom functions that may be useful
252+ for analyzing your data.
0 commit comments