-
Notifications
You must be signed in to change notification settings - Fork 19
doc/tutorial: adding a tutorial for MorphFuncy and proper docstring #215
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
ed382bb
a7431d9
77d987b
ff368cf
d535e4a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -397,6 +397,67 @@ There is also support for morphing from a nanoparticle to a bulk. When | |
| applying the inverse morphs, it is recommended to set ``--rmax=psize`` | ||
| where ``psize`` is the longest diameter of the nanoparticle. | ||
|
|
||
| MorphFuncy: Applying custom functions | ||
| ------------------------------------- | ||
|
|
||
| The ``MorphFuncy`` morph allows users to apply a custom Python function | ||
| to the y-axis values of a dataset, enabling flexible and user-defined | ||
| transformations. | ||
|
|
||
| In this tutorial, we walk through how to use ``MorphFuncy`` with an example | ||
| transformation. Unlike other morphs that can be run from the command line, | ||
| ``MorphFuncy`` requires a Python function and is therefore intended to be used | ||
| within the Python API. | ||
|
|
||
| 1. Import the necessary modules into your Python script :: | ||
|
|
||
| from diffpy.morph.morph_api import morph, morph_default_config | ||
| import numpy as np | ||
|
|
||
| 2. Define a custom Python function to apply a transformation to the data. | ||
| For this example, we will use a simple linear transformation that | ||
| scales the input and applies an offset :: | ||
|
||
|
|
||
| def linear_function(x, y, scale, offset): | ||
| return (scale * x) * y + offset | ||
|
|
||
| 3. In this example, we use a sine function for the morph data and generate | ||
| the target data by applying the linear transformation with known scale | ||
| and offset to it :: | ||
|
|
||
| x_morph = np.linspace(0, 10, 101) | ||
| y_morph = np.sin(x_morph) | ||
| x_target = x_morph.copy() | ||
| y_target = np.sin(x_target) * 20 * x_target + 0.8 | ||
|
|
||
| 4. Set up the configuration dictionary. This includes both the | ||
| transformation parameters (our initial guess) and the transformation | ||
| function itself :: | ||
|
|
||
| cfg = morph_default_config(funcy={"scale": 1.2, "offset": 0.1}) | ||
|
||
| cfg["function"] = linear_function | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would add a line that shows what the dictionary looks like after it is created in case users want to create it in an editor and not use python code.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Luiskitsu gentle ping on this |
||
| 5. Run the morph using the API function ``morph(...)``. This will apply the | ||
|
||
| user-defined function and refine the parameters to best align the morph data | ||
| with the target data :: | ||
|
|
||
| morph_rv = morph(x_morph, y_morph, x_target, y_target, **cfg) | ||
|
||
|
|
||
| 6. Extract the morphed output and the fitted parameters from the result :: | ||
|
|
||
| morphed_cfg = morph_rv["morphed_config"] | ||
| x_morph_out, y_morph_out, x_target_out, y_target_out = morph_rv["morph_chain"].xyallout | ||
|
|
||
| fitted_parameters = morphed_cfg["funcy"] | ||
| print("Fitted scale:", fitted_parameters["scale"]) | ||
|
||
| print("Fitted offset:", fitted_parameters["offset"]) | ||
|
|
||
| As you can see, the fitted scale and offset values match the ones used | ||
| to generate the target (scale=20 & offset=0.8). This example shows how | ||
| ``MorphFuncy`` can be used to fit and apply custom transformations. Now | ||
| it's your turn to experiment with other custom functions that may be useful | ||
| for analyzing your data. | ||
|
|
||
| Bug Reports | ||
| =========== | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| **Added:** | ||
|
|
||
| * Added a tutorial for MorphFuncy | ||
|
|
||
| **Changed:** | ||
|
|
||
| * Changed docstrings location for MorphFuncy and MorphSqueeze | ||
|
|
||
| **Deprecated:** | ||
|
|
||
| * <news item> | ||
|
|
||
| **Removed:** | ||
|
|
||
| * <news item> | ||
|
|
||
| **Fixed:** | ||
|
|
||
| * <news item> | ||
|
|
||
| **Security:** | ||
|
|
||
| * <news item> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,61 @@ | ||
| """class MorphFuncy -- apply a user-supplied python function to the y-axis.""" | ||
|
|
||
| from diffpy.morph.morphs.morph import LABEL_GR, LABEL_RA, Morph | ||
|
|
||
|
|
||
| class MorphFuncy(Morph): | ||
| """Apply the user-supplied Python function to the y-coordinates of the | ||
| morph data""" | ||
| """General morph function that applies a user-supplied function to the | ||
|
||
| y-coordinates of morph data to make it align with a target. | ||
|
|
||
| Configuration Variables | ||
| ----------------------- | ||
| function: callable | ||
| The user-supplied function that applies a transformation to the | ||
| y-coordinates of the data. | ||
|
|
||
| parameters: dict | ||
| A dictionary of parameters to pass to the function. | ||
| These parameters are unpacked using **kwargs. | ||
|
||
|
|
||
| Returns | ||
| ------- | ||
| A tuple (x_morph_out, y_morph_out, x_target_out, y_target_out) | ||
| where the target values remain the same and the morph data is | ||
| transformed according to the user-specified function and parameters | ||
| The morphed data is returned on the same grid as the unmorphed data | ||
|
|
||
| Example | ||
| ------- | ||
| Import the funcy morph function: | ||
|
|
||
| >>> from diffpy.morph.morphs.morphfuncy import MorphFuncy | ||
|
|
||
| Define or import the user-supplied transformation function: | ||
|
|
||
| >>> def sine_function(x, y, amplitude, frequency): | ||
| >>> return amplitude * np.sin(frequency * x) * y | ||
|
|
||
| Provide initial guess for parameters: | ||
|
|
||
| >>> parameters = {'amplitude': 2, 'frequency': 2} | ||
|
|
||
| Run the funcy morph given input morph array (x_morph, y_morph)and target | ||
| array (x_target, y_target): | ||
|
|
||
| >>> morph = MorphFuncy() | ||
| >>> morph.function = sine_function | ||
| >>> morph.funcy = parameters | ||
| >>> x_morph_out, y_morph_out, x_target_out, y_target_out = | ||
| ... morph.morph(x_morph, y_morph, x_target, y_target) | ||
|
|
||
| To access parameters from the morph instance: | ||
|
|
||
| >>> x_morph_in = morph.x_morph_in | ||
| >>> y_morph_in = morph.y_morph_in | ||
| >>> x_target_in = morph.x_target_in | ||
| >>> y_target_in = morph.y_target_in | ||
| >>> parameters_out = morph.funcy | ||
| """ | ||
|
|
||
| # Define input output types | ||
| summary = "Apply a Python function to the y-axis data" | ||
|
|
@@ -14,53 +66,8 @@ class MorphFuncy(Morph): | |
| parnames = ["funcy"] | ||
|
|
||
| def morph(self, x_morph, y_morph, x_target, y_target): | ||
| """General morph function that applies a user-supplied function to the | ||
| y-coordinates of morph data to make it align with a target. | ||
|
|
||
| Configuration Variables | ||
| ----------------------- | ||
| function: callable | ||
| The user-supplied function that applies a transformation to the | ||
| y-coordinates of the data. | ||
|
|
||
| parameters: dict | ||
| A dictionary of parameters to pass to the function. | ||
| These parameters are unpacked using **kwargs. | ||
|
|
||
| Returns | ||
| ------- | ||
| A tuple (x_morph_out, y_morph_out, x_target_out, y_target_out) | ||
| where the target values remain the same and the morph data is | ||
| transformed according to the user-specified function and parameters | ||
| The morphed data is returned on the same grid as the unmorphed data | ||
|
|
||
| Example | ||
| ------- | ||
| Import the funcy morph function: | ||
| >>> from diffpy.morph.morphs.morphfuncy import MorphFuncy | ||
|
|
||
| Define or import the user-supplied transformation function: | ||
| >>> def sine_function(x, y, amplitude, frequency): | ||
| >>> return amplitude * np.sin(frequency * x) * y | ||
|
|
||
| Provide initial guess for parameters: | ||
| >>> parameters = {'amplitude': 2, 'frequency': 2} | ||
|
|
||
| Run the funcy morph given input morph array (x_morph, y_morph) | ||
| and target array (x_target, y_target): | ||
| >>> morph = MorphFuncy() | ||
| >>> morph.function = sine_function | ||
| >>> morph.funcy = parameters | ||
| >>> x_morph_out, y_morph_out, x_target_out, y_target_out = morph.morph( | ||
| ... x_morph, y_morph, x_target, y_target) | ||
|
|
||
| To access parameters from the morph instance: | ||
| >>> x_morph_in = morph.x_morph_in | ||
| >>> y_morph_in = morph.y_morph_in | ||
| >>> x_target_in = morph.x_target_in | ||
| >>> y_target_in = morph.y_target_in | ||
| >>> parameters_out = morph.funcy | ||
| """ | ||
| """Apply the user-supplied Python function to the y-coordinates of the | ||
| morph data""" | ||
| Morph.morph(self, x_morph, y_morph, x_target, y_target) | ||
|
|
||
| self.y_morph_out = self.function( | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is copied from the other docs but it is not the preferred pattern. At least for new docs (not sure if we want to fix all the old code blocks, but maybe?) It looks better if:
goes to
I am not 100% sure about the indentation of the
.. code-blockand there are requirements for blank lines here and thee, but you can figure it out so it builds correctly it will be color coded in the built documentation.