Skip to content

Commit 80b4a60

Browse files
committed
Add online documentation for morphpy
1 parent 1028c46 commit 80b4a60

File tree

5 files changed

+195
-9
lines changed

5 files changed

+195
-9
lines changed

doc/source/morphpy.rst

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
.. _morphpy:
2+
3+
Using diffpy.morph in Python
4+
############################
5+
6+
On top of the command-line usage described in the `quickstart tutorial <quickstart.html>`__,
7+
``diffpy.morph`` also supports Python integration.
8+
This functionality is intended for those acquainted with the basic morphs
9+
described in the aforementioned quickstart tutorial who want to use ``diffpy.morph`` in their
10+
Python scripts.
11+
12+
Python Morphing Functions
13+
=========================
14+
15+
1. In the quickstart tutorial, you were asked to try a combined scale, stretch, and smear
16+
morph on the files `darkSub_rh20_C_01.gr` and `darkSub_rh20_C_44.gr` using the command-line
17+
command ::
18+
19+
diffpy.morph --scale=0.8 --smear=-0.08 --stretch=0.5 --rmin=1.5 --rmax=30 darkSub_rh20_C_01.gr darkSub_rh20_C_44.gr
20+
21+
2. To do the same on Python, we must first create a new Python script in the same directory as the
22+
data files `darkSub_rh20_C_01.gr` and `darkSub_rh20_C_44.gr`.
23+
3. Then, in that script, import ::
24+
25+
from diffpy.morph.morphpy import morph
26+
27+
3. Finally, we run the ``morph`` function ::
28+
29+
morph_info, morph_table = morph("darkSub_rh20_C_01.gr", "darkSub_rh20_C_44.gr", scale=0.8, smear=-0.08, stretch=0.5, rmin=1.5, rmax=30)
30+
31+
* The ``morph`` function takes in two file names (or paths). You can also provide various parameters
32+
for morphing (see the Full Parameter List below).
33+
* If, let's say, the file `darkSub_rh20_C_01.gr` is in a subdirectory `subdir/darkSub_rh20_C_01.gr`,
34+
you should replace ``"darkSub_rh20_C_01.gr"`` in the above example with ``"subdir/darkSub_rh20_C_01.gr"``.
35+
36+
4. The ``morph`` function returns a dictionary ``morph_info`` and a numpy array ``morph_table``.
37+
38+
* ``morph_info`` contains all morphs as keys (e.g. ``"scale"``, ``"stretch"``, ``"smear"``) with
39+
the optimized morphing parameters found by ``diffpy.morph`` as values. ``morph_info`` also contains
40+
the Rw and Pearson correlation coefficients found post-morphing.
41+
* ``morph_table`` is a two-column array of the morphed function interpolated onto the grid of the
42+
target function (e.g. in our example, it returns the contents of `darkSub_rh20_C_01.gr` after
43+
the morphs are applied interpolated onto the grid of `darkSub_rh20_C_44.gr`).
44+
5. Notice that most parameters you are able to use are the same as the options provided in the command-line
45+
interface version of ``diffpy.morph``. For example, the ``--apply`` option becomes the ``apply=True`` parameter.
46+
6. With that, you have already mastered the basics of using ``diffpy.morph`` on Python!
47+
7. Note that instead of passing two files to ``diffpy.morph``, you might instead want to directly
48+
pass arrays. For example, rather than passing `darkSub_rh20_C_01.gr`, I may want to pass
49+
a two-column array named ``ds_rh20_c_01_array`` containing the data table contents of the file
50+
`darkSub_rh20_C_01.gr`. In this case, we have a separate function ::
51+
52+
from diffpy.morph.morphpy import morph_arrays
53+
54+
8. Assuming we have loaded the data in `darkSub_rh20_C_01.gr` into ``ds_rh20_c_01_array`` and
55+
`darkSub_rh20_C_44.gr` into ``ds_rh20_c_44_array``, we can apply the same morph as step 3
56+
by running ::
57+
58+
morph_info, morph_table = morph_arrays(ds_rh20_c_01_array, ds_rh20_c_44_array, scale=0.8, smear=-0.08, stretch=0.5, rmin=1.5, rmax=30)
59+
60+
9. Notice that the two-column format of the input to ``morph_arrays`` is the same as the
61+
output of ``morph`` and ``morph_arrays``. It is VERY IMPORTANT that the data is in two-column format
62+
rather than the traditional two-row format. This is to reflect the file format used to store PDFs.
63+
10. For a full list of parameters used by (both) ``morph`` and ``morph_arrays``, see the Full Parameter List
64+
section below.
65+
66+
Full Parameter List
67+
===================
68+
69+
General Parameters
70+
------------------
71+
72+
save: str or path
73+
Save the morphed function to a the file passed to save. Use '-' for stdout.
74+
verbose: bool
75+
Print additional header details to saved files. These include details about the morph
76+
inputs and outputs.
77+
rmin: float
78+
Minimum r-value (abscissa) to use for function comparisons.
79+
rmax: float
80+
Maximum r-value (abscissa) to use for function comparisons.
81+
tolerance: float
82+
Specify least squares refiner tolerance when optimizing for morph parameters. Default: 10e-8.
83+
pearson: bool
84+
The refiner instead maximizes agreement in the Pearson function
85+
(default behavior is to minimize the residual).
86+
Note that this is insensitive to scale.
87+
addpearson: bool
88+
Maximize agreement in the Pearson function as well as minimizing the residual.
89+
90+
Manipulations
91+
-------------
92+
These parameters select the manipulations that are to be applied to the
93+
function. The passed values will be refined unless specifically
94+
excluded with the apply or exclude parameters.
95+
96+
apply: bool
97+
Apply morphs but do not refine.
98+
exclude: str
99+
Exclude a manipulation from refinement by name.
100+
scale: float
101+
Apply scale factor. This multiplies the function ordinate by scale.
102+
stretch: float
103+
Stretch function grid by a fraction stretch. Specifically, this multiplies the function grid by 1+stretch.
104+
squeeze: list of float
105+
Squeeze function grid given a polynomial
106+
p(x) = squeeze[0]+squeeze[1]*x+...+squeeze[n]*x^n. n is dependent on the number
107+
of values in the user-inputted comma-separated list.
108+
The morph transforms the function grid from x to x+p(x).
109+
When this parameter is given, hshift is disabled.
110+
When n>1, stretch is disabled.
111+
smear: float
112+
Smear the peaks with a Gaussian of width smear. This
113+
is done by convolving the function with a Gaussian
114+
with standard deviation smear. If both smear and
115+
smear_pdf are used, only smear_pdf will be
116+
applied.
117+
smear_pdf: float
118+
Convert PDF to RDF. Then, smear peaks with a Gaussian
119+
of width smear_pdf. Convert back to PDF. If both smear and
120+
smear_pdf are used, only smear_pdf will be
121+
applied.
122+
slope: float
123+
Slope of the baseline used in converting from PDF to RDF.
124+
This is used with the option smear_pdf. The slope will
125+
be estimated if not provided.
126+
hshift: float
127+
Shift the function horizontally by hshift to the right.
128+
vshift: float
129+
Shift the function vertically by vshift upward.
130+
qdamp: float
131+
Dampen PDF by a factor qdamp.
132+
radius: float
133+
Apply characteristic function of sphere with radius
134+
given by parameter radius. If pradius is also specified, instead apply
135+
characteristic function of spheroid with equatorial
136+
radius radius and polar radius pradius.
137+
pradius: float
138+
Apply characteristic function of spheroid with
139+
equatorial radius given by above parameter radius and polar radius pradius.
140+
If only pradius is specified, instead apply
141+
characteristic function of sphere with radius pradius.
142+
iradius: float
143+
Apply inverse characteristic function of sphere with
144+
radius iradius. If ipradius is also specified, instead
145+
apply inverse characteristic function of spheroid with
146+
equatorial radius iradius and polar radius ipradius.
147+
ipradius: float
148+
Apply inverse characteristic function of spheroid with
149+
equatorial radius iradius and polar radius ipradius.
150+
If only ipradius is specified, instead apply inverse
151+
characteristic function of sphere with radius ipradius.
152+
funcy: tuple (function, dict)
153+
See Python-Specific Morphs below.
154+
155+
Python-Specific Morphs
156+
======================
157+
158+
Some morphs in diffpy.morph are supported only in Python. Here, we detail
159+
how they are used and how to call them.
160+
161+
funcy: tuple (function, dict)
162+
This morph applies the function funcy[0] with parameters given in funcy[1].
163+
The function funcy[0] must be a function of both the abscissa and ordinate
164+
(e.g. take in at least two inputs with as many additional parameters as needed).
165+
For example, let's start with a two-column table with abscissa x and ordinate y.
166+
let us say we want to apply the function ::
167+
168+
def linear(x, y, a, b, c):
169+
return a * x + b * y + c
170+
171+
This function takes in both the abscissa and ordinate on top of three additional
172+
parameters a, b, and c. To use the funcy parameter with initial guesses
173+
a=1.0, b=2.0, c=3.0, we would pass ``funcy=(linear, {a: 1.0, b: 2.0, c: 3.0})``.

