diffpy.fourigui 0.1.0rc0__py3-none-any.whl
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.
- diffpy/__init__.py +23 -0
- diffpy/fourigui/__init__.py +24 -0
- diffpy/fourigui/fourigui.py +571 -0
- diffpy/fourigui/version.py +26 -0
- diffpy.fourigui-0.1.0rc0.dist-info/AUTHORS.rst +10 -0
- diffpy.fourigui-0.1.0rc0.dist-info/LICENSE.rst +30 -0
- diffpy.fourigui-0.1.0rc0.dist-info/METADATA +154 -0
- diffpy.fourigui-0.1.0rc0.dist-info/RECORD +10 -0
- diffpy.fourigui-0.1.0rc0.dist-info/WHEEL +5 -0
- diffpy.fourigui-0.1.0rc0.dist-info/top_level.txt +1 -0
diffpy/__init__.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
##############################################################################
|
|
3
|
+
#
|
|
4
|
+
# (c) 2024 The Trustees of Columbia University in the City of New York.
|
|
5
|
+
# All rights reserved.
|
|
6
|
+
#
|
|
7
|
+
# File coded by: Billinge Group members and community contributors.
|
|
8
|
+
#
|
|
9
|
+
# See GitHub contributions for a more detailed list of contributors.
|
|
10
|
+
# https://github.com/diffpy/diffpy.fourigui/graphs/contributors
|
|
11
|
+
#
|
|
12
|
+
# See LICENSE.rst for license information.
|
|
13
|
+
#
|
|
14
|
+
##############################################################################
|
|
15
|
+
|
|
16
|
+
"""Blank namespace package for module diffpy."""
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
from pkgutil import extend_path
|
|
20
|
+
|
|
21
|
+
__path__ = extend_path(__path__, __name__)
|
|
22
|
+
|
|
23
|
+
# End of file
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
##############################################################################
|
|
3
|
+
#
|
|
4
|
+
# (c) 2024 The Trustees of Columbia University in the City of New York.
|
|
5
|
+
# All rights reserved.
|
|
6
|
+
#
|
|
7
|
+
# File coded by: Billinge Group members and community contributors.
|
|
8
|
+
#
|
|
9
|
+
# See GitHub contributions for a more detailed list of contributors.
|
|
10
|
+
# https://github.com/diffpy/diffpy.fourigui/graphs/contributors
|
|
11
|
+
#
|
|
12
|
+
# See LICENSE.rst for license information.
|
|
13
|
+
#
|
|
14
|
+
##############################################################################
|
|
15
|
+
|
|
16
|
+
"""Tool for visualizing 3D diffraction and PDF Images."""
|
|
17
|
+
|
|
18
|
+
# package version
|
|
19
|
+
from diffpy.fourigui.version import __version__
|
|
20
|
+
|
|
21
|
+
# silence the pyflakes syntax checker
|
|
22
|
+
assert __version__ or True
|
|
23
|
+
|
|
24
|
+
# End of file
|
|
@@ -0,0 +1,571 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import tkinter as tk
|
|
3
|
+
from tkinter.ttk import Button
|
|
4
|
+
|
|
5
|
+
import h5py
|
|
6
|
+
import matplotlib
|
|
7
|
+
import numpy as np
|
|
8
|
+
from matplotlib import pyplot as plt
|
|
9
|
+
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
|
|
10
|
+
|
|
11
|
+
matplotlib.use("tkagg")
|
|
12
|
+
|
|
13
|
+
WIDTH = 920
|
|
14
|
+
HEIGHT = 630
|
|
15
|
+
XPOS = 300
|
|
16
|
+
YPOS = 100
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class Gui(tk.Frame):
|
|
20
|
+
def __init__(self):
|
|
21
|
+
super().__init__()
|
|
22
|
+
self.initUI()
|
|
23
|
+
|
|
24
|
+
def initUI(self):
|
|
25
|
+
|
|
26
|
+
self.loaded = False # denotes whether a dataset is loaded
|
|
27
|
+
self.transformed = False # denotes whether dataset is Fourier transformed
|
|
28
|
+
self.cutted = False # denotes whether cutoff frequencies are applied to dataset
|
|
29
|
+
self.transcutted = False # denotes whether cutoff frequencies are applied and Fourier transformed
|
|
30
|
+
|
|
31
|
+
self.master.title("FouriGUI")
|
|
32
|
+
self.pack(fill=tk.BOTH, expand=True)
|
|
33
|
+
|
|
34
|
+
print("\nNew Session started ...")
|
|
35
|
+
print("Enjoy exploring the beautiful reconstructions in real and in reciprocal space!")
|
|
36
|
+
|
|
37
|
+
# 4 frames:
|
|
38
|
+
# frame 00: all buttons
|
|
39
|
+
# frame 01: plot area
|
|
40
|
+
# frame 10: exit button
|
|
41
|
+
# frame 11: not used
|
|
42
|
+
|
|
43
|
+
# 00 #
|
|
44
|
+
# frame 00, upper left
|
|
45
|
+
|
|
46
|
+
frame00 = tk.Frame(self)
|
|
47
|
+
frame00.place(x=5, y=0)
|
|
48
|
+
|
|
49
|
+
filelabel = tk.Label(frame00, text="filename: ")
|
|
50
|
+
filelabel.grid(row=0, column=0)
|
|
51
|
+
|
|
52
|
+
# row 0: load file area
|
|
53
|
+
self.filename_entry = tk.Entry(frame00)
|
|
54
|
+
self.filename_entry.grid(row=0, column=1, columnspan=3)
|
|
55
|
+
self.filename_entry.insert(0, "/path/data.h5")
|
|
56
|
+
|
|
57
|
+
loadbutton = Button(frame00, text="load", command=lambda: self.load_cube())
|
|
58
|
+
loadbutton.grid(row=0, column=4)
|
|
59
|
+
|
|
60
|
+
# row 1: change axis area
|
|
61
|
+
axislabel = tk.Label(frame00, text="axis: ")
|
|
62
|
+
axislabel.grid(row=1, column=0, pady=7, sticky=tk.W)
|
|
63
|
+
|
|
64
|
+
self.axis = tk.IntVar()
|
|
65
|
+
|
|
66
|
+
rb0 = tk.Radiobutton(
|
|
67
|
+
frame00,
|
|
68
|
+
text="0",
|
|
69
|
+
variable=self.axis,
|
|
70
|
+
value=0,
|
|
71
|
+
command=lambda: self.plot_plane(),
|
|
72
|
+
)
|
|
73
|
+
rb0.grid(row=1, column=1)
|
|
74
|
+
rb1 = tk.Radiobutton(
|
|
75
|
+
frame00,
|
|
76
|
+
text="1",
|
|
77
|
+
variable=self.axis,
|
|
78
|
+
value=1,
|
|
79
|
+
command=lambda: self.plot_plane(),
|
|
80
|
+
)
|
|
81
|
+
rb1.grid(row=1, column=2)
|
|
82
|
+
rb2 = tk.Radiobutton(
|
|
83
|
+
frame00,
|
|
84
|
+
text="2",
|
|
85
|
+
variable=self.axis,
|
|
86
|
+
value=2,
|
|
87
|
+
command=lambda: self.plot_plane(),
|
|
88
|
+
)
|
|
89
|
+
rb2.grid(row=1, column=3)
|
|
90
|
+
|
|
91
|
+
# row 2-4: intensity specs
|
|
92
|
+
intlabel = tk.Label(frame00, text="intensity:")
|
|
93
|
+
intlabel.grid(row=2, column=0, pady=1, sticky=tk.W)
|
|
94
|
+
maxintlabel = tk.Label(frame00, text="max:")
|
|
95
|
+
maxintlabel.grid(row=3, column=0, pady=1, sticky=tk.E)
|
|
96
|
+
minintlabel = tk.Label(frame00, text="min:")
|
|
97
|
+
minintlabel.grid(row=4, column=0, pady=1, sticky=tk.E)
|
|
98
|
+
sumintlabel = tk.Label(frame00, text="sum:")
|
|
99
|
+
sumintlabel.grid(row=5, column=0, pady=1, sticky=tk.E)
|
|
100
|
+
nanratiolabel = tk.Label(frame00, text="nan ratio:")
|
|
101
|
+
nanratiolabel.grid(row=6, column=0, pady=1, sticky=tk.E)
|
|
102
|
+
globallabel = tk.Label(frame00, text="global", width=7)
|
|
103
|
+
globallabel.grid(row=2, column=1)
|
|
104
|
+
self.globalmax = tk.Label(frame00, text="")
|
|
105
|
+
self.globalmax.grid(row=3, column=1)
|
|
106
|
+
self.globalmin = tk.Label(frame00, text="")
|
|
107
|
+
self.globalmin.grid(row=4, column=1)
|
|
108
|
+
self.globalsum = tk.Label(frame00, text="")
|
|
109
|
+
self.globalsum.grid(row=5, column=1)
|
|
110
|
+
self.globalnanratio = tk.Label(frame00, text="")
|
|
111
|
+
self.globalnanratio.grid(row=6, column=1)
|
|
112
|
+
inplanelabel = tk.Label(frame00, text="in plane", width=7)
|
|
113
|
+
inplanelabel.grid(row=2, column=2)
|
|
114
|
+
self.localmax = tk.Label(frame00, text="")
|
|
115
|
+
self.localmax.grid(row=3, column=2)
|
|
116
|
+
self.localmin = tk.Label(frame00, text="")
|
|
117
|
+
self.localmin.grid(row=4, column=2)
|
|
118
|
+
self.localsum = tk.Label(frame00, text="")
|
|
119
|
+
self.localsum.grid(row=5, column=2)
|
|
120
|
+
self.localnanratio = tk.Label(frame00, text="")
|
|
121
|
+
self.localnanratio.grid(row=6, column=2)
|
|
122
|
+
colorbarlabel = tk.Label(frame00, text="colorbar")
|
|
123
|
+
colorbarlabel.grid(row=2, column=3)
|
|
124
|
+
self.colorbarmax = tk.Entry(frame00, width=7)
|
|
125
|
+
self.colorbarmax.grid(row=3, column=3)
|
|
126
|
+
self.colorbarmin = tk.Entry(frame00, width=7)
|
|
127
|
+
self.colorbarmin.grid(row=4, column=3)
|
|
128
|
+
set_range = Button(frame00, text="set range", command=lambda: self.colorrange_upd())
|
|
129
|
+
set_range.grid(row=2, column=4)
|
|
130
|
+
toglobalmax = Button(
|
|
131
|
+
frame00,
|
|
132
|
+
text="global max",
|
|
133
|
+
command=lambda: self.multiple_funcs(
|
|
134
|
+
self.colorbarmax.delete(0, len(self.colorbarmax.get())),
|
|
135
|
+
self.colorbarmax.insert(0, self.globalmax["text"]),
|
|
136
|
+
),
|
|
137
|
+
)
|
|
138
|
+
toglobalmax.grid(row=3, column=4)
|
|
139
|
+
toglobalmin = Button(
|
|
140
|
+
frame00,
|
|
141
|
+
text="global min",
|
|
142
|
+
command=lambda: self.multiple_funcs(
|
|
143
|
+
self.colorbarmin.delete(0, len(self.colorbarmin.get())),
|
|
144
|
+
self.colorbarmin.insert(0, self.globalmin["text"]),
|
|
145
|
+
),
|
|
146
|
+
)
|
|
147
|
+
toglobalmin.grid(row=4, column=4)
|
|
148
|
+
|
|
149
|
+
# row 7-8: animation - automatic slicing through the planes
|
|
150
|
+
anilabel = tk.Label(frame00, text="animation speed [ms]")
|
|
151
|
+
anilabel.grid(row=7, column=3, columnspan=2, sticky=tk.W)
|
|
152
|
+
self.anientry = tk.Entry(frame00, width=7)
|
|
153
|
+
self.anientry.grid(row=8, column=3)
|
|
154
|
+
anibutton = Button(frame00, text="animation", command=lambda: self.animation())
|
|
155
|
+
anibutton.grid(row=8, column=4)
|
|
156
|
+
|
|
157
|
+
# row 10-12 Fourier transformation
|
|
158
|
+
seperator = tk.Label(
|
|
159
|
+
frame00, text=" "
|
|
160
|
+
) # __________________________________________________________________")
|
|
161
|
+
seperator.grid(row=9, column=0, columnspan=5)
|
|
162
|
+
cutofflabel = tk.Label(frame00, text="cutoff frequency")
|
|
163
|
+
cutofflabel.grid(row=10, column=2, columnspan=2)
|
|
164
|
+
qminlabel = tk.Label(frame00, text="qmin [px]:")
|
|
165
|
+
qminlabel.grid(row=11, column=2, sticky=tk.E)
|
|
166
|
+
qmaxlabel = tk.Label(frame00, text="qmax [px]:")
|
|
167
|
+
qmaxlabel.grid(row=12, column=2, sticky=tk.E)
|
|
168
|
+
self.qminentry = tk.Entry(frame00, width=7)
|
|
169
|
+
self.qminentry.grid(row=11, column=3)
|
|
170
|
+
self.qmaxentry = tk.Entry(frame00, width=7)
|
|
171
|
+
self.qmaxentry.grid(row=12, column=3)
|
|
172
|
+
self.cutoff = tk.IntVar()
|
|
173
|
+
newcutoffbutton = Button(frame00, text="new cutoff", command=lambda: self.newcutoff())
|
|
174
|
+
newcutoffbutton.grid(row=10, column=4)
|
|
175
|
+
cutoffon = tk.Radiobutton(
|
|
176
|
+
frame00,
|
|
177
|
+
text="on",
|
|
178
|
+
variable=self.cutoff,
|
|
179
|
+
value=1,
|
|
180
|
+
command=lambda: self.applycutoff(),
|
|
181
|
+
)
|
|
182
|
+
cutoffon.grid(row=11, column=4, sticky=tk.W)
|
|
183
|
+
cutoffoff = tk.Radiobutton(
|
|
184
|
+
frame00,
|
|
185
|
+
text="off",
|
|
186
|
+
variable=self.cutoff,
|
|
187
|
+
value=0,
|
|
188
|
+
command=lambda: self.redocutuff(),
|
|
189
|
+
)
|
|
190
|
+
cutoffoff.grid(row=12, column=4, sticky=tk.W)
|
|
191
|
+
|
|
192
|
+
spacelabel = tk.Label(frame00, text="Space Selection")
|
|
193
|
+
spacelabel.grid(row=10, column=0, columnspan=2, sticky=tk.W)
|
|
194
|
+
self.space = tk.IntVar()
|
|
195
|
+
reciprocal = tk.Radiobutton(
|
|
196
|
+
frame00,
|
|
197
|
+
text="reciprocal space",
|
|
198
|
+
variable=self.space,
|
|
199
|
+
value=0,
|
|
200
|
+
command=lambda: self.ifft(),
|
|
201
|
+
pady=5,
|
|
202
|
+
)
|
|
203
|
+
reciprocal.grid(row=11, column=0, columnspan=2, sticky=tk.W)
|
|
204
|
+
fft = tk.Radiobutton(
|
|
205
|
+
frame00,
|
|
206
|
+
text="real space",
|
|
207
|
+
variable=self.space,
|
|
208
|
+
value=1,
|
|
209
|
+
command=lambda: self.fft(),
|
|
210
|
+
)
|
|
211
|
+
fft.grid(row=12, column=0, columnspan=2, sticky=tk.W)
|
|
212
|
+
|
|
213
|
+
# 01 #
|
|
214
|
+
# frame 01, upper right
|
|
215
|
+
self.frame01 = tk.Frame(self, bg="#cccccc")
|
|
216
|
+
self.frame01.place(x=400, y=0) # , height=HEIGHT//2, width=WIDTH//2)
|
|
217
|
+
|
|
218
|
+
self.plane_num = tk.IntVar()
|
|
219
|
+
|
|
220
|
+
self.slider = tk.Scale(
|
|
221
|
+
self.frame01,
|
|
222
|
+
variable=self.plane_num,
|
|
223
|
+
from_=0,
|
|
224
|
+
to=500,
|
|
225
|
+
label="slider",
|
|
226
|
+
orient=tk.HORIZONTAL,
|
|
227
|
+
length=WIDTH // 2, # resolution=-1,
|
|
228
|
+
command=lambda x: self.multiple_funcs(self.plot_plane(), self.intensity_upd_local()),
|
|
229
|
+
)
|
|
230
|
+
# command=lambda p: self.plot_plane())
|
|
231
|
+
self.slider.grid(row=0, column=0, padx=10, pady=10, sticky=tk.N + tk.E + tk.S + tk.W)
|
|
232
|
+
|
|
233
|
+
self.frame01_plotcell = tk.Frame(self.frame01)
|
|
234
|
+
self.frame01_plotcell.grid(row=1, column=0, padx=10, pady=10, sticky=tk.N + tk.E + tk.S + tk.W)
|
|
235
|
+
|
|
236
|
+
self.frame01_toolbar = tk.Frame(self.frame01)
|
|
237
|
+
self.frame01_toolbar.grid(row=2, column=0)
|
|
238
|
+
|
|
239
|
+
# 10 #
|
|
240
|
+
# frame 10, lower left
|
|
241
|
+
frame10 = tk.Frame(self)
|
|
242
|
+
frame10.place(x=5, y=HEIGHT - 30) # , height=HEIGHT//2, width=WIDTH//2)
|
|
243
|
+
quit = Button(
|
|
244
|
+
frame10,
|
|
245
|
+
text="exit",
|
|
246
|
+
command=lambda: self.multiple_funcs(print("Session ended...\n", self.quit())),
|
|
247
|
+
)
|
|
248
|
+
quit.pack(side=tk.TOP)
|
|
249
|
+
|
|
250
|
+
# 11 #
|
|
251
|
+
# frame 00, lower right
|
|
252
|
+
# no functionality
|
|
253
|
+
frame11 = tk.Frame(self)
|
|
254
|
+
frame11.place(x=WIDTH // 2, y=HEIGHT // 2) # , height=HEIGHT//2, width=WIDTH//2)
|
|
255
|
+
|
|
256
|
+
def load_cube(self):
|
|
257
|
+
"""
|
|
258
|
+
loads 3D array in h5py file format from the filename input panel
|
|
259
|
+
3D array is expected to be a reconstructed reciprocal scattering volume
|
|
260
|
+
when executed, one slide perpendicular to the selected axis will be plotted in the plot panel
|
|
261
|
+
"""
|
|
262
|
+
|
|
263
|
+
filename = self.filename_entry.get()
|
|
264
|
+
f = h5py.File(filename, "r")
|
|
265
|
+
try:
|
|
266
|
+
if "data" in f.keys():
|
|
267
|
+
self.cube = np.array(f["data"])
|
|
268
|
+
elif "rebinned_data" in f.keys():
|
|
269
|
+
self.cube = np.array(f["rebinned_data"])
|
|
270
|
+
except Exception:
|
|
271
|
+
raise KeyError(
|
|
272
|
+
"- No data found in "
|
|
273
|
+
+ filename
|
|
274
|
+
+ " :( ..."
|
|
275
|
+
+ "\nchange to alternative keys: "
|
|
276
|
+
+ str(list(f.keys()))
|
|
277
|
+
)
|
|
278
|
+
print("- file loaded: {}".format(filename))
|
|
279
|
+
|
|
280
|
+
self.slider.destroy()
|
|
281
|
+
self.slider = tk.Scale(
|
|
282
|
+
self.frame01,
|
|
283
|
+
variable=self.plane_num,
|
|
284
|
+
from_=0,
|
|
285
|
+
to=len(self.cube) - 1,
|
|
286
|
+
label="slider",
|
|
287
|
+
orient=tk.HORIZONTAL,
|
|
288
|
+
length=WIDTH // 2, # resolution=-1,
|
|
289
|
+
command=lambda x: self.multiple_funcs(self.plot_plane(), self.intensity_upd_local()),
|
|
290
|
+
)
|
|
291
|
+
self.slider.grid(row=0, column=0, padx=10, pady=10, sticky=tk.N + tk.E + tk.S + tk.W)
|
|
292
|
+
|
|
293
|
+
if not self.loaded:
|
|
294
|
+
|
|
295
|
+
fig, ax = plt.subplots(figsize=(4.95, 4.95))
|
|
296
|
+
fig = plt.gcf()
|
|
297
|
+
DPI = fig.get_dpi()
|
|
298
|
+
fig.set_size_inches(500 / float(DPI), 500 / float(DPI))
|
|
299
|
+
|
|
300
|
+
self.plane_num.set(np.shape(self.cube)[0] // 2)
|
|
301
|
+
|
|
302
|
+
if self.axis.get() == 0:
|
|
303
|
+
self.im = plt.imshow(self.cube[self.plane_num.get(), :, :])
|
|
304
|
+
elif self.axis.get() == 1:
|
|
305
|
+
self.im = plt.imshow(self.cube[:, self.plane_num.get(), :])
|
|
306
|
+
elif self.axis.get() == 2:
|
|
307
|
+
self.im = plt.imshow(self.cube[:, :, self.plane_num.get()])
|
|
308
|
+
else:
|
|
309
|
+
raise ValueError("axis must be 0,1,2")
|
|
310
|
+
plt.colorbar(shrink=0.81)
|
|
311
|
+
ax.set_xlabel("pixel")
|
|
312
|
+
ax.set_ylabel("pixel")
|
|
313
|
+
self.canvas = FigureCanvasTkAgg(fig, master=self.frame01_plotcell)
|
|
314
|
+
self.toolbar = NavigationToolbar2Tk(self.canvas, self.frame01_toolbar)
|
|
315
|
+
self.toolbar.pack(side=tk.LEFT)
|
|
316
|
+
# self.toolbar.children['!button6'].pack_forget()
|
|
317
|
+
# self.toolbar.children['!button7'].pack_forget()
|
|
318
|
+
self.toolbar.update()
|
|
319
|
+
self.canvas.draw()
|
|
320
|
+
self.canvas.get_tk_widget().pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
|
|
321
|
+
self.loaded = True
|
|
322
|
+
|
|
323
|
+
else:
|
|
324
|
+
self.plot_plane()
|
|
325
|
+
self.transformed = False
|
|
326
|
+
self.transcutted = False
|
|
327
|
+
self.cutted = False
|
|
328
|
+
self.cutoff.set(0)
|
|
329
|
+
self.space.set(0)
|
|
330
|
+
|
|
331
|
+
self.intensity_upd_global()
|
|
332
|
+
|
|
333
|
+
def plot_plane(self):
|
|
334
|
+
"""update plotted plane perpendicular to the selected axis"""
|
|
335
|
+
if self.axis.get() == 0:
|
|
336
|
+
self.im.set_data(self.cube[self.plane_num.get(), :, :])
|
|
337
|
+
elif self.axis.get() == 1:
|
|
338
|
+
self.im.set_data(self.cube[:, self.plane_num.get(), :])
|
|
339
|
+
elif self.axis.get() == 2:
|
|
340
|
+
self.im.set_data(self.cube[:, :, self.plane_num.get()])
|
|
341
|
+
else:
|
|
342
|
+
raise ValueError("axis must be 0,1,2")
|
|
343
|
+
self.canvas.draw()
|
|
344
|
+
|
|
345
|
+
def colorrange_upd(self):
|
|
346
|
+
"""change color range in plot"""
|
|
347
|
+
try:
|
|
348
|
+
if self.colorbarmin.get() and self.colorbarmax.get():
|
|
349
|
+
vmin = float(self.colorbarmin.get())
|
|
350
|
+
vmax = float(self.colorbarmax.get())
|
|
351
|
+
elif self.colorbarmin.get():
|
|
352
|
+
vmin = float(self.colorbarmin.get())
|
|
353
|
+
vmax = self.globalmax["text"]
|
|
354
|
+
elif self.colorbarmax.get():
|
|
355
|
+
vmin = self.globalmin["text"]
|
|
356
|
+
vmax = float(self.colorbarmax.get())
|
|
357
|
+
else:
|
|
358
|
+
vmin = self.globalmin["text"]
|
|
359
|
+
vmax = self.globalmax["text"]
|
|
360
|
+
except ValueError:
|
|
361
|
+
print("Oops... colorbar range must be a number or empty string.")
|
|
362
|
+
self.im.set_clim(vmin, vmax)
|
|
363
|
+
self.plot_plane()
|
|
364
|
+
|
|
365
|
+
def intensity_upd_local(self):
|
|
366
|
+
"""show local intensity minimum, maximum and sum of current plotted plane"""
|
|
367
|
+
if self.axis.get() == 0:
|
|
368
|
+
plane = self.cube[self.plane_num.get(), :, :]
|
|
369
|
+
elif self.axis.get() == 1:
|
|
370
|
+
plane = self.cube[:, self.plane_num.get(), :]
|
|
371
|
+
elif self.axis.get() == 2:
|
|
372
|
+
plane = self.cube[:, :, self.plane_num.get()]
|
|
373
|
+
nan_ratio = np.count_nonzero(np.isnan(plane)) / plane.size
|
|
374
|
+
self.localmax["text"] = "{}".format(np.format_float_scientific(np.nanmax(plane), 1))
|
|
375
|
+
self.localmin["text"] = "{}".format(np.format_float_scientific(np.nanmin(plane), 1))
|
|
376
|
+
self.localsum["text"] = "{}".format(np.format_float_scientific(np.nansum(plane), 1))
|
|
377
|
+
self.localnanratio["text"] = "{}".format(round(nan_ratio, 2))
|
|
378
|
+
|
|
379
|
+
def intensity_upd_global(self):
|
|
380
|
+
"""show global intensity minimum, maximum and sum of 3D array"""
|
|
381
|
+
self.intensity_upd_local()
|
|
382
|
+
nan_ratio = np.count_nonzero(np.isnan(self.cube)) / self.cube.size
|
|
383
|
+
self.globalmax["text"] = "{}".format(np.format_float_scientific(np.nanmax(self.cube), 1))
|
|
384
|
+
self.globalmin["text"] = "{}".format(np.format_float_scientific(np.nanmin(self.cube), 1))
|
|
385
|
+
self.globalsum["text"] = "{}".format(np.format_float_scientific(np.nansum(self.cube), 1))
|
|
386
|
+
self.globalnanratio["text"] = "{}".format(round(nan_ratio, 2))
|
|
387
|
+
|
|
388
|
+
def fft(self):
|
|
389
|
+
"""
|
|
390
|
+
Fourier transform 3D array from reciprocal to real space
|
|
391
|
+
the origin of reciprocal and real space is expected to be the central voxel
|
|
392
|
+
"""
|
|
393
|
+
|
|
394
|
+
def perform_fft(fftholder):
|
|
395
|
+
time0 = time.time()
|
|
396
|
+
fftholder = np.nan_to_num(fftholder)
|
|
397
|
+
size = list(fftholder.shape)
|
|
398
|
+
fftholder = np.fft.ifftshift(fftholder)
|
|
399
|
+
fftholder = np.fft.fftn(fftholder, s=size, norm="ortho")
|
|
400
|
+
fftholder = np.fft.fftshift(fftholder)
|
|
401
|
+
fftholder = fftholder.real
|
|
402
|
+
fftdur = time.time() - time0
|
|
403
|
+
print("- FFT performed in {} sec.".format(round(fftdur, 4)))
|
|
404
|
+
return fftholder
|
|
405
|
+
|
|
406
|
+
if not self.transformed and not self.transcutted: # no fft at all yet
|
|
407
|
+
if not self.cutoff.get():
|
|
408
|
+
self.cube_reci = self.cube
|
|
409
|
+
self.cube = perform_fft(self.cube)
|
|
410
|
+
self.cube_real = self.cube
|
|
411
|
+
self.transformed = True
|
|
412
|
+
else:
|
|
413
|
+
self.cube_recicut = self.cube
|
|
414
|
+
self.cube = perform_fft(self.cube)
|
|
415
|
+
self.cube_realcut = self.cube
|
|
416
|
+
self.transcutted = True
|
|
417
|
+
|
|
418
|
+
elif not self.transformed and self.transcutted:
|
|
419
|
+
if not self.cutoff.get():
|
|
420
|
+
self.cube = perform_fft(self.cube_reci)
|
|
421
|
+
self.cube_real = self.cube
|
|
422
|
+
self.transformed = True
|
|
423
|
+
else:
|
|
424
|
+
self.cube = self.cube_realcut
|
|
425
|
+
|
|
426
|
+
elif self.transformed and not self.transcutted:
|
|
427
|
+
if not self.cutoff.get():
|
|
428
|
+
self.cube_reci = self.cube
|
|
429
|
+
self.cube = self.cube_real
|
|
430
|
+
else:
|
|
431
|
+
self.cube = perform_fft(self.cube_recicut)
|
|
432
|
+
# self.cube = self.cube_realcut
|
|
433
|
+
self.transcutted = True
|
|
434
|
+
|
|
435
|
+
else:
|
|
436
|
+
if not self.cutoff.get():
|
|
437
|
+
self.cube = self.cube_real
|
|
438
|
+
else:
|
|
439
|
+
self.cube = self.cube_realcut
|
|
440
|
+
|
|
441
|
+
print("- Switching to real space")
|
|
442
|
+
|
|
443
|
+
self.plot_plane()
|
|
444
|
+
self.intensity_upd_global()
|
|
445
|
+
|
|
446
|
+
def ifft(self):
|
|
447
|
+
"""
|
|
448
|
+
Inverse Fourier transform 3D array from real to reciprocal space
|
|
449
|
+
the origin of real and reciprocal space is expected to be the central voxel
|
|
450
|
+
"""
|
|
451
|
+
if not self.cutoff.get():
|
|
452
|
+
self.cube_real = self.cube
|
|
453
|
+
self.cube = self.cube_reci
|
|
454
|
+
else:
|
|
455
|
+
self.cube_realcut = self.cube
|
|
456
|
+
self.cube = self.cube_recicut
|
|
457
|
+
|
|
458
|
+
print("- Switching to reciprocal space")
|
|
459
|
+
|
|
460
|
+
self.plot_plane()
|
|
461
|
+
self.intensity_upd_global()
|
|
462
|
+
|
|
463
|
+
def applycutoff(self):
|
|
464
|
+
"""
|
|
465
|
+
reassign all voxels with distance smaller than qmin and greater than qmax
|
|
466
|
+
from the central voxel to 0.0
|
|
467
|
+
qmin, qmax is loaded from the qmin, qmax input panel
|
|
468
|
+
currently opperates in units of pixels
|
|
469
|
+
"""
|
|
470
|
+
if not self.cutted:
|
|
471
|
+
|
|
472
|
+
time0 = time.time()
|
|
473
|
+
X, Y, Z = self.cube.shape
|
|
474
|
+
sphere = np.ones((X, Y, Z))
|
|
475
|
+
qmin = float(self.qminentry.get())
|
|
476
|
+
qmax = float(self.qmaxentry.get())
|
|
477
|
+
# convert qmin to pixels
|
|
478
|
+
# convert qmax to pixels
|
|
479
|
+
r2_inner = qmin**2
|
|
480
|
+
r2_outer = qmax**2
|
|
481
|
+
XS, YS, ZS = np.meshgrid(np.arange(X), np.arange(Y), np.arange(Z))
|
|
482
|
+
R2 = (XS - X // 2) ** 2 + (YS - Y // 2) ** 2 + (ZS - Z // 2) ** 2
|
|
483
|
+
mask = (R2 <= r2_inner) | (R2 >= r2_outer)
|
|
484
|
+
sphere[mask] = np.nan
|
|
485
|
+
cutdur = time.time() - time0
|
|
486
|
+
|
|
487
|
+
if self.space.get():
|
|
488
|
+
self.cube_real = self.cube
|
|
489
|
+
self.cube = self.cube_reci * sphere
|
|
490
|
+
self.cube_recicut = self.cube
|
|
491
|
+
print("- Cutoff below {} and beyond {} in {} sec.".format(qmin, qmax, round(cutdur, 4)))
|
|
492
|
+
self.fft()
|
|
493
|
+
else:
|
|
494
|
+
self.cube_reci = self.cube
|
|
495
|
+
self.cube = self.cube * sphere
|
|
496
|
+
self.cube_recicut = self.cube
|
|
497
|
+
self.plot_plane()
|
|
498
|
+
self.intensity_upd_global()
|
|
499
|
+
print("- Cutoff below {} and beyond {} in {} sec.".format(qmin, qmax, round(cutdur, 4)))
|
|
500
|
+
|
|
501
|
+
self.cutted = True
|
|
502
|
+
|
|
503
|
+
else:
|
|
504
|
+
if self.space.get(): # in real space
|
|
505
|
+
self.cube = self.cube_realcut
|
|
506
|
+
else:
|
|
507
|
+
self.cube = self.cube_recicut
|
|
508
|
+
self.plot_plane()
|
|
509
|
+
self.intensity_upd_global()
|
|
510
|
+
|
|
511
|
+
def redocutuff(self):
|
|
512
|
+
if self.space.get(): # in real space
|
|
513
|
+
self.cube_realcut = self.cube
|
|
514
|
+
if not self.transformed:
|
|
515
|
+
self.fft()
|
|
516
|
+
self.cube = self.cube_real
|
|
517
|
+
else:
|
|
518
|
+
self.cube_recicut = self.cube
|
|
519
|
+
self.cube = self.cube_reci
|
|
520
|
+
self.plot_plane()
|
|
521
|
+
self.intensity_upd_global()
|
|
522
|
+
|
|
523
|
+
def newcutoff(self):
|
|
524
|
+
if self.cutoff.get():
|
|
525
|
+
if self.space.get() and self.transformed:
|
|
526
|
+
self.cube = self.cube_real
|
|
527
|
+
else:
|
|
528
|
+
self.cube = self.cube_reci
|
|
529
|
+
self.cutted = False
|
|
530
|
+
self.transcutted = False
|
|
531
|
+
self.applycutoff()
|
|
532
|
+
|
|
533
|
+
def plot_next_plane(self):
|
|
534
|
+
n = self.plane_num.get()
|
|
535
|
+
if n == len(self.cube[self.axis.get()]) - 1:
|
|
536
|
+
n = 0
|
|
537
|
+
else:
|
|
538
|
+
n += 1
|
|
539
|
+
self.plane_num.set(n)
|
|
540
|
+
self.plot_plane()
|
|
541
|
+
|
|
542
|
+
def animation(self):
|
|
543
|
+
"""
|
|
544
|
+
slices through the 3D array along the selcted axis
|
|
545
|
+
"""
|
|
546
|
+
try:
|
|
547
|
+
if not self.anientry.get():
|
|
548
|
+
anispeed = 1
|
|
549
|
+
else:
|
|
550
|
+
anispeed = self.anientry.get()
|
|
551
|
+
except ValueError:
|
|
552
|
+
print("Oops... animation speed must be an integer > 0 or empty string.")
|
|
553
|
+
n = self.plane_num.get() - 1
|
|
554
|
+
while n is not self.plane_num.get():
|
|
555
|
+
self.slider.after(anispeed, self.plot_next_plane())
|
|
556
|
+
self.plot_next_plane()
|
|
557
|
+
|
|
558
|
+
def multiple_funcs(*funcs):
|
|
559
|
+
for func in funcs:
|
|
560
|
+
func
|
|
561
|
+
|
|
562
|
+
|
|
563
|
+
def main():
|
|
564
|
+
root = tk.Tk()
|
|
565
|
+
root.geometry("{}x{}+{}+{}".format(WIDTH, HEIGHT, XPOS, YPOS))
|
|
566
|
+
Gui()
|
|
567
|
+
root.mainloop()
|
|
568
|
+
|
|
569
|
+
|
|
570
|
+
if __name__ == "__main__":
|
|
571
|
+
main()
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
##############################################################################
|
|
3
|
+
#
|
|
4
|
+
# (c) 2024 The Trustees of Columbia University in the City of New York.
|
|
5
|
+
# All rights reserved.
|
|
6
|
+
#
|
|
7
|
+
# File coded by: Billinge Group members and community contributors.
|
|
8
|
+
#
|
|
9
|
+
# See GitHub contributions for a more detailed list of contributors.
|
|
10
|
+
# https://github.com/diffpy/diffpy.fourigui/graphs/contributors
|
|
11
|
+
#
|
|
12
|
+
# See LICENSE.rst for license information.
|
|
13
|
+
#
|
|
14
|
+
##############################################################################
|
|
15
|
+
|
|
16
|
+
"""Definition of __version__."""
|
|
17
|
+
|
|
18
|
+
# We do not use the other three variables, but can be added back if needed.
|
|
19
|
+
# __all__ = ["__date__", "__git_commit__", "__timestamp__", "__version__"]
|
|
20
|
+
|
|
21
|
+
# obtain version information
|
|
22
|
+
from importlib.metadata import version
|
|
23
|
+
|
|
24
|
+
__version__ = version("diffpy.fourigui")
|
|
25
|
+
|
|
26
|
+
# End of file
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024, The Trustees of Columbia University
|
|
4
|
+
in the City of New York.
|
|
5
|
+
All rights reserved.
|
|
6
|
+
|
|
7
|
+
Redistribution and use in source and binary forms, with or without
|
|
8
|
+
modification, are permitted provided that the following conditions are met:
|
|
9
|
+
|
|
10
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
11
|
+
list of conditions and the following disclaimer.
|
|
12
|
+
|
|
13
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
14
|
+
this list of conditions and the following disclaimer in the documentation
|
|
15
|
+
and/or other materials provided with the distribution.
|
|
16
|
+
|
|
17
|
+
3. Neither the name of the copyright holder nor the names of its contributors
|
|
18
|
+
may be used to endorse or promote products derived from this software
|
|
19
|
+
without specific prior written permission.
|
|
20
|
+
|
|
21
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
22
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
23
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
24
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
25
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
26
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
27
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
28
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
29
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
30
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: diffpy.fourigui
|
|
3
|
+
Version: 0.1.0rc0
|
|
4
|
+
Summary: Tool for visualizing 3D diffraction and PDF Images.
|
|
5
|
+
Author-email: "Simon J.L. Billinge group" <simon.billinge@gmail.com>
|
|
6
|
+
Maintainer-email: "Simon J.L. Billinge group" <simon.billinge@gmail.com>
|
|
7
|
+
Project-URL: Homepage, https://github.com/diffpy/diffpy.fourigui/
|
|
8
|
+
Project-URL: Issues, https://github.com/diffpy/diffpy.fourigui/issues/
|
|
9
|
+
Keywords: diffraction,pdf,pair distribution function,gui
|
|
10
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
15
|
+
Classifier: Operating System :: MacOS :: MacOS X
|
|
16
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
17
|
+
Classifier: Operating System :: POSIX
|
|
18
|
+
Classifier: Operating System :: Unix
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
23
|
+
Classifier: Topic :: Scientific/Engineering :: Chemistry
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Description-Content-Type: text/x-rst
|
|
26
|
+
License-File: LICENSE.rst
|
|
27
|
+
License-File: AUTHORS.rst
|
|
28
|
+
Requires-Dist: h5py
|
|
29
|
+
Requires-Dist: time
|
|
30
|
+
Requires-Dist: tk
|
|
31
|
+
Requires-Dist: matplotlib
|
|
32
|
+
Requires-Dist: numpy
|
|
33
|
+
|
|
34
|
+
|Icon| |title|_
|
|
35
|
+
===============
|
|
36
|
+
|
|
37
|
+
.. |title| replace:: diffpy.fourigui
|
|
38
|
+
.. _title: https://diffpy.github.io/diffpy.fourigui
|
|
39
|
+
|
|
40
|
+
.. |Icon| image:: https://avatars.githubusercontent.com/diffpy
|
|
41
|
+
:target: https://diffpy.github.io/diffpy.fourigui
|
|
42
|
+
:height: 100px
|
|
43
|
+
|
|
44
|
+
|PyPi| |Forge| |PythonVersion| |PR|
|
|
45
|
+
|
|
46
|
+
|CI| |Codecov| |Black| |Tracking|
|
|
47
|
+
|
|
48
|
+
.. |Black| image:: https://img.shields.io/badge/code_style-black-black
|
|
49
|
+
:target: https://github.com/psf/black
|
|
50
|
+
|
|
51
|
+
.. |CI| image:: https://github.com/diffpy/diffpy.fourigui/actions/workflows/matrix-and-codecov-on-merge-to-main.yml/badge.svg
|
|
52
|
+
:target: https://github.com/diffpy/diffpy.fourigui/actions/workflows/matrix-and-codecov-on-merge-to-main.yml
|
|
53
|
+
|
|
54
|
+
.. |Codecov| image:: https://codecov.io/gh/diffpy/diffpy.fourigui/branch/main/graph/badge.svg
|
|
55
|
+
:target: https://codecov.io/gh/diffpy/diffpy.fourigui
|
|
56
|
+
|
|
57
|
+
.. |Forge| image:: https://img.shields.io/conda/vn/conda-forge/diffpy.fourigui
|
|
58
|
+
:target: https://anaconda.org/conda-forge/diffpy.fourigui
|
|
59
|
+
|
|
60
|
+
.. |PR| image:: https://img.shields.io/badge/PR-Welcome-29ab47ff
|
|
61
|
+
|
|
62
|
+
.. |PyPi| image:: https://img.shields.io/pypi/v/diffpy.fourigui
|
|
63
|
+
:target: https://pypi.org/project/diffpy.fourigui/
|
|
64
|
+
|
|
65
|
+
.. |PythonVersion| image:: https://img.shields.io/pypi/pyversions/diffpy.fourigui
|
|
66
|
+
:target: https://pypi.org/project/diffpy.fourigui/
|
|
67
|
+
|
|
68
|
+
.. |Tracking| image:: https://img.shields.io/badge/issue_tracking-github-blue
|
|
69
|
+
:target: https://github.com/diffpy/diffpy.fourigui/issues
|
|
70
|
+
|
|
71
|
+
Tool for visualizing 3D diffraction and PDF Images.
|
|
72
|
+
|
|
73
|
+
* LONGER DESCRIPTION HERE
|
|
74
|
+
|
|
75
|
+
For more information about the diffpy.fourigui library, please consult our `online documentation <https://diffpy.github.io/diffpy.fourigui>`_.
|
|
76
|
+
|
|
77
|
+
Citation
|
|
78
|
+
--------
|
|
79
|
+
|
|
80
|
+
If you use diffpy.fourigui in a scientific publication, we would like you to cite this package as
|
|
81
|
+
|
|
82
|
+
diffpy.fourigui Package, https://github.com/diffpy/diffpy.fourigui
|
|
83
|
+
|
|
84
|
+
Installation
|
|
85
|
+
------------
|
|
86
|
+
|
|
87
|
+
The preferred method is to use `Miniconda Python
|
|
88
|
+
<https://docs.conda.io/projects/miniconda/en/latest/miniconda-install.html>`_
|
|
89
|
+
and install from the "conda-forge" channel of Conda packages.
|
|
90
|
+
|
|
91
|
+
To add "conda-forge" to the conda channels, run the following in a terminal. ::
|
|
92
|
+
|
|
93
|
+
conda config --add channels conda-forge
|
|
94
|
+
|
|
95
|
+
We want to install our packages in a suitable conda environment.
|
|
96
|
+
The following creates and activates a new environment named ``diffpy.fourigui_env`` ::
|
|
97
|
+
|
|
98
|
+
conda create -n diffpy.fourigui_env python=3
|
|
99
|
+
conda activate diffpy.fourigui_env
|
|
100
|
+
|
|
101
|
+
Then, to fully install ``diffpy.fourigui`` in our active environment, run ::
|
|
102
|
+
|
|
103
|
+
conda install diffpy.fourigui
|
|
104
|
+
|
|
105
|
+
Another option is to use ``pip`` to download and install the latest release from
|
|
106
|
+
`Python Package Index <https://pypi.python.org>`_.
|
|
107
|
+
To install using ``pip`` into your ``diffpy.fourigui_env`` environment, we will also have to install dependencies ::
|
|
108
|
+
|
|
109
|
+
pip install -r https://raw.githubusercontent.com/diffpy/diffpy.fourigui/main/requirements/run.txt
|
|
110
|
+
|
|
111
|
+
and then install the package ::
|
|
112
|
+
|
|
113
|
+
pip install diffpy.fourigui
|
|
114
|
+
|
|
115
|
+
If you prefer to install from sources, after installing the dependencies, obtain the source archive from
|
|
116
|
+
`GitHub <https://github.com/diffpy/diffpy.fourigui/>`_. Once installed, ``cd`` into your ``diffpy.fourigui`` directory
|
|
117
|
+
and run the following ::
|
|
118
|
+
|
|
119
|
+
pip install .
|
|
120
|
+
|
|
121
|
+
Support and Contribute
|
|
122
|
+
----------------------
|
|
123
|
+
|
|
124
|
+
`Diffpy user group <https://groups.google.com/g/diffpy-users>`_ is the discussion forum for general questions and discussions about the use of diffpy.fourigui. Please join the diffpy.fourigui users community by joining the Google group. The diffpy.fourigui project welcomes your expertise and enthusiasm!
|
|
125
|
+
|
|
126
|
+
If you see a bug or want to request a feature, please `report it as an issue <https://github.com/diffpy/diffpy.fourigui/issues>`_ and/or `submit a fix as a PR <https://github.com/diffpy/diffpy.fourigui/pulls>`_. You can also post it to the `Diffpy user group <https://groups.google.com/g/diffpy-users>`_.
|
|
127
|
+
|
|
128
|
+
Feel free to fork the project and contribute. To install diffpy.fourigui
|
|
129
|
+
in a development mode, with its sources being directly used by Python
|
|
130
|
+
rather than copied to a package directory, use the following in the root
|
|
131
|
+
directory ::
|
|
132
|
+
|
|
133
|
+
pip install -e .
|
|
134
|
+
|
|
135
|
+
To ensure code quality and to prevent accidental commits into the default branch, please set up the use of our pre-commit
|
|
136
|
+
hooks.
|
|
137
|
+
|
|
138
|
+
1. Install pre-commit in your working environment by running ``conda install pre-commit``.
|
|
139
|
+
|
|
140
|
+
2. Initialize pre-commit (one time only) ``pre-commit install``.
|
|
141
|
+
|
|
142
|
+
Thereafter your code will be linted by black and isort and checked against flake8 before you can commit.
|
|
143
|
+
If it fails by black or isort, just rerun and it should pass (black and isort will modify the files so should
|
|
144
|
+
pass after they are modified). If the flake8 test fails please see the error messages and fix them manually before
|
|
145
|
+
trying to commit again.
|
|
146
|
+
|
|
147
|
+
Improvements and fixes are always appreciated.
|
|
148
|
+
|
|
149
|
+
Before contribuing, please read our `Code of Conduct <https://github.com/diffpy/diffpy.fourigui/blob/main/CODE_OF_CONDUCT.rst>`_.
|
|
150
|
+
|
|
151
|
+
Contact
|
|
152
|
+
-------
|
|
153
|
+
|
|
154
|
+
For more information on diffpy.fourigui please visit the project `web-page <https://diffpy.github.io/>`_ or email Prof. Simon Billinge at sb2896@columbia.edu.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
diffpy/__init__.py,sha256=w43pJCjwSRowjr294Q6vQ_hWvIrnJRz3nbO9dLyluDU,672
|
|
2
|
+
diffpy/fourigui/__init__.py,sha256=XjMy6FaPr4PIhzyGWX2yYKUagX2Bl8B7Gw4i3wYML8Y,736
|
|
3
|
+
diffpy/fourigui/fourigui.py,sha256=UkS8hrO2bgUo6HbNYELuWAf0XZO7aeNvrep4b0TR1e0,21217
|
|
4
|
+
diffpy/fourigui/version.py,sha256=kPQ5HapKeTQzwpb53v984CBIDzBOI1Z0jGQIfAy1jys,843
|
|
5
|
+
diffpy.fourigui-0.1.0rc0.dist-info/AUTHORS.rst,sha256=3booMNorzYNNI3cqkYs-sWbimnSegFURpo7iSX6oKiU,184
|
|
6
|
+
diffpy.fourigui-0.1.0rc0.dist-info/LICENSE.rst,sha256=FFZAG9Hh02sJbGQEu06NuMxdgx_i1GuezTT4cKTyLkc,1568
|
|
7
|
+
diffpy.fourigui-0.1.0rc0.dist-info/METADATA,sha256=qbvUc8Lll6ilgTwTMtiUxvK3EvFbgtmbpGPxxTy4tU4,6583
|
|
8
|
+
diffpy.fourigui-0.1.0rc0.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
|
|
9
|
+
diffpy.fourigui-0.1.0rc0.dist-info/top_level.txt,sha256=34qLZyi9mxikpHepVDTMHrrNbe8VoOuz3ShYeiWA7KA,7
|
|
10
|
+
diffpy.fourigui-0.1.0rc0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
diffpy
|