llwp 2.1.3__tar.gz → 2.1.4__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.
llwp-2.1.4/MANIFEST.in ADDED
@@ -0,0 +1,4 @@
1
+ include llwp/IconLLWP.svg
2
+ include llwp/IconASAP.svg
3
+ include llwp/IconLLWPMac.png
4
+ include llwp/IconASAPMac.png
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: llwp
3
- Version: 2.1.3
3
+ Version: 2.1.4
4
4
  Summary: LLWP is a fast, efficient and easy solution for exploring and assigning spectra - relying on Loomis-Wood plots.
5
5
  Author-email: Luis Bonah <bonah@ph1.uni-koeln.de>
6
6
  License-Expression: GPL-3.0-only
@@ -766,11 +766,11 @@ class PlotWidget(QWidget):
766
766
  )
767
767
 
768
768
  if config["convolution_kernel"]:
769
- kernel_ys = np.array(config["convolution_kernel"])
769
+ xmin, xmax = self.xrange
770
+ kernel_ys = ConvolutionWindow.kernel_at((xmin + xmax) / 2)
770
771
  convolution_padding = len(kernel_ys) // 2
771
772
  stepwidth = config["convolution_stepwidth"]
772
773
 
773
- xmin, xmax = self.xrange
774
774
  n_xs = (xmax - xmin) // stepwidth + 1
775
775
  con_xs = np.arange(-n_xs, n_xs + 1) * stepwidth + (xmax + xmin) / 2
776
776
 
@@ -2745,7 +2745,7 @@ class LWPAx:
2745
2745
  )
2746
2746
 
2747
2747
  if config["convolution_kernel"]:
2748
- kernel_ys = np.array(config["convolution_kernel"])
2748
+ kernel_ys = ConvolutionWindow.kernel_at((xmin + xmax) / 2)
2749
2749
  convolution_padding = len(kernel_ys) // 2
2750
2750
  stepwidth = config["convolution_stepwidth"]
2751
2751
 
@@ -3262,6 +3262,9 @@ class LWPWidget(QGroupBox):
3262
3262
  self.fig.savefig(fname)
3263
3263
 
3264
3264
  def on_click(self, event):
3265
+ if event.canvas.widgetlock.locked(): # Pan or zoom of the matplotlib toolbar is active
3266
+ return
3267
+
3265
3268
  ax = event.inaxes
3266
3269
  index = np.asarray(np.where(self.axes == ax)).T
3267
3270
 
@@ -3908,11 +3911,11 @@ class MainWindow(QMainWindow):
3908
3911
  ]
3909
3912
  for folder in possible_folders:
3910
3913
  if sys.platform == "darwin":
3911
- iconpath = os.path.join(folder, f"{APP_TAG}Mac.png")
3914
+ iconpath = os.path.join(folder, f"Icon{APP_TAG}Mac.png")
3912
3915
  if os.path.isfile(iconpath):
3913
3916
  break
3914
3917
 
3915
- iconpath = os.path.join(folder, f"{APP_TAG}.svg")
3918
+ iconpath = os.path.join(folder, f"Icon{APP_TAG}.svg")
3916
3919
  if os.path.isfile(iconpath):
3917
3920
  break
3918
3921
 
@@ -4231,13 +4234,10 @@ class LLWP(QApplication):
4231
4234
  mainwindow = self.mainwindow_class(self)
4232
4235
  mainwindow.create_gui_components()
4233
4236
 
4234
- if len(sys.argv) > 1:
4235
- project = sys.argv[1]
4236
- if project != "--ASAP":
4237
- File.load_files(project)
4238
-
4239
4237
  mainwindow.show()
4240
4238
 
4239
+ self.load_command_line_files()
4240
+
4241
4241
  if messages:
4242
4242
  notify_warning.emit("\n".join(messages))
4243
4243
 
@@ -4284,6 +4284,28 @@ class LLWP(QApplication):
4284
4284
  file.color = "#000000"
