@@ -105,19 +105,26 @@ apply: bool
105105exclude: str
106106 Exclude a manipulation from refinement by name.
107107scale: float
108- Apply scale factor. This multiplies the function ordinate by scale.
108+ Apply scale factor.
109+
110+ This multiplies the function ordinate by scale.
109111stretch: float
110- Stretch function grid by a fraction stretch. Specifically, this multiplies the function grid by 1+stretch.
112+ Stretch function grid by a fraction stretch.
113+
114+ This multiplies the function grid by 1+stretch.
111115squeeze: list of float
112116 Squeeze function grid given a polynomial
113- p(x) = squeeze[0]+squeeze[1]*x+...+squeeze[n]*x^n. n is dependent on the number
117+ p(x) = squeeze[0]+squeeze[1]*x+...+squeeze[n]*x^n.
118+
119+ n is dependent on the number
114120 of values in the user-inputted comma-separated list.
115121 The morph transforms the function grid from x to x+p(x).
116122 When this parameter is given, hshift is disabled.
117123 When n>1, stretch is disabled.
118124smear: float
119- Smear the peaks with a Gaussian of width smear. This
120- is done by convolving the function with a Gaussian
125+ Smear the peaks with a Gaussian of width smear.
126+
127+ This is done by convolving the function with a Gaussian
121128 with standard deviation smear. If both smear and
122129 smear_pdf are used, only smear_pdf will be
123130 applied.
@@ -128,6 +135,7 @@ smear_pdf: float
128135 applied.
129136slope: float
130137 Slope of the baseline used in converting from PDF to RDF.
138+
131139 This is used with the option smear_pdf. The slope will
132140 be estimated if not provided.
133141hshift: float
@@ -138,57 +146,119 @@ qdamp: float
138146 Dampen PDF by a factor qdamp.
139147radius: float
140148 Apply characteristic function of sphere with radius
141- given by parameter radius. If pradius is also specified, instead apply
149+ given by parameter radius.
150+
151+ If pradius is also specified, instead apply
142152 characteristic function of spheroid with equatorial
143153 radius radius and polar radius pradius.
144154pradius: float
145155 Apply characteristic function of spheroid with
146156 equatorial radius given by above parameter radius and polar radius pradius.
157+
147158 If only pradius is specified, instead apply
148159 characteristic function of sphere with radius pradius.
149160iradius: float
150161 Apply inverse characteristic function of sphere with
151- radius iradius. If ipradius is also specified, instead
162+ radius iradius.
163+
164+ If ipradius is also specified, instead
152165 apply inverse characteristic function of spheroid with
153166 equatorial radius iradius and polar radius ipradius.
154167ipradius: float
155168 Apply inverse characteristic function of spheroid with
156169 equatorial radius iradius and polar radius ipradius.
170+
157171 If only ipradius is specified, instead apply inverse
158172 characteristic function of sphere with radius ipradius.
159173funcy: tuple (function, dict)
174+ Apply a function to the y-axis of the (two-column) data.
175+
160176 This morph applies the function funcy[0] with parameters given in funcy[1].
161- The function funcy[0] must be a function of both the abscissa and ordinate
162- (e.g. take in at least two inputs with as many additional parameters as needed).
177+ The function funcy[0] take in as parameters both the abscissa and ordinate
178+ (i.e. take in at least two inputs with as many additional parameters as needed).
179+ The y-axis values of the data are then replaced by the return value of funcy[0].
180+
163181 For example, let's start with a two-column table with abscissa x and ordinate y.
164182 let us say we want to apply the function ::
165183
166184 def linear(x, y, a, b, c):
167185 return a * x + b * y + c
168186
169- This function takes in both the abscissa and ordinate on top of three additional
170- parameters a, b, and c. To use the funcy parameter with initial guesses
171- a=1.0, b=2.0, c=3.0, we would pass ``funcy=(linear, {a: 1.0, b: 2.0, c: 3.0}) ``.
172- For an example use-case, see the Python-Specific Morphs section below.
187+ This example function above takes in both the abscissa and ordinate on top of
188+ three additional parameters a, b, and c.
189+ To use the funcy parameter with parameter values a=1.0, b=2.0, and c=3.0,
190+ we would pass ``funcy=(linear, {"a": 1.0, "b": 2.0, "c": 3.0}) ``.
191+ For an explicit example, see the Python-Specific Morphs section below.
192+ funcx: tuple (function, dict)
193+ Apply a function to the x-axis of the (two-column) data.
194+
195+ This morph applies the function funcx[0] with parameters given in funcx[1].
196+ The function funcx[0] take in as parameters both the abscissa and ordinate
197+ (i.e. take in at least two inputs with as many additional parameters as needed).
198+ The x-axis values of the data are then replaced by the return value of funcx[0].
199+ Note that diffpy.morph requires the x-axis be monotonic increasing
200+ (i.e. for i < j, x[i] < x[j]): as such,
201+ if funcx[0] is not a monotonic increasing function of the provided x-axis data,
202+ the error ``x must be a strictly increasing sequence `` will be thrown.
173203
204+ For example, let's start with a two-column table with abscissa x and ordinate y.
205+ let us say we want to apply the function ::
206+
207+ def exponential(x, y, amp, decay):
208+ return abs(amp) * (1 - 2**(-decay * x))
209+
210+ This example function above takes in both the abscissa and ordinate on top of
211+ three additional parameters amp and decay.
212+ (Even though the ordinate is not used in the function,
213+ it is still required that the function take in both acscissa and ordinate.)
214+ To use the funcx parameter with parameter values amp=1.0 and decay=2.0,
215+ we would pass ``funcx=(exponential, {"amp": 1.0, "decay:: 2.0}) ``.
216+ For an explicit example, see the Python-Specific Morphs section below.
217+ funcxy: tuple (function, dict)
218+ Apply a function the (two-column) data.
219+
220+ This morph applies the function funcxy[0] with parameters given in funcxy[1].
221+ The function funcxy[0] take in as parameters both the abscissa and ordinate
222+ (i.e. take in at least two inputs with as many additional parameters as needed).
223+ The two columns of the data are then replaced by the two return values of funcxy[0].
224+
225+ For example, let's start with a two-column table with abscissa x and ordinate y.
226+ let us say we want to apply the function ::
227+
228+ def shift(x, y, hshift, vshift):
229+ return x + hshift, y + vshift
230+
231+ This example function above takes in both the abscissa and ordinate on top of
232+ two additional parameters hshift and vshift.
233+ To use the funcy parameter with parameter values hshift=1.0 and vshift=2.0,
234+ we would pass ``funcy=(shift, {"hshift": 1.0, "vshift": 1.0}) ``.
235+ For an example use-case, see the Python-Specific Morphs section below.
174236
175237Python-Specific Morphs
176238======================
177239
178240Some morphs in ``diffpy.morph `` are supported only in Python. Here, we detail
179241how they are used and how to call them.
180242
181- MorphFuncy : Applying custom functions
243+ MorphFunc : Applying custom functions
182244-------------------------------------
183245
246+ In these tutorial, we walk through how to use the ``MorphFunc `` morphs
247+ (``MorphFuncy ``, ``MorphFuncx ``, ``MorphFuncxy ``)
248+ with some example transformations.
249+
250+ Unlike other morphs that can be run from the command line,
251+ ``MorphFunc `` moprhs require a Python function and is therefore
252+ intended to be used through Python scripting.
253+
254+ MorphFuncy:
255+ ^^^^^^^^^^^
256+
184257The ``MorphFuncy `` morph allows users to apply a custom Python function
185258to the y-axis values of a dataset, enabling flexible and user-defined
186259transformations.
187260
188- In this tutorial, we walk through how to use ``MorphFuncy `` with an example
189- transformation. Unlike other morphs that can be run from the command line,
190- ``MorphFuncy `` requires a Python function and is therefore intended to be used
191- through Python scripting.
261+ Let's try out this morph!
192262
193263 1. Import the necessary modules into your Python script:
194264
@@ -229,7 +299,7 @@ through Python scripting.
229299
230300 .. code-block :: python
231301
232- morph_params, morph_table = morph_arrays(np.array([x_morph, y_morph]).T,np.array([x_target, y_target]).T,
302+ morph_params, morph_table = morph_arrays(np.array([x_morph, y_morph]).T, np.array([x_target, y_target]).T,
233303 funcy = (linear_function,{' scale' : 1.2 , ' offset' : 0.1 }))
234304
235305 5. Extract the fitted parameters from the result:
@@ -245,3 +315,85 @@ to generate the target (scale=20 & offset=0.8). This example shows how
245315``MorphFuncy `` can be used to fit and apply custom transformations. Now
246316it's your turn to experiment with other custom functions that may be useful
247317for analyzing your data.
318+
319+ MorphFuncx:
320+ ^^^^^^^^^^^
321+
322+ The ``MorphFuncx `` morph allows users to apply a custom Python function
323+ to the x-axis values of a dataset, similar to the ``MorphFuncy `` morph.
324+
325+ One caveat to this morph is that the x-axis values must remain monotonic
326+ increasing, so it is possible to run into errors when applying this morph.
327+ For example, if your initial grid is ``[-1, 0, 1] ``, and your function is
328+ ``lambda x, y: x**2 ``, the grid after the function is applied will be
329+ ``[1, 0, 1] ``, which is no longer monotonic increasing.
330+ In this case, the error ``x must be a strictly increasing sequence ``
331+ will be thrown.
332+
333+ Let's try out this morph!
334+
335+ 1. Import the necessary modules into your Python script:
336+
337+ .. code-block :: python
338+
339+ from diffpy.morph.morphpy import morph_arrays
340+ import numpy as np
341+
342+ 2. Define a custom Python function to apply a transformation to the data.
343+ The function must take ``x `` and ``y `` (1D arrays of the same length)
344+ along with named parameters, and return a transformed ``x `` array of the
345+ same length. Recall that this function must maintain the monotonic
346+ increasing nature of the ``x `` array.
347+
348+ For this example, we will use a simple exponential function transformation that
349+ greatly modifies the input:
350+
351+ .. code-block :: python
352+
353+ def exp_function (x , y , scale , rate ):
354+ return np.abs(scale) * np.exp(np.abs(rate) * x)
355+
356+ Notice that, though the function only uses the ``x `` input,
357+ the function signature takes in both ``x `` and ``y ``.
358+
359+ 3. Like in the previous example, we will use a sine function for the morph
360+ data and generate the target data by applying the decay transfomration
361+ with a known scale and rate:
362+
363+ .. code-block :: python
364+
365+ x_morph = np.linspace(0 , 10 , 1001 )
366+ y_morph = np.sin(x_morph)
367+ x_target = x_target = 20 * np.exp(0.8 * x_morph)
368+ y_target = y_morph.copy()
369+
370+ 4. Setup and run the morph using the ``morph_arrays(...) ``.
371+ ``morph_arrays `` expects the morph and target data as **2D arrays ** in
372+ *two-column * format ``[[x0, y0], [x1, y1], ...] ``. This will apply
373+ the user-defined function and refine the parameters to best align the
374+ morph data with the target data. This includes both the transformation
375+ parameters (our initial guess) and the transformation function itself:
376+
377+ .. code-block :: python
378+
379+ morph_params, morph_table = morph_arrays(np.array([x_morph, y_morph]).T, np.array([x_target, y_target]).T,
380+ funcx = (decay_function, {' scale' : 1.2 , ' rate' : 1.0 }))
381+
382+ 5. Extract the fitted parameters from the result:
383+
384+ .. code-block :: python
385+
386+ fitted_params = morph_params[" funcx" ]
387+ print (f " Fitted scale: { fitted_params[' scale' ]} " )
388+ print (f " Fitted rate: { fitted_params[' rate' ]} " )
389+
390+ Again, we should see that the fitted scale and offset values match the ones used
391+ to generate the target (scale=20 & rate=0.8).
392+
393+ For fun, you can plot the original function to the morphed function to see
394+ how much the
395+
396+ MorphFuncxy:
397+ ^^^^^^^^^^^^
398+ The ``MorphFuncxy `` morph allows users to apply a custom Python function
399+ to a dataset, ***.
0 commit comments