ediff 0.2__tar.gz → 0.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ediff-0.2/src/ediff.egg-info → ediff-0.2.2}/PKG-INFO +16 -11
- ediff-0.2.2/README.md +46 -0
- ediff-0.2.2/src/ediff/__init__.py +45 -0
- ediff-0.2.2/src/ediff/background.py +35 -0
- {ediff-0.2 → ediff-0.2.2}/src/ediff/center.py +159 -143
- {ediff-0.2 → ediff-0.2.2}/src/ediff/io.py +21 -16
- {ediff-0.2 → ediff-0.2.2}/src/ediff/pxrd.py +52 -8
- {ediff-0.2 → ediff-0.2.2}/src/ediff/radial.py +2 -2
- {ediff-0.2 → ediff-0.2.2/src/ediff.egg-info}/PKG-INFO +16 -11
- ediff-0.2/README.md +0 -41
- ediff-0.2/src/ediff/__init__.py +0 -7
- ediff-0.2/src/ediff/background.py +0 -24
- {ediff-0.2 → ediff-0.2.2}/LICENCE +0 -0
- {ediff-0.2 → ediff-0.2.2}/pyproject.toml +0 -0
- {ediff-0.2 → ediff-0.2.2}/setup.cfg +0 -0
- {ediff-0.2 → ediff-0.2.2}/setup.py +0 -0
- {ediff-0.2 → ediff-0.2.2}/src/ediff.egg-info/SOURCES.txt +0 -0
- {ediff-0.2 → ediff-0.2.2}/src/ediff.egg-info/dependency_links.txt +0 -0
- {ediff-0.2 → ediff-0.2.2}/src/ediff.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ediff
|
|
3
|
-
Version: 0.2
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Processing of powder electron diffraction patterns
|
|
5
5
|
Home-page: https://github.com/mirekslouf/ediff/
|
|
6
6
|
Author: Mirek Slouf
|
|
@@ -18,24 +18,28 @@ EDIFF :: processing of powder electron diffraction patterns
|
|
|
18
18
|
-----------------------------------------------------------
|
|
19
19
|
* EDIFF is under development, but key modules do work:
|
|
20
20
|
- io = input/output data treatment
|
|
21
|
-
-
|
|
21
|
+
- background = background subtraction
|
|
22
22
|
- center = find center of 2D powder diffraction pattern
|
|
23
|
-
- radial = calculate radial distribution (2D-pattern
|
|
23
|
+
- radial = calculate radial distribution (2D-pattern ⇒ 1D-pattern)
|
|
24
24
|
- pxrd = calculation of theoretical powder X-ray diffraction patterns
|
|
25
25
|
|
|
26
26
|
Installation
|
|
27
27
|
------------
|
|
28
|
-
*
|
|
29
|
-
* `pip install
|
|
28
|
+
* Requirement: Python with sci-modules: numpy, matplotlib, scipy, pandas
|
|
29
|
+
* `pip install scikit-image` = 3rd party package for advanced image processing
|
|
30
|
+
* `pip install pymatgen` = 3rd party package employed in PXRD calculation
|
|
31
|
+
* `pip install bground`= our package, interactive background subtraction
|
|
32
|
+
* `pip install ediff` = EDIFF package itself (uses all packages above)
|
|
30
33
|
|
|
31
34
|
Quick start
|
|
32
35
|
-----------
|
|
33
36
|
* See how it works:
|
|
34
|
-
- Look at [worked example](https://
|
|
37
|
+
- Look at [worked example](https://www.dropbox.com/scl/fi/3hb78voxd17wb3fzh9n1p/01_ediff_au.nb.pdf?rlkey=qmbvwaw80o1gbe262hwgjvmgx&dl=0)
|
|
35
38
|
in Jupyter.
|
|
36
39
|
* Try it yourself:
|
|
37
|
-
- Download
|
|
38
|
-
|
|
40
|
+
- Download [complete examples with data](https://www.dropbox.com/scl/fo/td6rkdgp2usxosj1vqeku/h?rlkey=41carfdej5h2f8f4yscbuvagm&dl=0)
|
|
41
|
+
and scripts and basic instructions.
|
|
42
|
+
- After downloading, unzip it and follow the instructions in *readme* file.
|
|
39
43
|
|
|
40
44
|
Documentation, help and examples
|
|
41
45
|
--------------------------------
|
|
@@ -51,7 +55,8 @@ Versions of EDIFF
|
|
|
51
55
|
* Version 0.0.2 = pxrd module works
|
|
52
56
|
* Version 0.0.3 = pxrd module works including profiles
|
|
53
57
|
* Version 0.0.4 = bground module incorporated + slightly improved docstrings
|
|
54
|
-
* Version 0.1
|
|
55
|
-
* Version 0.1.1 =
|
|
56
|
-
* Version 0.1.2 =
|
|
58
|
+
* Version 0.1 = 1st semi-complete version with basic documentation
|
|
59
|
+
* Version 0.1.1 = improved/simplified outputs
|
|
60
|
+
* Version 0.1.2 = small improvements of code and documentation
|
|
57
61
|
* Version 0.2 = important improvements of center.py
|
|
62
|
+
* Version 0.2.2 = consolidation, update of docs and examples on www
|
ediff-0.2.2/README.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
EDIFF :: processing of powder electron diffraction patterns
|
|
2
|
+
-----------------------------------------------------------
|
|
3
|
+
* EDIFF is under development, but key modules do work:
|
|
4
|
+
- io = input/output data treatment
|
|
5
|
+
- background = background subtraction
|
|
6
|
+
- center = find center of 2D powder diffraction pattern
|
|
7
|
+
- radial = calculate radial distribution (2D-pattern ⇒ 1D-pattern)
|
|
8
|
+
- pxrd = calculation of theoretical powder X-ray diffraction patterns
|
|
9
|
+
|
|
10
|
+
Installation
|
|
11
|
+
------------
|
|
12
|
+
* Requirement: Python with sci-modules: numpy, matplotlib, scipy, pandas
|
|
13
|
+
* `pip install scikit-image` = 3rd party package for advanced image processing
|
|
14
|
+
* `pip install pymatgen` = 3rd party package employed in PXRD calculation
|
|
15
|
+
* `pip install bground`= our package, interactive background subtraction
|
|
16
|
+
* `pip install ediff` = EDIFF package itself (uses all packages above)
|
|
17
|
+
|
|
18
|
+
Quick start
|
|
19
|
+
-----------
|
|
20
|
+
* See how it works:
|
|
21
|
+
- Look at [worked example](https://www.dropbox.com/scl/fi/3hb78voxd17wb3fzh9n1p/01_ediff_au.nb.pdf?rlkey=qmbvwaw80o1gbe262hwgjvmgx&dl=0)
|
|
22
|
+
in Jupyter.
|
|
23
|
+
* Try it yourself:
|
|
24
|
+
- Download [complete examples with data](https://www.dropbox.com/scl/fo/td6rkdgp2usxosj1vqeku/h?rlkey=41carfdej5h2f8f4yscbuvagm&dl=0)
|
|
25
|
+
and scripts and basic instructions.
|
|
26
|
+
- After downloading, unzip it and follow the instructions in *readme* file.
|
|
27
|
+
|
|
28
|
+
Documentation, help and examples
|
|
29
|
+
--------------------------------
|
|
30
|
+
* [PyPI](https://pypi.org/project/ediff) repository.
|
|
31
|
+
* [GitHub](https://github.com/mirekslouf/ediff) repository.
|
|
32
|
+
* [GitHub Pages](https://mirekslouf.github.io/ediff/)
|
|
33
|
+
with [documentation](https://mirekslouf.github.io/ediff/docs).
|
|
34
|
+
|
|
35
|
+
Versions of EDIFF
|
|
36
|
+
-----------------
|
|
37
|
+
|
|
38
|
+
* Version 0.0.1 = just draft
|
|
39
|
+
* Version 0.0.2 = pxrd module works
|
|
40
|
+
* Version 0.0.3 = pxrd module works including profiles
|
|
41
|
+
* Version 0.0.4 = bground module incorporated + slightly improved docstrings
|
|
42
|
+
* Version 0.1 = 1st semi-complete version with basic documentation
|
|
43
|
+
* Version 0.1.1 = improved/simplified outputs
|
|
44
|
+
* Version 0.1.2 = small improvements of code and documentation
|
|
45
|
+
* Version 0.2 = important improvements of center.py
|
|
46
|
+
* Version 0.2.2 = consolidation, update of docs and examples on www
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
'''
|
|
2
|
+
Package: EDIFF
|
|
3
|
+
--------------
|
|
4
|
+
Utilities for processing of electron diffraction patterns.
|
|
5
|
+
|
|
6
|
+
* Input:
|
|
7
|
+
- 2D powder electron diffraction pattern
|
|
8
|
+
* Output:
|
|
9
|
+
- 1D powder electron diffraction pattern
|
|
10
|
+
- the 1D pattern/profile is obtained by radial averaging of 2D pattern
|
|
11
|
+
- the final 1D profile can be calibrated and compared with calculated PXRD
|
|
12
|
+
|
|
13
|
+
EDIFF modules:
|
|
14
|
+
|
|
15
|
+
* ediff.background = background correction (employs auxilliary package BGROUND)
|
|
16
|
+
* ediff.center = find center of 2D-diffraction pattern
|
|
17
|
+
* ediff.io = input/output operations (read diffractogram, set plot params...)
|
|
18
|
+
* ediff.pxrd = calculate 1D-PXRD pattern for a known structure
|
|
19
|
+
* ediff.radial = calculate 1D-radial profile from 2D-diffraction pattern
|
|
20
|
+
|
|
21
|
+
Auxiliary package BGROUND:
|
|
22
|
+
|
|
23
|
+
* the package enables simple, semi-automated, interactive background correction
|
|
24
|
+
* it is imported during ediff initialization and accessible as ediff.background
|
|
25
|
+
'''
|
|
26
|
+
|
|
27
|
+
__version__ = "0.2.2"
|
|
28
|
+
|
|
29
|
+
# Import of modules so that we could use the package as follows:
|
|
30
|
+
# >>> import ediff as ed
|
|
31
|
+
# >>> ed.io.read_image ...
|
|
32
|
+
import ediff.center
|
|
33
|
+
import ediff.io
|
|
34
|
+
import ediff.pxrd
|
|
35
|
+
import ediff.radial
|
|
36
|
+
|
|
37
|
+
# This is a slightly special import:
|
|
38
|
+
# * ediff (1) imports ediff.background, which (2) imports bground package
|
|
39
|
+
# * see additional imports in ediff.background module to see what is done
|
|
40
|
+
# * this "two-step import" enables us to use the ediff module as follows:
|
|
41
|
+
# >>> import ediff as ed
|
|
42
|
+
# >>> DATA = ed.background.InputData ...
|
|
43
|
+
# >>> PPAR = ed.background.PlotParams ...
|
|
44
|
+
# >>> IPLOT = ed.background.InteractivePlot ...
|
|
45
|
+
import ediff.background
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
'''
|
|
2
|
+
Module: ediff.background
|
|
3
|
+
------------------------
|
|
4
|
+
Semi-automated background correction.
|
|
5
|
+
|
|
6
|
+
* This module just imports key objects from external bground package.
|
|
7
|
+
* Therefore, it is just a formal incorporation of bground package to ediff.
|
|
8
|
+
|
|
9
|
+
The source code is the whole module is rather brief,
|
|
10
|
+
but it contains a detailed explanation of how it works.
|
|
11
|
+
|
|
12
|
+
* See the source code of ediff.background
|
|
13
|
+
if you are interested in technical details concerning the import.
|
|
14
|
+
* See documentation of bground package at https://pypi.org/project/bground
|
|
15
|
+
to find out how the background correction works.
|
|
16
|
+
'''
|
|
17
|
+
|
|
18
|
+
# Explanation of the following two import commands
|
|
19
|
+
#
|
|
20
|
+
# The 1st import command = all modules from bground.ui to THIS module
|
|
21
|
+
# - now ediff.background knows the same modules as bground.ui
|
|
22
|
+
# - but NOT yet the classes within bground.ui - these are imported next
|
|
23
|
+
# The 2nd import command = three key classes from bground.ui to THIS module
|
|
24
|
+
# - now ediff.bacground contains the three objects from bground.ui
|
|
25
|
+
# - THIS module now contains InputData, PlotParams, InteractivePlot
|
|
26
|
+
#
|
|
27
|
+
# Final conclusion => the users can do:
|
|
28
|
+
#
|
|
29
|
+
# >>> import ediff.background
|
|
30
|
+
# >>> DATA = ediff.background.InputData ...
|
|
31
|
+
# >>> PPAR = ediff.background.PlotParams ...
|
|
32
|
+
# >>> IPLOT = ediff.background.InteractivePlot ...
|
|
33
|
+
|
|
34
|
+
import bground.ui
|
|
35
|
+
from bground.ui import InputData, PlotParams, InteractivePlot
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
'''
|
|
2
|
-
Module ediff.center
|
|
3
|
-
|
|
2
|
+
Module: ediff.center
|
|
3
|
+
--------------------
|
|
4
4
|
Find center of 2D diffraction pattern.
|
|
5
|
-
|
|
6
|
-
CenterDet, aktualizace 06-10-23 CentDet update, methods compatibility
|
|
7
5
|
'''
|
|
8
6
|
|
|
7
|
+
# CenterDet
|
|
8
|
+
# PS 2023-10-06: CentDet update, methods compatibility
|
|
9
|
+
# MS 2023-11-26: Improved code formatting and docs + TODO notes for PS
|
|
10
|
+
|
|
11
|
+
|
|
9
12
|
import numpy as np
|
|
10
13
|
import skimage as sk
|
|
11
14
|
import matplotlib.pyplot as plt
|
|
@@ -17,9 +20,8 @@ import ediff.io
|
|
|
17
20
|
from skimage.measure import moments
|
|
18
21
|
from skimage.transform import hough_circle, hough_circle_peaks
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
import warnings
|
|
22
23
|
import sys
|
|
24
|
+
import warnings
|
|
23
25
|
warnings.filterwarnings("ignore")
|
|
24
26
|
|
|
25
27
|
|
|
@@ -27,13 +29,17 @@ class CenterEstimator:
|
|
|
27
29
|
'''
|
|
28
30
|
Detection of the center of diffraction patterns.
|
|
29
31
|
|
|
30
|
-
|
|
31
|
-
- Manually selected 3 points defining a circular diffraction pattern
|
|
32
|
-
to calculate center coordinates
|
|
33
|
-
- Visualize results
|
|
32
|
+
The center can be estimated in one of the following ways:
|
|
34
33
|
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
* Center of the intensity/mass in selected area.
|
|
35
|
+
* Center from three points (defined interactivelly)
|
|
36
|
+
which define one ring in a powder electron diffraction pattern.
|
|
37
|
+
* Center estimated from Hough transform,
|
|
38
|
+
which detects circles in the diffraction pattern.
|
|
39
|
+
|
|
40
|
+
SUBCLASS : CenterLocator
|
|
41
|
+
|
|
42
|
+
* the subclass refines the position of the estimated center
|
|
37
43
|
|
|
38
44
|
Parameters
|
|
39
45
|
----------
|
|
@@ -63,14 +69,13 @@ class CenterEstimator:
|
|
|
63
69
|
Print to terminal additional messages about program run.
|
|
64
70
|
|
|
65
71
|
Returns
|
|
66
|
-
-------
|
|
67
|
-
self.x :
|
|
72
|
+
-------
|
|
73
|
+
self.x : float
|
|
68
74
|
x-coordinate of the detected center
|
|
69
|
-
self.y :
|
|
75
|
+
self.y : float
|
|
70
76
|
y-coordinate of the detected center
|
|
71
|
-
self.r :
|
|
72
|
-
radius of the detected center (if available, othervise returns None)
|
|
73
|
-
|
|
77
|
+
self.r : float
|
|
78
|
+
radius of the detected center (if available, othervise returns None)
|
|
74
79
|
'''
|
|
75
80
|
|
|
76
81
|
def __init__(self, input_image,
|
|
@@ -79,6 +84,8 @@ class CenterEstimator:
|
|
|
79
84
|
heq = False,
|
|
80
85
|
icut = None,
|
|
81
86
|
cmap = 'gray',
|
|
87
|
+
csquare=50,
|
|
88
|
+
cintensity=0.8,
|
|
82
89
|
messages = False):
|
|
83
90
|
|
|
84
91
|
# Initialize attributes
|
|
@@ -108,15 +115,91 @@ class CenterEstimator:
|
|
|
108
115
|
self.x, self.y, self.r = self.detection_3points()
|
|
109
116
|
|
|
110
117
|
elif detection_method == 'intensity':
|
|
111
|
-
self.x, self.y, self.r = self.detection_intensity()
|
|
118
|
+
self.x, self.y, self.r = self.detection_intensity(csquare, cintensity)
|
|
112
119
|
|
|
113
120
|
elif detection_method == 'hough':
|
|
114
121
|
self.x, self.y, self.r = self.detection_Hough()
|
|
115
122
|
else:
|
|
116
123
|
print("Incorrect method for detection selected")
|
|
117
124
|
sys.exit()
|
|
125
|
+
|
|
118
126
|
|
|
127
|
+
def detection_intensity(self, csquare, cintensity, plot_results=0):
|
|
128
|
+
'''
|
|
129
|
+
Find center of intensity/mass of an array.
|
|
130
|
+
|
|
131
|
+
Parameters
|
|
132
|
+
----------
|
|
133
|
+
arr : 2D-numpy array
|
|
134
|
+
The array, whose intensity center will be determined.
|
|
135
|
+
csquare : int, optional, default is 20
|
|
136
|
+
The size/edge of the square in the (geometrical) center.
|
|
137
|
+
The intensity center will be searched only within the central square.
|
|
138
|
+
Reasons: To avoid other spots/diffractions and
|
|
139
|
+
to minimize the effect of possible intensity assymetry around center.
|
|
140
|
+
cintensity : float, optional, default is 0.8
|
|
141
|
+
The intensity fraction.
|
|
142
|
+
When searching the intensity center, we will consider only
|
|
143
|
+
pixels with intensity > max.intensity.
|
|
144
|
+
|
|
145
|
+
Returns
|
|
146
|
+
-------
|
|
147
|
+
xc,yc : float,float
|
|
148
|
+
XY-coordinates of the intensity/mass center of the array.
|
|
149
|
+
Round XY-coordinates if you use them for image/array calculations.
|
|
150
|
+
'''
|
|
151
|
+
|
|
152
|
+
# (1) Get image/array size
|
|
153
|
+
image = np.copy(self.to_refine)
|
|
154
|
+
arr = np.copy(image)
|
|
155
|
+
xsize,ysize = arr.shape
|
|
156
|
+
|
|
157
|
+
# (2) Calculate borders around the central square
|
|
158
|
+
xborder = (xsize - csquare) // 2
|
|
159
|
+
yborder = (ysize - csquare) // 2
|
|
160
|
+
|
|
161
|
+
# (3) Create the central square,
|
|
162
|
+
# from which the intensity center will be detected
|
|
163
|
+
arr2 = arr[xborder:-xborder,yborder:-yborder].copy()
|
|
164
|
+
|
|
165
|
+
# (4) In the central square,
|
|
166
|
+
# set all values below cintenstity to zero
|
|
167
|
+
arr2 = np.where(arr2>np.max(arr2)*cintensity, arr2, 0)
|
|
168
|
+
|
|
169
|
+
# (5) Determine the intensity center from image moments
|
|
170
|
+
# see image moments in...
|
|
171
|
+
# skimage: https://scikit-image.org/docs/dev/api/skimage.measure.html
|
|
172
|
+
# wikipedia: https://en.wikipedia.org/wiki/Image_moment -> Centroid
|
|
173
|
+
# ---
|
|
174
|
+
# (a) Calculate 1st central moments of the image
|
|
175
|
+
M = moments(arr2,1)
|
|
176
|
+
# (b) Calculate the intensity center = centroid according to www-help
|
|
177
|
+
(self.x, self.y) = (M[1,0]/M[0,0], M[0,1]/M[0,0])
|
|
178
|
+
# (c) We have centroid of the central square
|
|
179
|
+
# but we have to recalculate it to the whole image
|
|
180
|
+
(self.x, self.y) = (self.x + xborder, self.y + yborder)
|
|
181
|
+
# (d) Radius of a diffraction ring is hardcoded to 100 here
|
|
182
|
+
# TODO: consider improving/correcting/removing in the future
|
|
183
|
+
self.r = 100
|
|
184
|
+
|
|
185
|
+
# (6) User information (if required)
|
|
186
|
+
if self.messages:
|
|
187
|
+
print("--- IntensityCenter = center of intensity/mass ---")
|
|
188
|
+
print(f"Center coordinates [x, y]: [{self.x:.3f}, {self.y:.3f}]")
|
|
189
|
+
print("---")
|
|
190
|
+
|
|
191
|
+
# (7) Plot results (if required)
|
|
192
|
+
if plot_results == 1:
|
|
193
|
+
self.visualize_center(self.x, self.y, self.r)
|
|
119
194
|
|
|
195
|
+
# (8) Return the results:
|
|
196
|
+
# a) XY-coordinates of the center
|
|
197
|
+
# b) radius of the circle/diff.ring,
|
|
198
|
+
# from which the center was determined
|
|
199
|
+
# ! radius of the circle is just hardcoded here - see TODO note above
|
|
200
|
+
return(self.x, self.y, self.r)
|
|
201
|
+
|
|
202
|
+
|
|
120
203
|
def detection_3points(self, plot_results=1):
|
|
121
204
|
'''
|
|
122
205
|
In the input image, select manually 3 points defining a circle using
|
|
@@ -171,10 +254,9 @@ class CenterEstimator:
|
|
|
171
254
|
ax.imshow(im, cmap = self.cmap)
|
|
172
255
|
ax.axis('off')
|
|
173
256
|
|
|
174
|
-
|
|
175
257
|
# User information:
|
|
176
258
|
if self.messages:
|
|
177
|
-
print("---
|
|
259
|
+
print("--- ThreePoints = semi-automated center detection ---")
|
|
178
260
|
print()
|
|
179
261
|
print("Select 3 points to define a circle in the diffractogram:")
|
|
180
262
|
print("Use these keys for the selection:")
|
|
@@ -184,8 +266,11 @@ class CenterEstimator:
|
|
|
184
266
|
print(" - 'd' : done = finished = go to the next step")
|
|
185
267
|
print()
|
|
186
268
|
print("Close the figure to terminate. No center will be detected.")
|
|
269
|
+
print("---")
|
|
187
270
|
|
|
188
271
|
# Enable interactive mode
|
|
272
|
+
# (figure is updated after every plotting command
|
|
273
|
+
# (so that calling figure.show() is not necessary
|
|
189
274
|
plt.ion()
|
|
190
275
|
|
|
191
276
|
# Initialize the list of coordinates
|
|
@@ -227,11 +312,10 @@ class CenterEstimator:
|
|
|
227
312
|
closest_index = np.argmin(distances)
|
|
228
313
|
del self.coords[closest_index]
|
|
229
314
|
|
|
230
|
-
|
|
315
|
+
## Redraw the image without the deleted point
|
|
231
316
|
ax.clear()
|
|
232
317
|
ax.imshow(self.to_refine, cmap = self.cmap)
|
|
233
318
|
for x, y in self.coords:
|
|
234
|
-
|
|
235
319
|
ax.scatter(x, y,
|
|
236
320
|
c='r', marker='x',
|
|
237
321
|
s=self.marker_size)
|
|
@@ -245,13 +329,12 @@ class CenterEstimator:
|
|
|
245
329
|
ax.set_xlim(current_xlim)
|
|
246
330
|
ax.set_ylim(current_ylim)
|
|
247
331
|
ax.axis('off')
|
|
248
|
-
|
|
249
|
-
|
|
332
|
+
|
|
250
333
|
fig.canvas.draw()
|
|
251
334
|
else:
|
|
252
335
|
print("No points to delete.")
|
|
253
336
|
|
|
254
|
-
|
|
337
|
+
# Delete recent point (last added) -- independent on the cursor
|
|
255
338
|
if event.key == '2':
|
|
256
339
|
# Check if there are points to delete
|
|
257
340
|
if point_counter > 0:
|
|
@@ -304,7 +387,7 @@ class CenterEstimator:
|
|
|
304
387
|
c='r', marker='x',
|
|
305
388
|
s=self.marker_size)
|
|
306
389
|
|
|
307
|
-
#
|
|
390
|
+
# Restore the previous zoom level
|
|
308
391
|
ax.set_xlim(current_xlim)
|
|
309
392
|
ax.set_ylim(current_ylim)
|
|
310
393
|
ax.axis('off')
|
|
@@ -340,8 +423,7 @@ class CenterEstimator:
|
|
|
340
423
|
ax.axis('off')
|
|
341
424
|
|
|
342
425
|
plt.show(block=False)
|
|
343
|
-
|
|
344
|
-
|
|
426
|
+
|
|
345
427
|
# Wait for 'd' key event or close the figure if no points are selected
|
|
346
428
|
while not calculate_circle_flag and not termination_flag:
|
|
347
429
|
|
|
@@ -361,8 +443,7 @@ class CenterEstimator:
|
|
|
361
443
|
# Retore the previous zoom level
|
|
362
444
|
ax.set_xlim(current_xlim)
|
|
363
445
|
ax.set_ylim(current_ylim)
|
|
364
|
-
|
|
365
|
-
|
|
446
|
+
|
|
366
447
|
circle = plt.Circle(
|
|
367
448
|
(self.x, self.y), self.r, color='r', fill=False)
|
|
368
449
|
ax.add_artist(circle)
|
|
@@ -383,8 +464,7 @@ class CenterEstimator:
|
|
|
383
464
|
except ValueError as e:
|
|
384
465
|
print("ValueError:", e)
|
|
385
466
|
break
|
|
386
|
-
|
|
387
|
-
|
|
467
|
+
|
|
388
468
|
# If the termination_flag is True, stop the code
|
|
389
469
|
if termination_flag:
|
|
390
470
|
print("No points selected. Returned None values.")
|
|
@@ -397,12 +477,15 @@ class CenterEstimator:
|
|
|
397
477
|
# local variables save
|
|
398
478
|
self.center = center
|
|
399
479
|
|
|
400
|
-
|
|
480
|
+
self.backip = [self.x, self.y, self.r]
|
|
401
481
|
# Manually adjust the calculated center coordinates
|
|
402
482
|
self.x, self.y, self.r = self.adjustment_3points(fig, circle, center)
|
|
403
483
|
|
|
404
|
-
|
|
405
|
-
|
|
484
|
+
# Return the results:
|
|
485
|
+
# a) XY-coordinates of the center
|
|
486
|
+
# b) radius of the circle/diff.ring,
|
|
487
|
+
# from which the center was determined
|
|
488
|
+
return(self.x, self.y, self.r)
|
|
406
489
|
|
|
407
490
|
|
|
408
491
|
def adjustment_3points(self, fig, circle, center, plot_results=0):
|
|
@@ -539,7 +622,7 @@ class CenterEstimator:
|
|
|
539
622
|
except KeyboardInterrupt:
|
|
540
623
|
# If the user manually closes the figure, terminate the loop
|
|
541
624
|
termination_flag = True
|
|
542
|
-
|
|
625
|
+
|
|
543
626
|
# Turn off interactive mode
|
|
544
627
|
plt.ioff()
|
|
545
628
|
|
|
@@ -559,74 +642,8 @@ class CenterEstimator:
|
|
|
559
642
|
|
|
560
643
|
|
|
561
644
|
return xy[0], xy[1], r
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
def detection_intensity(self, csquare=20, cintensity=0.5, plot_results=0):
|
|
565
|
-
'''
|
|
566
|
-
Find center of intensity/mass of an array.
|
|
567
|
-
|
|
568
|
-
Parameters
|
|
569
|
-
----------
|
|
570
|
-
arr : 2D-numpy array
|
|
571
|
-
The array, whose intensity center will be determined.
|
|
572
|
-
csquare : int, optional, default is 20
|
|
573
|
-
The size/edge of the square in the (geometrical) center.
|
|
574
|
-
The intensity center will be searched only within the central square.
|
|
575
|
-
Reasons: To avoid other spots/diffractions and
|
|
576
|
-
to minimize the effect of possible intensity assymetry around center.
|
|
577
|
-
cintensity : float, optional, default is 0.8
|
|
578
|
-
The intensity fraction.
|
|
579
|
-
When searching the intensity center, we will consider only
|
|
580
|
-
pixels with intensity > max.intensity.
|
|
581
|
-
|
|
582
|
-
Returns
|
|
583
|
-
-------
|
|
584
|
-
xc,yc : float,float
|
|
585
|
-
XY-coordinates of the intensity/mass center of the array.
|
|
586
|
-
Round XY-coordinates if you use them for image/array calculations.
|
|
587
|
-
'''
|
|
588
|
-
|
|
589
|
-
# Get image/array size
|
|
590
|
-
image = np.copy(self.to_refine)
|
|
591
|
-
arr = np.copy(image)
|
|
592
|
-
xsize,ysize = arr.shape
|
|
593
|
-
|
|
594
|
-
# Calculate borders around the central square
|
|
595
|
-
xborder = (xsize - csquare) // 2
|
|
596
|
-
yborder = (ysize - csquare) // 2
|
|
597
|
-
|
|
598
|
-
# Create central square = cut off the borders
|
|
599
|
-
arr2 = arr[xborder:-xborder,yborder:-yborder].copy()
|
|
600
|
-
|
|
601
|
-
# In the central square, set all values below cintenstity to zero
|
|
602
|
-
arr2 = np.where(arr2>np.max(arr2)*cintensity, arr2, 0)
|
|
603
|
-
|
|
604
|
-
# Calculate 1st central moments of the image
|
|
605
|
-
M = moments(arr2,1)
|
|
606
|
-
|
|
607
|
-
# Calculate the intensity center = centroid according to www-help
|
|
608
|
-
(self.x, self.y) = (M[1,0]/M[0,0], M[0,1]/M[0,0])
|
|
609
|
-
|
|
610
|
-
# We have centroid of the central square => recalculate to whole image
|
|
611
|
-
(self.x, self.y) = (self.x + xborder, self.y + yborder)
|
|
612
|
-
self.r = 100
|
|
613
|
-
|
|
614
|
-
# User information:
|
|
615
|
-
if self.messages:
|
|
616
|
-
print("--------- Diffraction pattern detection via intensity detection ----------")
|
|
617
|
-
print("Central coordinate [ x, y ]: [{:.3f}, {:.3f}]".format(float(self.x),
|
|
618
|
-
float(self.y)))
|
|
619
|
-
print("--------------------------------------------------------------------------")
|
|
620
|
-
|
|
621
|
-
# Plot result of the Hough transform
|
|
622
|
-
if plot_results == 1:
|
|
623
|
-
self.visualize_center(self.x, self.y, self.r)
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
# Return results
|
|
627
|
-
return self.x, self.y, self.r
|
|
628
|
-
|
|
629
645
|
|
|
646
|
+
|
|
630
647
|
def detection_Hough(self, plot_results=0):
|
|
631
648
|
'''
|
|
632
649
|
Perform Hough transform to detect center of diffraction patterns.
|
|
@@ -812,9 +829,7 @@ class CenterEstimator:
|
|
|
812
829
|
plt.axis('off')
|
|
813
830
|
plt.tight_layout()
|
|
814
831
|
plt.show(block=False)
|
|
815
|
-
|
|
816
|
-
pass
|
|
817
|
-
#plt.close('all')
|
|
832
|
+
|
|
818
833
|
|
|
819
834
|
self.center = (self.x, self.y)
|
|
820
835
|
self.circle = plt.Circle((self.x,self.y),self.r)
|
|
@@ -935,7 +950,7 @@ class CenterLocator(CenterEstimator):
|
|
|
935
950
|
Selection of a method for center position correction. Default is None.
|
|
936
951
|
String codes are:
|
|
937
952
|
- 'manual' : manual corection
|
|
938
|
-
- '
|
|
953
|
+
- 'var' : correction via variance minimization
|
|
939
954
|
- 'sum' : correction via sum maximization
|
|
940
955
|
heq : boolean
|
|
941
956
|
Allow histogram equalization. The default is 0 (no enhancement)
|
|
@@ -953,6 +968,7 @@ class CenterLocator(CenterEstimator):
|
|
|
953
968
|
radius of the detected center
|
|
954
969
|
'''
|
|
955
970
|
|
|
971
|
+
|
|
956
972
|
def __init__(self, image_path,
|
|
957
973
|
detection_method, correction_method=None,
|
|
958
974
|
heq=False, icut=None, cmap='gray',
|
|
@@ -965,7 +981,6 @@ class CenterLocator(CenterEstimator):
|
|
|
965
981
|
|
|
966
982
|
|
|
967
983
|
# (2) Define additional parameter
|
|
968
|
-
self.final_replot = final_replot
|
|
969
984
|
self.messages = messages
|
|
970
985
|
self.image_path = image_path
|
|
971
986
|
|
|
@@ -975,25 +990,41 @@ class CenterLocator(CenterEstimator):
|
|
|
975
990
|
self.ret = 1
|
|
976
991
|
if correction_method == 'manual':
|
|
977
992
|
if detection_method == 'manual':
|
|
978
|
-
self.
|
|
979
|
-
self.
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
(self.xx, self.yy), self.r)
|
|
993
|
+
self.yy, self.xx, self.rr = self.x, self.y, self.r
|
|
994
|
+
self.y, self.x, self.r = self.backip[0], self.backip[1], self.r
|
|
995
|
+
elif detection_method == 'intensity':
|
|
996
|
+
self.yy, self.xx, self.rr = \
|
|
997
|
+
self.ref_interactive(self.y, self.x, self.r)
|
|
984
998
|
else:
|
|
985
|
-
self.
|
|
999
|
+
self.yy, self.xx, self.rr = \
|
|
986
1000
|
self.ref_interactive(self.x, self.y, self.r)
|
|
987
|
-
|
|
1001
|
+
|
|
1002
|
+
elif correction_method == 'var':
|
|
988
1003
|
self.xx, self.yy, self.rr = \
|
|
989
|
-
self.
|
|
1004
|
+
self.ref_var(self.x, self.y, self.r)
|
|
1005
|
+
if detection_method == 'manual':
|
|
1006
|
+
self.xx, self.yy = self.yy, self.xx
|
|
1007
|
+
self.x, self.y = self.y, self.x
|
|
1008
|
+
|
|
990
1009
|
elif correction_method == 'sum':
|
|
991
1010
|
self.xx, self.yy, self.rr = \
|
|
992
|
-
self.
|
|
1011
|
+
self.ref_sum(self.x, self.y, self.r)
|
|
1012
|
+
if detection_method == 'manual':
|
|
1013
|
+
self.xx, self.yy = self.yy, self.xx
|
|
1014
|
+
self.x, self.y = self.y, self.x
|
|
1015
|
+
|
|
993
1016
|
else:
|
|
994
1017
|
print("Incorrect method for correction selected")
|
|
995
1018
|
sys.exit()
|
|
1019
|
+
|
|
1020
|
+
if detection_method == 'hough':
|
|
1021
|
+
self.x, self.y = self.y, self.x
|
|
1022
|
+
self.xx, self.yy = self.yy, self.xx
|
|
996
1023
|
|
|
1024
|
+
if final_replot:
|
|
1025
|
+
self.visualize_refinement(
|
|
1026
|
+
self.y, self.x, self.r,
|
|
1027
|
+
(self.yy, self.xx), self.rr)
|
|
997
1028
|
else:
|
|
998
1029
|
self.ret = 2
|
|
999
1030
|
|
|
@@ -1220,10 +1251,9 @@ class CenterLocator(CenterEstimator):
|
|
|
1220
1251
|
y : float
|
|
1221
1252
|
y-coordinate of the center detected via detection_method
|
|
1222
1253
|
xx : float
|
|
1223
|
-
x-coordinate of the center detected via
|
|
1254
|
+
x-coordinate of the center detected via refinement_method
|
|
1224
1255
|
yy : float
|
|
1225
|
-
|
|
1226
|
-
|
|
1256
|
+
y-coordinate of the center detected via refinement_method
|
|
1227
1257
|
"""
|
|
1228
1258
|
|
|
1229
1259
|
if self.ret == 1:
|
|
@@ -1285,6 +1315,7 @@ class CenterLocator(CenterEstimator):
|
|
|
1285
1315
|
r : float64
|
|
1286
1316
|
new radius of the circular diffraction pattern
|
|
1287
1317
|
'''
|
|
1318
|
+
|
|
1288
1319
|
# Load original image
|
|
1289
1320
|
im = np.copy(self.to_refine)
|
|
1290
1321
|
|
|
@@ -1321,7 +1352,7 @@ class CenterLocator(CenterEstimator):
|
|
|
1321
1352
|
ax.add_artist(circle)
|
|
1322
1353
|
|
|
1323
1354
|
# Plot center point
|
|
1324
|
-
center, = ax.plot(
|
|
1355
|
+
center, = ax.plot(px, py, 'rx', markersize=12)
|
|
1325
1356
|
|
|
1326
1357
|
|
|
1327
1358
|
plt.title('Manually adjust the center position.',
|
|
@@ -1426,15 +1457,11 @@ class CenterLocator(CenterEstimator):
|
|
|
1426
1457
|
if self.messages:
|
|
1427
1458
|
print("CenterEstimator :: manual detection + adjustment")
|
|
1428
1459
|
print(f"Center coordinates: {xy[0]:.2f} {xy[1]:.2f}")
|
|
1429
|
-
|
|
1430
|
-
# Plot results
|
|
1431
|
-
if self.final_replot:
|
|
1432
|
-
self.visualize_refinement(px, py, pr, xy, r)
|
|
1433
|
-
|
|
1460
|
+
|
|
1434
1461
|
return xy[0], xy[1], r
|
|
1435
1462
|
|
|
1436
1463
|
|
|
1437
|
-
def
|
|
1464
|
+
def ref_var(self, px, py, pr, plot_results = 0):
|
|
1438
1465
|
'''
|
|
1439
1466
|
Adjust center coordinates of a detected circular diffraction pattern.
|
|
1440
1467
|
The center adjustment is based on variance minimization.
|
|
@@ -1587,11 +1614,6 @@ class CenterLocator(CenterEstimator):
|
|
|
1587
1614
|
if np.round(init_var,-2) < np.round(min_intensity_var,-2):
|
|
1588
1615
|
print("Refinement redundant.")
|
|
1589
1616
|
best_center = np.copy(bckup)
|
|
1590
|
-
|
|
1591
|
-
# Refinement visualization
|
|
1592
|
-
if self.final_replot:
|
|
1593
|
-
self.visualize_refinement(
|
|
1594
|
-
bckup[0], bckup[1], bckup[2], (best_center), best_radius)
|
|
1595
1617
|
|
|
1596
1618
|
# Print results
|
|
1597
1619
|
if self.messages:
|
|
@@ -1601,7 +1623,7 @@ class CenterLocator(CenterEstimator):
|
|
|
1601
1623
|
return best_center[0], best_center[1], best_radius
|
|
1602
1624
|
|
|
1603
1625
|
|
|
1604
|
-
def
|
|
1626
|
+
def ref_sum(self, px, py, pr, plot_results=1):
|
|
1605
1627
|
'''
|
|
1606
1628
|
Adjust center position based on gradient optimization method
|
|
1607
1629
|
via maximization of intensity sum.
|
|
@@ -1754,12 +1776,6 @@ class CenterLocator(CenterEstimator):
|
|
|
1754
1776
|
if np.round(init_sum,-2) > np.round(max_intensity_sum,-2):
|
|
1755
1777
|
print("Refinement redundant.")
|
|
1756
1778
|
best_center = np.copy(bckup)
|
|
1757
|
-
|
|
1758
|
-
# Refinement visualization
|
|
1759
|
-
if plot_results == 1:
|
|
1760
|
-
if self.final_replot:
|
|
1761
|
-
self.visualize_refinement(
|
|
1762
|
-
bckup[0], bckup[1], bckup[2], (best_center), best_radius)
|
|
1763
1779
|
|
|
1764
1780
|
# Print results
|
|
1765
1781
|
if self.messages:
|
|
@@ -1950,7 +1966,6 @@ class HandlerCircle(HandlerBase):
|
|
|
1950
1966
|
return [marker]
|
|
1951
1967
|
|
|
1952
1968
|
|
|
1953
|
-
|
|
1954
1969
|
class IntensityCenter:
|
|
1955
1970
|
'''
|
|
1956
1971
|
Simple center determination for a symmetric diffractogram.
|
|
@@ -1977,7 +1992,7 @@ class IntensityCenter:
|
|
|
1977
1992
|
>>> arr, detection_method='intensity', csquare=30, cintensity=0.8)
|
|
1978
1993
|
'''
|
|
1979
1994
|
|
|
1980
|
-
|
|
1995
|
+
@staticmethod
|
|
1981
1996
|
def center_of_intensity(arr, csquare=20, cintensity=0.8):
|
|
1982
1997
|
'''
|
|
1983
1998
|
Find center of intensity/mass of an array.
|
|
@@ -2017,6 +2032,7 @@ class IntensityCenter:
|
|
|
2017
2032
|
(xc,yc) = (M[1,0]/M[0,0], M[0,1]/M[0,0])
|
|
2018
2033
|
# We have centroid of the central square => recalculate to whole image
|
|
2019
2034
|
(xc,yc) = (xc+xborder,yc+yborder)
|
|
2035
|
+
|
|
2020
2036
|
## Return the final center
|
|
2021
2037
|
return(xc,yc)
|
|
2022
2038
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'''
|
|
2
|
-
Module ediff.io
|
|
3
|
-
|
|
2
|
+
Module: ediff.io
|
|
3
|
+
----------------
|
|
4
4
|
Input/output functions for package ediff.
|
|
5
5
|
'''
|
|
6
6
|
|
|
@@ -68,13 +68,14 @@ def set_plot_parameters(
|
|
|
68
68
|
if fontsize: # Global font size
|
|
69
69
|
plt.rcParams.update({'font.size' : fontsize})
|
|
70
70
|
# (2) Additional default parameters ---------------------------------------
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
71
|
+
if my_defaults: # Default rcParams if not forbidden by my_defaults=False
|
|
72
|
+
plt.rcParams.update({
|
|
73
|
+
'lines.linewidth' : 0.8,
|
|
74
|
+
'axes.linewidth' : 0.6,
|
|
75
|
+
'xtick.major.width' : 0.6,
|
|
76
|
+
'ytick.major.width' : 0.6,
|
|
77
|
+
'grid.linewidth' : 0.6,
|
|
78
|
+
'grid.linestyle' : ':'})
|
|
78
79
|
# (3) Further user-defined parameter in rcParams format -------------------
|
|
79
80
|
if my_rcParams: # Other possible rcParams in the form of dictionary
|
|
80
81
|
plt.rcParams.update(my_rcParams)
|
|
@@ -114,13 +115,17 @@ def plot_radial_distributions(
|
|
|
114
115
|
The output is the plot on screen
|
|
115
116
|
(and in *output file* if the *output* argument was given).
|
|
116
117
|
|
|
117
|
-
Technical
|
|
118
|
-
|
|
119
|
-
This function is quite flexible.
|
|
120
|
-
It can plot one radial distribution or more.
|
|
121
|
-
It can take data from PNG-files, TXT-files, 2D-arrays and 1D-arrays.
|
|
122
|
-
|
|
123
|
-
|
|
118
|
+
Technical notes
|
|
119
|
+
---------------
|
|
120
|
+
* This function is quite flexible.
|
|
121
|
+
* It can plot one radial distribution or more.
|
|
122
|
+
* It can take data from PNG-files, TXT-files, 2D-arrays and 1D-arrays.
|
|
123
|
+
* If the input is a PNG-file or2D-array,
|
|
124
|
+
the center is just *estimated* as as the center of intensity;
|
|
125
|
+
therefore, this works only for good diffractograms with a central spot.
|
|
126
|
+
* This makes the code a more complex, but it is convenient for the user.
|
|
127
|
+
* An example of fast comparison of three 1D-distributions
|
|
128
|
+
taken from three 2D-diffractograms in the form of 16-bit PNG images:
|
|
124
129
|
|
|
125
130
|
>>> ediff.io.plot_radial_distributions(
|
|
126
131
|
>>> data_to_plot = [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'''
|
|
2
|
-
Module ediff.pxrd
|
|
3
|
-
|
|
2
|
+
Module: ediff.pxrd
|
|
3
|
+
------------------
|
|
4
4
|
Calculation of powder X-ray diffraction patterns.
|
|
5
5
|
'''
|
|
6
6
|
|
|
@@ -12,6 +12,7 @@ from scipy.signal import convolve as spConvolve
|
|
|
12
12
|
from pymatgen.core.structure import Structure as pmStructure
|
|
13
13
|
from pymatgen.analysis.diffraction.xrd import XRDCalculator as pmXRDCalculator
|
|
14
14
|
|
|
15
|
+
|
|
15
16
|
class Crystal:
|
|
16
17
|
'''
|
|
17
18
|
Define crystal structure.
|
|
@@ -38,6 +39,7 @@ class Crystal:
|
|
|
38
39
|
the elements have the values defined in the dictionary;
|
|
39
40
|
a sample input dictionary: `temp_factors = {'Na':1.2, 'Cl':1.1}`.
|
|
40
41
|
'''
|
|
42
|
+
|
|
41
43
|
|
|
42
44
|
def __init__(self, structure, temp_factors=0.8):
|
|
43
45
|
'''
|
|
@@ -60,6 +62,7 @@ class Crystal:
|
|
|
60
62
|
# (the number is a universal temperature factor for all atoms
|
|
61
63
|
self.temp_factors = self.get_elements_with_temp_factors(
|
|
62
64
|
self.structure, temp_factors)
|
|
65
|
+
|
|
63
66
|
|
|
64
67
|
@staticmethod
|
|
65
68
|
def read_structure_from_CIF(CIF):
|
|
@@ -86,6 +89,7 @@ class Crystal:
|
|
|
86
89
|
structure = pmStructure.from_file(CIF)
|
|
87
90
|
return(structure)
|
|
88
91
|
|
|
92
|
+
|
|
89
93
|
def get_elements(self, structure):
|
|
90
94
|
'''
|
|
91
95
|
Get a list of all elements, which are contained in given structure.
|
|
@@ -122,6 +126,7 @@ class Crystal:
|
|
|
122
126
|
list_of_elements = np.unique(list_of_atoms)
|
|
123
127
|
return(list_of_elements)
|
|
124
128
|
|
|
129
|
+
|
|
125
130
|
def get_elements_with_temp_factors(self, structure, B=0.8):
|
|
126
131
|
'''
|
|
127
132
|
Get a dictionary, which contains symbols and temperature factors
|
|
@@ -154,6 +159,8 @@ class Crystal:
|
|
|
154
159
|
elements_with_temp_factors = dict.fromkeys(elements, B)
|
|
155
160
|
return(elements_with_temp_factors)
|
|
156
161
|
|
|
162
|
+
|
|
163
|
+
|
|
157
164
|
class Experiment:
|
|
158
165
|
'''
|
|
159
166
|
Define experimental parameters.
|
|
@@ -167,6 +174,8 @@ class Experiment:
|
|
|
167
174
|
Minimal and maximal diffraction angle;
|
|
168
175
|
both values are TwoTheta angle in [deg] (for given *wavelength*).
|
|
169
176
|
'''
|
|
177
|
+
|
|
178
|
+
|
|
170
179
|
def __init__(self, wavelength, two_theta_range):
|
|
171
180
|
'''
|
|
172
181
|
* Initialize Experimental object.
|
|
@@ -175,6 +184,8 @@ class Experiment:
|
|
|
175
184
|
self.wavelength = wavelength
|
|
176
185
|
self.two_theta_range = two_theta_range
|
|
177
186
|
|
|
187
|
+
|
|
188
|
+
|
|
178
189
|
class PlotParameters:
|
|
179
190
|
'''
|
|
180
191
|
Define local+global parameters for plotting.
|
|
@@ -191,6 +202,7 @@ class PlotParameters:
|
|
|
191
202
|
This enables to override current rcParams, if necessary.
|
|
192
203
|
'''
|
|
193
204
|
|
|
205
|
+
|
|
194
206
|
def __init__(self, title=None, x_axis='q', xlim=None, rcParams={}):
|
|
195
207
|
'''
|
|
196
208
|
* Initialize PlotParameters object.
|
|
@@ -203,6 +215,8 @@ class PlotParameters:
|
|
|
203
215
|
self.xlim = xlim
|
|
204
216
|
if rcParams: plt.rcParams.update(rcParams)
|
|
205
217
|
|
|
218
|
+
|
|
219
|
+
|
|
206
220
|
class PeakProfiles:
|
|
207
221
|
'''
|
|
208
222
|
Define profile of diffraction peaks.
|
|
@@ -211,6 +225,7 @@ class PeakProfiles:
|
|
|
211
225
|
* It contains three functions/definitions of diffratction peak profiles.
|
|
212
226
|
'''
|
|
213
227
|
|
|
228
|
+
|
|
214
229
|
def gaussian(X,m,s):
|
|
215
230
|
'''
|
|
216
231
|
Gaussian function (~ profile for PXRD calculation).
|
|
@@ -231,6 +246,7 @@ class PeakProfiles:
|
|
|
231
246
|
'''
|
|
232
247
|
return( 1/(s*np.sqrt(2*np.pi)) * np.exp(-(X-m)**2/(2*s**2)) )
|
|
233
248
|
|
|
249
|
+
|
|
234
250
|
def lorentzian(X,m,s):
|
|
235
251
|
'''
|
|
236
252
|
Lorentzian function (~ profile for PXRD calculation).
|
|
@@ -251,6 +267,7 @@ class PeakProfiles:
|
|
|
251
267
|
'''
|
|
252
268
|
return( 1/np.pi * s/((X-m)**2 + s**2) )
|
|
253
269
|
|
|
270
|
+
|
|
254
271
|
def pseudo_voigt(X,m,s,n=0.5):
|
|
255
272
|
'''
|
|
256
273
|
Pseudo-Voigt function (~ profile for PXRD calculation).
|
|
@@ -296,6 +313,8 @@ class PeakProfiles:
|
|
|
296
313
|
# (3) Return calculated function
|
|
297
314
|
return(pseudo_voigt)
|
|
298
315
|
|
|
316
|
+
|
|
317
|
+
|
|
299
318
|
class PXRDcalculation:
|
|
300
319
|
'''
|
|
301
320
|
Define calculation of PXRD = powder X-ray diffraction pattern.
|
|
@@ -323,7 +342,8 @@ class PXRDcalculation:
|
|
|
323
342
|
This default is suitable for common calculations
|
|
324
343
|
and does not have to be changed (in great majority of cases).
|
|
325
344
|
'''
|
|
326
|
-
|
|
345
|
+
|
|
346
|
+
|
|
327
347
|
def __init__(self, crystal, experiment, plot_parameters,
|
|
328
348
|
peak_profile_sigma = 0.03,
|
|
329
349
|
peak_profile_type = PeakProfiles.pseudo_voigt):
|
|
@@ -339,6 +359,7 @@ class PXRDcalculation:
|
|
|
339
359
|
self.diffractions = self.calculate_diffractions()
|
|
340
360
|
self.diffractogram = self.calculate_diffractogram()
|
|
341
361
|
|
|
362
|
+
|
|
342
363
|
def calculate_diffractions(self):
|
|
343
364
|
# (1) Calculate intensities
|
|
344
365
|
calculation = pmXRDCalculator(
|
|
@@ -353,6 +374,7 @@ class PXRDcalculation:
|
|
|
353
374
|
# (pandas.DataFrame with cols: TwoTheta, h,k,l, dhkl, S, q, Intensity
|
|
354
375
|
return(diffractions_df)
|
|
355
376
|
|
|
377
|
+
|
|
356
378
|
def calculate_diffractogram(self):
|
|
357
379
|
# (1) Base diffraction profile
|
|
358
380
|
# = diffractogram with zero intensities
|
|
@@ -402,6 +424,7 @@ class PXRDcalculation:
|
|
|
402
424
|
# (5) Return diffractogram
|
|
403
425
|
return(df)
|
|
404
426
|
|
|
427
|
+
|
|
405
428
|
def print_diffractions(self):
|
|
406
429
|
'''
|
|
407
430
|
Print the calculated diffractions to stdout.
|
|
@@ -409,6 +432,7 @@ class PXRDcalculation:
|
|
|
409
432
|
table = PXRDcalculation.dframe_to_table(self.diffractions)
|
|
410
433
|
print(table)
|
|
411
434
|
|
|
435
|
+
|
|
412
436
|
def save_diffractions(self, output_file):
|
|
413
437
|
'''
|
|
414
438
|
Save the calculated diffractions to *output_file*.
|
|
@@ -429,6 +453,7 @@ class PXRDcalculation:
|
|
|
429
453
|
except:
|
|
430
454
|
print(f'Error saving diffractions to {output_file}!')
|
|
431
455
|
|
|
456
|
+
|
|
432
457
|
def plot_diffractions(self, outfile=None):
|
|
433
458
|
'''
|
|
434
459
|
Plot the calculated diffractions.
|
|
@@ -441,18 +466,25 @@ class PXRDcalculation:
|
|
|
441
466
|
|
|
442
467
|
Returns
|
|
443
468
|
-------
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
469
|
+
None
|
|
470
|
+
The output is the plot on the screen (and outfile).
|
|
471
|
+
This function plots just diffraction intensities,
|
|
472
|
+
not profiles.
|
|
473
|
+
Use ediff.pxrd.plot_diffractions
|
|
474
|
+
for diffractogram with intensity profiles.
|
|
447
475
|
'''
|
|
476
|
+
|
|
448
477
|
# (1) Make local copies of pre-defined parameters (just convenience)
|
|
449
478
|
df = self.diffractions
|
|
450
479
|
x_axis = self.plot_parameters.x_axis
|
|
480
|
+
|
|
451
481
|
# (2) Prepare the plot
|
|
452
482
|
plt.vlines(df[x_axis],0,df.Ihkl, lw=2)
|
|
483
|
+
|
|
453
484
|
# (3) Set plot details
|
|
454
485
|
# (external function, common to diffractions and diffractogram plots
|
|
455
486
|
self.set_plot_details(x_axis)
|
|
487
|
+
|
|
456
488
|
# (4) Save/show the plot...
|
|
457
489
|
# In Spyder: plot is always shown
|
|
458
490
|
# In CLI: plot is saved (if outfile is defined) or it is just shown
|
|
@@ -461,6 +493,7 @@ class PXRDcalculation:
|
|
|
461
493
|
else:
|
|
462
494
|
plt.show()
|
|
463
495
|
|
|
496
|
+
|
|
464
497
|
def plot_diffractions_with_indexes(self):
|
|
465
498
|
'''
|
|
466
499
|
Plot indexed diffractions.
|
|
@@ -533,6 +566,7 @@ class PXRDcalculation:
|
|
|
533
566
|
# (6) Revert to original rcParams.
|
|
534
567
|
plt.rcParams.update(original_rcParams)
|
|
535
568
|
|
|
569
|
+
|
|
536
570
|
def print_diffractogram(self):
|
|
537
571
|
self.print_diffractions()
|
|
538
572
|
print('-----')
|
|
@@ -540,6 +574,7 @@ class PXRDcalculation:
|
|
|
540
574
|
print('* Reason: the whole diffraction pattern is too long.')
|
|
541
575
|
print('* Note: save_diffractogram save the pattern to TXT-file.')
|
|
542
576
|
|
|
577
|
+
|
|
543
578
|
def save_diffractogram(self, outfile):
|
|
544
579
|
my_title = 'Calculated PXRD diffractogram\n'
|
|
545
580
|
np.savetxt(
|
|
@@ -549,22 +584,28 @@ class PXRDcalculation:
|
|
|
549
584
|
header = my_title +
|
|
550
585
|
'Columns: TwoTheta[deg], S[1/A], q[1/A], Intensity')
|
|
551
586
|
|
|
552
|
-
|
|
587
|
+
|
|
588
|
+
def plot_diffractogram(self, outfile, x_axis='q', dpi=300):
|
|
589
|
+
|
|
553
590
|
# (1) Make local copies of pre-defined parameters (just convenience)
|
|
554
591
|
df = self.diffractogram
|
|
555
592
|
x_axis = self.plot_parameters.x_axis
|
|
593
|
+
|
|
556
594
|
# (2) Prepare the plot
|
|
557
595
|
plt.plot(df[x_axis],df.Intensity)
|
|
596
|
+
|
|
558
597
|
# (3) Set plot details
|
|
559
598
|
# (external function, common to diffractions and diffractogram plots
|
|
560
599
|
self.set_plot_details(x_axis)
|
|
600
|
+
|
|
561
601
|
# (4) Save/show the plot...
|
|
562
602
|
# In Spyder: plot is always shown
|
|
563
603
|
# In CLI: plot is saved (if outfile is defined) or it is just shown
|
|
564
604
|
if outfile != None:
|
|
565
|
-
plt.savefig(outfile)
|
|
605
|
+
plt.savefig(outfile, dpi=dpi)
|
|
566
606
|
else:
|
|
567
607
|
plt.show()
|
|
608
|
+
|
|
568
609
|
|
|
569
610
|
@staticmethod
|
|
570
611
|
def diffractions_to_dframe(intensities):
|
|
@@ -602,6 +643,7 @@ class PXRDcalculation:
|
|
|
602
643
|
df.insert(loc=6, column='S', value=1/df.dhkl)
|
|
603
644
|
df.insert(loc=7, column='q', value=2*np.pi*df.S)
|
|
604
645
|
return(df)
|
|
646
|
+
|
|
605
647
|
|
|
606
648
|
@staticmethod
|
|
607
649
|
def dframe_to_table(dframe):
|
|
@@ -649,6 +691,7 @@ class PXRDcalculation:
|
|
|
649
691
|
'Ihkl' : '{:9.3f}'.format})
|
|
650
692
|
return(table)
|
|
651
693
|
|
|
694
|
+
|
|
652
695
|
def add_diffraction_vectors_to_diffractogram(self, df):
|
|
653
696
|
# Prepare wavelenght (just shortcut for convenience)
|
|
654
697
|
wavelength = self.experiment.wavelength
|
|
@@ -663,6 +706,7 @@ class PXRDcalculation:
|
|
|
663
706
|
# Return the modified/extended DataFrame
|
|
664
707
|
return(df)
|
|
665
708
|
|
|
709
|
+
|
|
666
710
|
def set_plot_details(self, x_axis):
|
|
667
711
|
# (1) Make local copies of pre-defined parameters (just convenience)
|
|
668
712
|
title = self.plot_parameters.title
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ediff
|
|
3
|
-
Version: 0.2
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Processing of powder electron diffraction patterns
|
|
5
5
|
Home-page: https://github.com/mirekslouf/ediff/
|
|
6
6
|
Author: Mirek Slouf
|
|
@@ -18,24 +18,28 @@ EDIFF :: processing of powder electron diffraction patterns
|
|
|
18
18
|
-----------------------------------------------------------
|
|
19
19
|
* EDIFF is under development, but key modules do work:
|
|
20
20
|
- io = input/output data treatment
|
|
21
|
-
-
|
|
21
|
+
- background = background subtraction
|
|
22
22
|
- center = find center of 2D powder diffraction pattern
|
|
23
|
-
- radial = calculate radial distribution (2D-pattern
|
|
23
|
+
- radial = calculate radial distribution (2D-pattern ⇒ 1D-pattern)
|
|
24
24
|
- pxrd = calculation of theoretical powder X-ray diffraction patterns
|
|
25
25
|
|
|
26
26
|
Installation
|
|
27
27
|
------------
|
|
28
|
-
*
|
|
29
|
-
* `pip install
|
|
28
|
+
* Requirement: Python with sci-modules: numpy, matplotlib, scipy, pandas
|
|
29
|
+
* `pip install scikit-image` = 3rd party package for advanced image processing
|
|
30
|
+
* `pip install pymatgen` = 3rd party package employed in PXRD calculation
|
|
31
|
+
* `pip install bground`= our package, interactive background subtraction
|
|
32
|
+
* `pip install ediff` = EDIFF package itself (uses all packages above)
|
|
30
33
|
|
|
31
34
|
Quick start
|
|
32
35
|
-----------
|
|
33
36
|
* See how it works:
|
|
34
|
-
- Look at [worked example](https://
|
|
37
|
+
- Look at [worked example](https://www.dropbox.com/scl/fi/3hb78voxd17wb3fzh9n1p/01_ediff_au.nb.pdf?rlkey=qmbvwaw80o1gbe262hwgjvmgx&dl=0)
|
|
35
38
|
in Jupyter.
|
|
36
39
|
* Try it yourself:
|
|
37
|
-
- Download
|
|
38
|
-
|
|
40
|
+
- Download [complete examples with data](https://www.dropbox.com/scl/fo/td6rkdgp2usxosj1vqeku/h?rlkey=41carfdej5h2f8f4yscbuvagm&dl=0)
|
|
41
|
+
and scripts and basic instructions.
|
|
42
|
+
- After downloading, unzip it and follow the instructions in *readme* file.
|
|
39
43
|
|
|
40
44
|
Documentation, help and examples
|
|
41
45
|
--------------------------------
|
|
@@ -51,7 +55,8 @@ Versions of EDIFF
|
|
|
51
55
|
* Version 0.0.2 = pxrd module works
|
|
52
56
|
* Version 0.0.3 = pxrd module works including profiles
|
|
53
57
|
* Version 0.0.4 = bground module incorporated + slightly improved docstrings
|
|
54
|
-
* Version 0.1
|
|
55
|
-
* Version 0.1.1 =
|
|
56
|
-
* Version 0.1.2 =
|
|
58
|
+
* Version 0.1 = 1st semi-complete version with basic documentation
|
|
59
|
+
* Version 0.1.1 = improved/simplified outputs
|
|
60
|
+
* Version 0.1.2 = small improvements of code and documentation
|
|
57
61
|
* Version 0.2 = important improvements of center.py
|
|
62
|
+
* Version 0.2.2 = consolidation, update of docs and examples on www
|
ediff-0.2/README.md
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
EDIFF :: processing of powder electron diffraction patterns
|
|
2
|
-
-----------------------------------------------------------
|
|
3
|
-
* EDIFF is under development, but key modules do work:
|
|
4
|
-
- io = input/output data treatment
|
|
5
|
-
- bkgr = background subtraction
|
|
6
|
-
- center = find center of 2D powder diffraction pattern
|
|
7
|
-
- radial = calculate radial distribution (2D-pattern to 1D-pattern)
|
|
8
|
-
- pxrd = calculation of theoretical powder X-ray diffraction patterns
|
|
9
|
-
|
|
10
|
-
Installation
|
|
11
|
-
------------
|
|
12
|
-
* `pip install bground` = interactive background subtraction
|
|
13
|
-
* `pip install ediff` = EDIFF program itself (uses bground internally)
|
|
14
|
-
|
|
15
|
-
Quick start
|
|
16
|
-
-----------
|
|
17
|
-
* See how it works:
|
|
18
|
-
- Look at [worked example](https://mirekslouf.github.io/ediff/docs/examples/ex1_ediff.nb.html)
|
|
19
|
-
in Jupyter.
|
|
20
|
-
* Try it yourself:
|
|
21
|
-
- Download and unzip the [complete example with data](https://www.dropbox.com/scl/fo/nmsvdtef7xtmb7r2ku5aa/h?dl=0&rlkey=2evadkk009wp248rp2c3ij2nj).
|
|
22
|
-
- Look at `00readme.txt` and run the example in Jupyter.
|
|
23
|
-
|
|
24
|
-
Documentation, help and examples
|
|
25
|
-
--------------------------------
|
|
26
|
-
* [PyPI](https://pypi.org/project/ediff) repository.
|
|
27
|
-
* [GitHub](https://github.com/mirekslouf/ediff) repository.
|
|
28
|
-
* [GitHub Pages](https://mirekslouf.github.io/ediff/)
|
|
29
|
-
with [documentation](https://mirekslouf.github.io/ediff/docs).
|
|
30
|
-
|
|
31
|
-
Versions of EDIFF
|
|
32
|
-
-----------------
|
|
33
|
-
|
|
34
|
-
* Version 0.0.1 = just draft
|
|
35
|
-
* Version 0.0.2 = pxrd module works
|
|
36
|
-
* Version 0.0.3 = pxrd module works including profiles
|
|
37
|
-
* Version 0.0.4 = bground module incorporated + slightly improved docstrings
|
|
38
|
-
* Version 0.1.0 = 1st semi-complete version with basic documentation
|
|
39
|
-
* Version 0.1.1 = v.0.1.0 + improved/simplified outputs
|
|
40
|
-
* Version 0.1.2 = v.0.1.1 + small improvements of code and documentation
|
|
41
|
-
* Version 0.2 = important improvements of center.py
|
ediff-0.2/src/ediff/__init__.py
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
'''
|
|
2
|
-
Module ediff.background
|
|
3
|
-
-----------------------
|
|
4
|
-
Interactive background definition.
|
|
5
|
-
'''
|
|
6
|
-
|
|
7
|
-
# The module just imports key objects from external bground module.
|
|
8
|
-
# This is a formal incorporation of bground module to ediff.background module.
|
|
9
|
-
|
|
10
|
-
# How it works? = comment to the next two import commands:
|
|
11
|
-
# The 1st import command = all modules from bground.ui to THIS module
|
|
12
|
-
# => now ediff.background knows the same modules as bground.ui
|
|
13
|
-
# => but NOT yet the classes within bground.ui - these are imported next
|
|
14
|
-
# The 2nd import command = three key classes from bground.ui to THIS module
|
|
15
|
-
# => now ediff.bacground contains the three objects from bground.ui
|
|
16
|
-
# => THIS module now contains InputData, PlotParams, InteractivePlot
|
|
17
|
-
# Now the users of this module can do:
|
|
18
|
-
# >>> import ediff.background
|
|
19
|
-
# >>> DATA = ediff.background.InputData ...
|
|
20
|
-
# >>> PPAR = ediff.background.PlotParams ...
|
|
21
|
-
# >>> IPLOT = ediff.background.InteractivePlot ...
|
|
22
|
-
|
|
23
|
-
import bground.ui
|
|
24
|
-
from bground.ui import InputData, PlotParams, InteractivePlot
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|