4285
4285
  file.apply_color()
4286
4286
 
4287
+ @staticmethod
4288
+ def load_command_line_files():
4289
+ files = []
4290
+ invalid_files = []
4291
+ for argument in sys.argv[1:]:
4292
+ if argument == "--ASAP":
4293
+ continue
4294
+ if os.path.isfile(argument):
4295
+ files.append(os.path.abspath(argument))
4296
+ else:
4297
+ invalid_files.append(argument)
4298
+
4299
+ if invalid_files:
4300
+ invalid_files_string = ", ".join(invalid_files)
4301
+ notify_warning.emit(
4302
+ f"The following command line arguments are not existing and were ignored: {invalid_files_string}"
4303
+ )
4304
+
4305
+ if files:
4306
+ files_by_type = File.sort_files_by_type(files)
4307
+ File.add_multiple_files_by_type(files_by_type)
4308
+
4287
4309
  def run_init_commands(self):
4288
4310
  try:
4289
4311
  commands = config["commandlinedialog_commands"]
@@ -5391,6 +5413,9 @@ class AssignAllDialog(QDialog):
5391
5413
  NewAssignments.get_instance().add_rows(new_assignments)
5392
5414
 
5393
5415
  def on_click(self, event):
5416
+ if event.canvas.widgetlock.locked(): # Pan or zoom of the matplotlib toolbar is active
5417
+ return
5418
+
5394
5419
  clicked_axis = event.inaxes
5395
5420
 
5396
5421
  if not clicked_axis or event.button != 1:
@@ -7374,7 +7399,7 @@ class ConvolutionWindow(EQDockWidget):
7374
7399
  def on_width_changed(self, name, value):
7375
7400
  config["convolution_widths"] = {**config["convolution_widths"], name: value}
7376
7401
 
7377
- def on_change(self):
7402
+ def compute_kernel(self, frequency=None):
7378
7403
  function = config["convolution_function"]
7379
7404
 
7380
7405
  if function == "Off":
@@ -7401,6 +7426,13 @@ class ConvolutionWindow(EQDockWidget):
7401
7426
  p.name: config["convolution_widths"].get(p.name, p.default or 1)
7402
7427
  for p in method.kernel_params()
7403
7428
  }
7429
+ if method.frequency_dependent_kernel:
7430
+ if frequency is None:
7431
+ # Only used to fill the stored kernel, the plots call kernel_at
7432
+ axes = getattr(mainwindow.lwpwidget, "lwpaxes", None)
7433
+ axes = [] if axes is None else axes.flatten()
7434
+ frequency = np.mean(axes[0].xrange) if len(axes) else 0.0
7435
+ widths["frequency"] = frequency
7404
7436
  kernel = method(derivative).kernel(kernel_xs, amplitude, **widths)
7405
7437
  else: # Custom Kernel
7406
7438
  tmp = self.custom_kernel_input.toPlainText().strip()
@@ -7409,7 +7441,23 @@ class ConvolutionWindow(EQDockWidget):
7409
7441
  else:
7410
7442
  tmp = tmp.split(",")
7411
7443
  kernel = [float(x) for x in tmp]
7444
+ return kernel
7445
+
7446
+ @classmethod
7447
+ def kernel_at(cls, frequency):
7448
+ """Convolution kernel for a plot centered at `frequency`."""
7449
+ self = cls.instance
7450
+ if config["convolution_kernel"] and config["convolution_function"] not in (
7451
+ "Off",
7452
+ "Custom",
7453
+ ):
7454
+ method = self.get_method()
7455
+ if method is not None and method[0].frequency_dependent_kernel:
7456
+ return np.array(self.compute_kernel(frequency))
7457
+ return np.array(config["convolution_kernel"])
7412
7458
 
7459
+ def on_change(self):
7460
+ kernel = self.compute_kernel()
7413
7461
  config["convolution_kernel"] = list(kernel)