doc/source/quickstart.rst

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ diffpy.morph Tutorial
44
#####################
55

66
Welcome! This will be a quick tutorial to accquaint users with ``diffpy.morph``
7-
and some of what it can do. To see more details and definitions about
7+
and some of what it can do on the command-line.
8+
For those wishing to integrate ``diffpy.morph`` into their Python scripts,
9+
see the `morphpy tutorial <morphpy.html>`__.
10+
11+
To see more details and definitions about
812
the morphs please see the publication describing ``diffpy.morph``.
913

1014
To be published:

src/diffpy/morph/morphpy.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,15 @@ def morph(
6767
pmorph_value = kwargs.pop(pmorph)
6868
pymorphs.update({pmorph: pmorph_value})
6969

70+
# Special handling of parameters with dashes
71+
kwargs_copy = kwargs.copy()
72+
kwargs = {}
73+
for key in kwargs_copy.keys():
74+
new_key = key
75+
if "_" in key:
76+
new_key = key.replace("_", "-")
77+
kwargs.update({new_key: kwargs_copy[key]})
78+
7079
# Wrap the CLI
7180
parser = create_option_parser()
7281
params = {
@@ -92,7 +101,7 @@ def morph(
92101

93102

94103
# Take in array-like objects as input.
95-
def morphpy(
104+
def morph_arrays(
96105
morph_table,
97106
target_table,
98107
scale=None,

tests/test_morphio.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
multiple_targets,
1111
single_morph,
1212
)
13-
from diffpy.morph.morphpy import morphpy
13+
from diffpy.morph.morphpy import morph_arrays
1414

1515
# Support Python 2
1616
try:
@@ -201,7 +201,7 @@ def quadratic(x, y, a0, a1, a2):
201201
r = np.linspace(0, 10, 101)
202202
gr = np.linspace(0, 10, 101)
203203

204-
morphpy(
204+
morph_arrays(
205205
np.array([r, gr]).T,
206206
np.array([r, quadratic(r, gr, 1, 2, 3)]).T,
207207
squeeze=[0, 0, 0],

tests/test_morphpy.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import pytest
77

88
from diffpy.morph.morphapp import create_option_parser, single_morph
9-
from diffpy.morph.morphpy import morph, morphpy
9+
from diffpy.morph.morphpy import morph, morph_arrays
1010
from diffpy.morph.tools import getRw
1111

1212
thisfile = locals().get("__file__", "file.py")
@@ -99,7 +99,7 @@ def test_morphpy(self, setup_morph):
9999
for target_file in self.testfiles[1:]:
100100
_, grm0 = morph(morph_file, morph_file)
101101
_, grt = morph(target_file, target_file)
102-
mr, grm = morphpy(
102+
mr, grm = morph_arrays(
103103
grm0, grt, scale=1, stretch=0, sort_by="temperature"
104104
)
105105
morph_results.update({target_file.name: mr})
@@ -130,12 +130,12 @@ def gaussian_like_function(x, y, mu):
130130
target_r = np.linspace(0, 100, 1001)
131131
target_gr = 0.5 * gaussian(target_r, 50, 5) + 0.05
132132

133-
morph_info, _ = morphpy(
133+
morph_info, _ = morph_arrays(
134134
np.array([morph_r, morph_gr]).T,
135135
np.array([target_r, target_gr]).T,
136136
scale=1,
137-
vshift=0.01,
138137
smear=3.75,
138+
vshift=0.01,
139139
funcy=(gaussian_like_function, {"mu": 47.5}),
140140
tolerance=1e-12,
141141
)
@@ -152,7 +152,7 @@ def test_morphpy_outputs(self, tmp_path):
152152
def linear(x, y, s):
153153
return s * (x + y)
154154

155-
morph_info, _ = morphpy(
155+
morph_info, _ = morph_arrays(
156156
np.array([r, gr]).T,
157157
np.array([r, gr]).T,
158158
squeeze=[1, 2, 3, 4, 5],

0 commit comments

Comments
 (0)