7414
7462
  mainwindow.lwpwidget.set_data()
7415
7463
 
@@ -8270,6 +8318,9 @@ class BlendedLinesWindow(EQDockWidget):
8270
8318
  plot_widget.update_plot_requested.emit()
8271
8319
 
8272
8320
  def add_peak(self, event):
8321
+ if event.canvas.widgetlock.locked(): # Pan or zoom of the matplotlib toolbar is active
8322
+ return
8323
+
8273
8324
  x, y = event.xdata, event.ydata
8274
8325
  is_left_mouse_button = event.button == 1
8275
8326
  if not (x and y and is_left_mouse_button):
@@ -10964,6 +11015,9 @@ class ASAPWidget(LWPWidget):
10964
11015
  mainwindow.statusbar.position_label.setText(text_cursor)
10965
11016
 
10966
11017
  def on_click(self, event):
11018
+ if event.canvas.widgetlock.locked(): # Pan or zoom of the matplotlib toolbar is active
11019
+ return
11020
+
10967
11021
  super().on_click(event)
10968
11022
 
10969
11023
  ax = event.inaxes
@@ -11806,3 +11860,88 @@ if __name__ == "__main__":
11806
11860
  # return(ts, ys)
11807
11861
 
11808
11862
  # FIDLineshape.postprocessing_function = FID_postprocessing_function
11863
+
11864
+
11865
+ ## Add Doppler splitted lines to fitting methods
11866
+
11867
+ # from llwp.fitmethods import Gauss, Lorentz
11868
+
11869
+ # # The splitting is proportional to the frequency. The fitted parameter is the relative
11870
+ # # splitting in ppm: the distance of each component from the center at the frequency f is
11871
+ # # delta * 1e-6 * f (in the unit of x, e.g. MHz). For 0.05 MHz at 12218 MHz this is 4.1 ppm.
11872
+ # START_DELTA = 2.75
11873
+
11874
+
11875
+ # def delta_at(frequency, delta):
11876
+ # """Distance of each component from the center at the given frequency."""
11877
+ # return delta * 1e-6 * frequency
11878
+
11879
+
11880
+ # # Tick "All Same Width" to use the same relative splitting for all lines.
11881
+ # DELTA = Param(
11882
+ # "delta", "Delta (ppm)", shareable=True, default=START_DELTA, in_kernel=True
11883
+ # )
11884
+
11885
+
11886
+ # class ScaledDoppler(ParametricLineshape):
11887
+ # """Doublet with the components at x0 +- delta_at(x0, delta).
11888
+
11889
+ # The relative splitting is fitted, starting at START_DELTA with bounds 0 and
11890
+ # `max_factor` times that. In the convolution window the relative splitting is entered
11891
+ # by hand (or taken from the last fit). The kernel is created for the frequency at the
11892
+ # center of the plot."""
11893
+
11894
+ # abstract = True
11895
+ # can_convolve = True
11896
+ # frequency_dependent_kernel = True # kernel() receives the plot's center frequency
11897
+ # component = None # Lineshape class of the two components
11898
+ # max_factor = 5
11899
+
11900
+ # def __init__(self, derivative=0, **options):
11901
+ # # Start the center of a single fit in the middle of the marked area. The highest
11902
+ # # point is one of the two components and not the center of the doublet.
11903
+ # options.setdefault("xs_weight_factor", 0)
11904
+ # super().__init__(derivative, **options)
11905
+ # self._component = self.component(derivative, **options)
11906
+
11907
+ # def initial_guess(self, guess):
11908
+ # guesses = super().initial_guess(guess)
11909
+ # guesses[-1] = (START_DELTA, 0, self.max_factor * START_DELTA)
11910
+ # return guesses
11911
+
11912
+ # def profile(self, x, *values):
11913
+ # *line, delta = values
11914
+ # x0, amp, *other = line
11915
+ # return self.doublet(x, x0, amp, other, delta_at(x0, delta))
11916
+
11917
+ # def doublet(self, x, x0, amp, other, delta):
11918
+ # return self._component.profile(
11919
+ # x, x0 - delta, amp, *other
11920
+ # ) + self._component.profile(x, x0 + delta, amp, *other)
11921
+
11922
+ # def kernel(self, xs, amplitude, frequency, **widths):
11923
+ # values = []
11924
+ # for param in self.params[:-1]:
11925
+ # if param.role == "center":
11926
+ # values.append(0)
11927
+ # elif param.role == "amplitude":
11928
+ # values.append(amplitude)
11929
+ # else:
11930
+ # values.append(widths.get(param.name, param.default))
11931
+ # delta = delta_at(frequency, widths.get("delta", START_DELTA))
11932
+ # _, amp, *other = values
11933
+ # return self.doublet(xs, 0, amp, other, delta)
11934
+
11935
+
11936
+ # class ScaledDopplerGauss(ScaledDoppler):
11937
+ # name = "Doppler Gauss (scaled)"
11938
+ # derivatives = (0, 1, 2)
11939
+ # component = Gauss
11940
+ # params = Gauss.params + (DELTA,)
11941
+
11942
+
11943
+ # class ScaledDopplerLorentz(ScaledDoppler):
11944
+ # name = "Doppler Lorentz (scaled)"
11945
+ # derivatives = (0, 1, 2)
11946
+ # component = Lorentz
11947
+ # params = Lorentz.params + (DELTA,)
@@ -11,6 +11,8 @@ its menus, depending on which capabilities a class declares:
11
11
  * ``can_fit_single``: fits a single line (main axes, assign all, ...)
12
12
  * ``can_fit_multi``: fits several lines at once (Blended Lines window)
13
13
  * ``can_convolve``: can create a kernel to convolute a stick spectrum
14
+ * ``frequency_dependent_kernel``: the kernel depends on the frequency, ``kernel`` then
15
+ receives the keyword argument ``frequency`` (center of the plot)
14
16
 
15
17
  Hierarchy::
16
18
 
@@ -174,6 +176,7 @@ class FitMethod:
174
176
  can_fit_single = False
175
177
  can_fit_multi = False
176
178
  can_convolve = False
179
+ frequency_dependent_kernel = False
177
180
  min_points = 2 # Minimum number of data points for a single fit
178
181
 
179
182
  def __init_subclass__(cls, **kwargs):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: llwp
3
- Version: 2.1.3
3
+ Version: 2.1.4
4
4
  Summary: LLWP is a fast, efficient and easy solution for exploring and assigning spectra - relying on Loomis-Wood plots.
5
5
  Author-email: Luis Bonah <bonah@ph1.uni-koeln.de>
6
6
  License-Expression: GPL-3.0-only
@@ -2,11 +2,11 @@ LICENSE
2
2
  MANIFEST.in
3
3
  README.md
4
4
  pyproject.toml
5
- llwp/ASAP.svg
6
- llwp/ASAPMac.png
5
+ llwp/IconASAP.svg
6
+ llwp/IconASAPMac.png
7
+ llwp/IconLLWP.svg
8
+ llwp/IconLLWPMac.png
7
9
  llwp/LLWP.py
8
- llwp/LLWP.svg
9
- llwp/LLWPMac.png
10
10
  llwp/__init__.py
11
11
  llwp/__main__.py
12
12
  llwp/fitmethods.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "llwp"
7
- version = "2.1.3"
7
+ version = "2.1.4"
8
8
  authors = [
9
9
  { name="Luis Bonah", email="bonah@ph1.uni-koeln.de" },
10
10
  ]
llwp-2.1.3/MANIFEST.in DELETED
@@ -1,4 +0,0 @@
1
- include llwp/LLWP.svg
2
- include llwp/ASAP.svg
3
- include llwp/LLWPMac.png
4
- include llwp/ASAPMac.png
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes