[MHz]:", 5, "Quadrupolar anisotropy variance: most probable (average) Cq is 2*σ")
+ self.addMultiLabel("Cq0", u"CQ0 [MHz]:", 7)
+ self.addMultiLabel("eta0", u"η0:", 9)
+ self.addMultiLabel("Integral", "Integral:", 11)
+ self.addMultiLabel("Lorentz", "Lorentz 2 [Hz]:", 13, "Lorentzian broadening (transverse relaxation rate) in direct dimension")
+ self.addMultiLabel("Lorentz1", "Lorentz 1 [Hz]:", 15, "Lorentzian broadening (transverse relaxation rate) in indirect dimension")
+# self.addMultiLabel("Gauss2", "Gauss 2 [Hz]:", 17)
+# self.addMultiLabel("Gauss1", "Gauss 1 [Hz]:", 19)
for i in range(self.FITNUM):
+ colorbar = QtWidgets.QWidget()
+ colorbar.setMaximumWidth(5)
+ colorbar.setMinimumWidth(5)
+ colorbar.setStyleSheet(f"QWidget {{ background-color : {self.fit_color_list[i%len(self.fit_color_list)]};}}")
+ self.frame3.addWidget(colorbar, i + 2, 0)
for j in range(len(self.MULTINAMES)):
self.ticks[self.MULTINAMES[j]].append(QtWidgets.QCheckBox(''))
- self.frame3.addWidget(self.ticks[self.MULTINAMES[j]][i], i + 2, 2 * j)
+ self.frame3.addWidget(self.ticks[self.MULTINAMES[j]][i], i + 2, 2 * j + 1)
self.entries[self.MULTINAMES[j]].append(wc.FitQLineEdit(self, self.MULTINAMES[j]))
- self.frame3.addWidget(self.entries[self.MULTINAMES[j]][i], i + 2, 2 * j + 1)
+ self.frame3.addWidget(self.entries[self.MULTINAMES[j]][i], i + 2, 2 * j + 2)
self.reset()
def reset(self):
@@ -5058,20 +5240,34 @@ def checkResults(self, numExp, struc):
"""
locList = self.getRedLocList()
for i in range(numExp):
+ if struc["Gauss"][i][0] == 1:
+ self.fitParamList[locList]["Gauss"][i][0] = abs(self.fitParamList[locList]["Gauss"][i][0])
if struc["Lorentz1"][i][0] == 1:
self.fitParamList[locList]["Lorentz1"][i][0] = abs(self.fitParamList[locList]["Lorentz1"][i][0])
- if struc["Gauss1"][i][0] == 1:
- self.fitParamList[locList]["Gauss1"][i][0] = abs(self.fitParamList[locList]["Gauss1"][i][0])
- if struc["Lorentz2"][i][0] == 1:
- self.fitParamList[locList]["Lorentz2"][i][0] = abs(self.fitParamList[locList]["Lorentz2"][i][0])
- if struc["Gauss2"][i][0] == 1:
- self.fitParamList[locList]["Gauss2"][i][0] = abs(self.fitParamList[locList]["Gauss2"][i][0])
+# if struc["Gauss1"][i][0] == 1:
+# self.fitParamList[locList]["Gauss1"][i][0] = abs(self.fitParamList[locList]["Gauss1"][i][0])
+ if struc["Lorentz"][i][0] == 1:
+ self.fitParamList[locList]["Lorentz"][i][0] = abs(self.fitParamList[locList]["Lorentz"][i][0])
+# if struc["Gauss2"][i][0] == 1:
+# self.fitParamList[locList]["Gauss2"][i][0] = abs(self.fitParamList[locList]["Gauss2"][i][0])
if struc['eta0'][i][0] == 1:
#eta is between 0--1 in a continuous way.
self.fitParamList[locList]['eta0'][i][0] = 1 - abs(abs(self.fitParamList[locList]['eta0'][i][0]) % 2 - 1)
if struc["Cq0"][i][0] == 1:
self.fitParamList[locList]["Cq0"][i][0] = abs(self.fitParamList[locList]["Cq0"][i][0])
+ def changeAxMult(self, oldAxMult):
+ """
+ Changing the units of the parameters which depend on the plot units.
+ """
+ newAxMult = self.parent.getCurrentAxMult()
+ locList = self.getRedLocList()
+ for j in range(len(self.fitParamList[locList]["Position"])):
+ if not isinstance(self.fitParamList[locList]["Position"][j][0], tuple):
+ self.fitParamList[locList]["Position"][j][0] *= newAxMult/oldAxMult
+# for j in range(len(self.fitParamList[locList]["Gauss"])): # same j index as for Position
+ if not isinstance(self.fitParamList[locList]["Gauss"][j][0], tuple):
+ self.fitParamList[locList]["Gauss"][j][0] *= newAxMult/oldAxMult
class NewTabDialog(QtWidgets.QDialog):
diff --git a/src/functions.py b/src/functions.py
index fc083fc..d069c57 100644
--- a/src/functions.py
+++ b/src/functions.py
@@ -1,6 +1,6 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
-# Copyright 2016 - 2020 Bas van Meerten and Wouter Franssen
+# Copyright 2016 - 2021 Bas van Meerten and Wouter Franssen
# This file is part of ssNake.
#
diff --git a/src/hypercomplex.py b/src/hypercomplex.py
index f682618..2409253 100644
--- a/src/hypercomplex.py
+++ b/src/hypercomplex.py
@@ -1,6 +1,6 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
-# Copyright 2016 - 2020 Bas van Meerten and Wouter Franssen
+# Copyright 2016 - 2021 Bas van Meerten and Wouter Franssen
# This file is part of ssNake.
#
diff --git a/src/loadIsotopes.py b/src/loadIsotopes.py
index dc1607c..2c1baa6 100644
--- a/src/loadIsotopes.py
+++ b/src/loadIsotopes.py
@@ -1,7 +1,7 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# -*- coding: utf-8 -*-
-# Copyright 2016 - 2020 Bas van Meerten and Wouter Franssen
+# Copyright 2016 - 2021 Bas van Meerten and Wouter Franssen
# This file is part of ssNake.
#
diff --git a/src/nmrTable.py b/src/nmrTable.py
index 9683db5..8bb813a 100644
--- a/src/nmrTable.py
+++ b/src/nmrTable.py
@@ -1,7 +1,7 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# -*- coding: utf-8 -*-
-# Copyright 2016 - 2020 Bas van Meerten and Wouter Franssen
+# Copyright 2016 - 2021 Bas van Meerten and Wouter Franssen
# This file is part of ssNake.
#
@@ -19,13 +19,8 @@
# along with ssNake. If not, see .
import sys
-try:
- from PyQt5 import QtGui, QtCore, QtWidgets
- QT = 5
-except ImportError:
- from PyQt4 import QtGui, QtCore
- from PyQt4 import QtGui as QtWidgets
- QT = 4
+from PyQt5 import QtGui, QtCore, QtWidgets
+QT = 5
import os
import math
import loadIsotopes
@@ -489,10 +484,7 @@ def __init__(self, parent):
grid.addWidget(self.orderType,0,1)
self.table = QtWidgets.QTableWidget(1,8)
- if QT == 4:
- self.table.horizontalHeader().setResizeMode(QtWidgets.QHeaderView.ResizeToContents)
- elif QT == 5:
- self.table.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
+ self.table.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
self.table.verticalHeader().setVisible(False)
self.table.setHorizontalHeaderLabels(['Nucleus','Name','Spin','Abundance [%]','Q [fm^2]','Frequency ratio [%]',
'Frequency [MHz]','Sensitivity [1H]'])
diff --git a/src/nus.py b/src/nus.py
index 1ba978e..8417434 100644
--- a/src/nus.py
+++ b/src/nus.py
@@ -1,6 +1,6 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
-# Copyright 2016 - 2020 Bas van Meerten and Wouter Franssen
+# Copyright 2016 - 2021 Bas van Meerten and Wouter Franssen
# This file is part of ssNake.
#
diff --git a/src/reimplement.py b/src/reimplement.py
index a246d59..9347a95 100644
--- a/src/reimplement.py
+++ b/src/reimplement.py
@@ -1,6 +1,6 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
-# Copyright 2016 - 2020 Bas van Meerten and Wouter Franssen
+# Copyright 2016 - 2021 Bas van Meerten and Wouter Franssen
# This file is part of ssNake.
#
diff --git a/src/safeEval.py b/src/safeEval.py
index 59d4d70..32d831c 100644
--- a/src/safeEval.py
+++ b/src/safeEval.py
@@ -1,6 +1,6 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
-# Copyright 2016 - 2020 Bas van Meerten and Wouter Franssen
+# Copyright 2016 - 2021 Bas van Meerten and Wouter Franssen
# This file is part of ssNake.
#
diff --git a/src/saveFigure.py b/src/saveFigure.py
index 160be6f..680bb44 100644
--- a/src/saveFigure.py
+++ b/src/saveFigure.py
@@ -1,6 +1,6 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
-# Copyright 2016 - 2020 Bas van Meerten and Wouter Franssen
+# Copyright 2016 - 2021 Bas van Meerten and Wouter Franssen
# This file is part of ssNake.
#
diff --git a/src/simFunctions.py b/src/simFunctions.py
index b8ef688..038a0bf 100644
--- a/src/simFunctions.py
+++ b/src/simFunctions.py
@@ -1,6 +1,6 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
-# Copyright 2016 - 2020 Bas van Meerten and Wouter Franssen
+# Copyright 2016 - 2021 Bas van Meerten and Wouter Franssen
# This file is part of ssNake.
#
@@ -379,7 +379,7 @@ def diffusionFunc(x, freq, sw, axMult, extra, amp, const, coeff, D):
"""
x = x[-1]
gamma, delta, triangle = extra
- return amp * (const + coeff * np.exp(-(abs(gamma) *1e6 * abs(delta) * x)**2 * abs(D) * (abs(triangle) - abs(delta) / 3.0)))
+ return amp * (const + coeff * np.exp(-(abs(gamma) *1e6 * 2 * np.pi * abs(delta) * x)**2 * abs(D) * (abs(triangle) - abs(delta) / 3.0)))
def functionRun(x, freq, sw, axMult, extra, *parameters):
"""
@@ -440,7 +440,7 @@ def externalFitRunScript(x, freq, sw, axMult, extra, bgrnd, mult, *parameters):
The value by which the output curve is multiplied.
*parameters
The parameters used in the fit.
- The last three values are interpreted as [amp, lor, gauss] and are used as the amplitude, the Lorentzian apodization (Hz) and Gaussian apodization (Hz).
+ The last three values are interpreted as [amp, lor, gauss] and are used as the amplitude, the Lorentzian apodization (Hz) and Gaussian apodization (chemical shift distribution) in axMult unit.
Should have be three longer than names.
Returns
@@ -450,6 +450,7 @@ def externalFitRunScript(x, freq, sw, axMult, extra, bgrnd, mult, *parameters):
"""
names, command, script, output, spec = extra
amp, lor, gauss = parameters[-3:]
+ gauss /= axMult
x = x[-1]
if script is None:
return None
@@ -498,7 +499,7 @@ def fib(n):
int
The n+2 Fibonacci number.
"""
- start = np.array([[1, 1], [1, 0]], dtype='int64')
+ start = np.array([[1, 1], [1, 0]], dtype=np.int64)
temp = start[:]
for i in range(n):
temp = np.dot(start, temp)
@@ -527,7 +528,7 @@ def zcw_angles(m, symm=0):
The weights of the different orientations.
"""
samples, fib_1, fib_2 = fib(m)
- js = np.arange(samples, dtype='Float64') / samples
+ js = np.arange(samples, dtype=np.float64) / samples
if symm == 0:
c = (1., 2., 1.)
elif symm == 1:
@@ -569,7 +570,7 @@ def peakSim(x, freq, sw, axMult, extra, bgrnd, mult, pos, amp, lor, gauss):
lor : float
The Lorentzian broadening of the peak.
gauss : float
- The Gaussian broadening of the peak.
+ The Gaussian broadening of the peak (in Hz*axMult), corresponding to CS distribution.
Returns
-------
@@ -578,6 +579,7 @@ def peakSim(x, freq, sw, axMult, extra, bgrnd, mult, pos, amp, lor, gauss):
"""
x = x[-1]
pos /= axMult
+ gauss /= axMult
if pos < np.min(x) or pos > np.max(x):
return np.zeros_like(x)
lor = np.abs(lor)
@@ -621,7 +623,7 @@ def makeSpectrum(x, sw, v, gauss, lor, weight):
inten *= len(inten) / abs(sw)
return inten
-def makeMQMASSpectrum(x, sw, v, gauss, lor, weight):
+def makeMQMASSpectrum(x, sw, v, gauss, lor, weight, slope):
"""
Creates an 2D FID from a list of frequencies with corresponding weights.
Also applies Lorentzian and Gaussian broadening.
@@ -644,6 +646,8 @@ def makeMQMASSpectrum(x, sw, v, gauss, lor, weight):
Lorentzian broadening in Hz for the first and second dimension.
weight : ndarray
The weights corresponding to the frequencies. Should have the same length as the arrays in v.
+ slope : slope (t2/t1) along which the CS and CS distribution is refocused
+ to simulate CS distribution with gaussian g=broadening
Returns
-------
@@ -657,10 +661,22 @@ def makeMQMASSpectrum(x, sw, v, gauss, lor, weight):
t2 = np.fft.fftfreq(length2, sw[-1]/float(length2))
diff2 = (x[-1][1] - x[-1][0])*0.5
t1 = t1[:, np.newaxis]
- final, _, _ = np.histogram2d(v[0], v[1], [length1, length2], range=[[x[-2][0]-diff1, x[-2][-1]+diff1], [x[-1][0]-diff2, x[-1][-1]+diff2]], weights=weight)
+ minD1 = x[-2][0] - diff1
+ maxD1 = x[-2][-1] + diff1
+ minD2 = x[-1][0] - diff2
+ maxD2 = x[-1][-1] + diff2
+ if minD1 > maxD1:
+ minD1, maxD1 = maxD1, minD1
+ v[0] *= -1
+ if minD2 > maxD2:
+ minD2, maxD2 = maxD2, minD2
+ v[1] *= -1
+ final, _, _ = np.histogram2d(v[0], v[1], [length1, length2], range=[[minD1, maxD1], [minD2, maxD2]], weights=weight)
final = np.fft.ifftn(final)
- apod2 = np.exp(-np.pi * np.abs(lor[1] * t2) - ((np.pi * np.abs(gauss[1]) * t2)**2) / (4 * np.log(2)))
- apod1 = np.exp(-np.pi * np.abs(lor[0] * t1) - ((np.pi * np.abs(gauss[0]) * t1)**2) / (4 * np.log(2)))
+ apod2 = np.exp(-np.pi * np.abs(lor[1] * t2) -
+ ((np.pi * np.abs(gauss[1]) * (t2 + t1*slope))**2) / (4 * np.log(2)))
+ apod1 = np.exp(-np.pi * np.abs(lor[0] * t1) -
+ ((np.pi * np.abs(gauss[0]) * t1)**2) / (4 * np.log(2)))
final *= apod1 * apod2 * length1 / abs(sw[-2]) * length2 / abs(sw[-1])
return final
@@ -748,15 +764,15 @@ def csaFunc(x, freq, sw, axMult, extra, bgrnd, mult, spinspeed, t11, t22, t33, a
"""
shiftdef, numssb, angle, D2, weight, MAStype = extra
extra = [False, 0.5, numssb, angle, D2, None, weight, MAStype, shiftdef]
- return quadCSAFunc(x, freq, sw, axMult, extra, bgrnd, mult, spinspeed, t11, t22, t33, 0.0, 0.0, 0.0, 0.0, 0.0, amp, lor, gauss)
+ return quadCSAFunc(x, freq, sw, axMult, extra, bgrnd, mult, spinspeed, t11, t22, t33, 0.0, 0.0, 0.0, 0.0, 0.0, amp, lor, gauss, 0)
-def quadFunc(x, freq, sw, axMult, extra, bgrnd, mult, spinspeed, pos, cq, eta, amp, lor, gauss):
+def quadFunc(x, freq, sw, axMult, extra, bgrnd, mult, spinspeed, pos, cq, eta, amp, lor, gauss, lorST):
"""
Uses the quadCSAFunc function for the specific case where the CSA interaction is zero.
"""
satBool, I, numssb, angle, D2, D4, weight, MAStype = extra
extra = [satBool, I, numssb, angle, D2, D4, weight, MAStype, 0]
- return quadCSAFunc(x, freq, sw, axMult, extra, bgrnd, mult, spinspeed, pos, pos, pos, cq, eta, 0.0, 0.0, 0.0, amp, lor, gauss)
+ return quadCSAFunc(x, freq, sw, axMult, extra, bgrnd, mult, spinspeed, pos, pos, pos, cq, eta, 0.0, 0.0, 0.0, amp, lor, gauss, lorST)
def quadFreqBase(I, m1, m2, cq, eta, freq, angle, D2, D4, numssb, spinspeed):
"""
@@ -831,7 +847,7 @@ def quadFreqBase(I, m1, m2, cq, eta, freq, angle, D2, D4, numssb, spinspeed):
v = np.matmul(dat2, spinD2) + np.matmul(dat4, spinD4)
return v, vConstant
-def quadCSAFunc(x, freq, sw, axMult, extra, bgrnd, mult, spinspeed, t11, t22, t33, cq, eta, alphaCSA, betaCSA, gammaCSA, amp, lor, gauss):
+def quadCSAFunc(x, freq, sw, axMult, extra, bgrnd, mult, spinspeed, t11, t22, t33, cq, eta, alphaCSA, betaCSA, gammaCSA, amp, lor, gauss, lorST):
"""
Calculates an FID of a powder averaged site under influence of CSA and a quadrupole interaction.
This function works for static, finite, and infinite spinnning.
@@ -878,6 +894,8 @@ def quadCSAFunc(x, freq, sw, axMult, extra, bgrnd, mult, spinspeed, t11, t22, t3
The Lorentzian broadening of the peak.
gauss : float
The Gaussian broadening of the peak.
+ lorST : float
+ The Lorentzian broadening of STs of the peak.
Returns
-------
@@ -901,6 +919,7 @@ def quadCSAFunc(x, freq, sw, axMult, extra, bgrnd, mult, spinspeed, t11, t22, t3
t33 = 1 - abs(abs(t33 + 1)%4 - 2)
tensor = np.array(func.shiftConversion([t11, t22, t33], shiftdef)[1], dtype=float)
tensor /= float(axMult)
+ gauss /= axMult
cq *= 1e6
eta = 1 - abs(abs(eta) % 2 - 1) # Force eta to 0--1 in a continuous way: 0.9 == 1.1, 0 == 2
spinspeed *= 1e3
@@ -926,7 +945,11 @@ def quadCSAFunc(x, freq, sw, axMult, extra, bgrnd, mult, spinspeed, t11, t22, t3
tot = weight
if spinspeed not in (0.0, np.inf):
v, tot = carouselAveraging(spinspeed, v, weight, vConstant)
- spectrum += eff * makeSpectrum(x, sw, v, gauss, lor, tot)
+ if m == -0.5:
+ lb = lor
+ else:
+ lb = lorST
+ spectrum += eff * makeSpectrum(x, sw, v, gauss, lb, tot)
return mult * amp * spectrum
def quadCzjzekFunc(x, freq, sw, axMult, extra, bgrnd, mult, pos, sigma, cq0, eta0, amp, lor, gauss):
@@ -967,7 +990,7 @@ def quadCzjzekFunc(x, freq, sw, axMult, extra, bgrnd, mult, pos, sigma, cq0, eta
lor : float
The Lorentzian broadening of the peak.
gauss : float
- The Gaussian broadening of the peak.
+ The Gaussian broadening of the peak in the units defined by axMult.
Returns
-------
@@ -981,6 +1004,7 @@ def quadCzjzekFunc(x, freq, sw, axMult, extra, bgrnd, mult, pos, sigma, cq0, eta
cq0 = 0
eta0 = 0
pos /= axMult
+ gauss /= axMult
sigma = abs(sigma) * 1e6
cq0 *= 1e6
czjzek = Czjzek.czjzekIntensities(sigma, d, cq, eta, cq0, eta0)
@@ -991,7 +1015,7 @@ def quadCzjzekFunc(x, freq, sw, axMult, extra, bgrnd, mult, pos, sigma, cq0, eta
apod = np.exp(2j * np.pi * pos * t - np.pi * np.abs(lor) * np.abs(t) - ((np.pi * np.abs(gauss) * t)**2) / (4 * np.log(2)))
return mult * amp * fid * apod
-def mqmasFunc(x, freq, sw, axMult, extra, bgrnd, mult, spinspeed, pos, cq, eta, amp, lor2, gauss2, lor1, gauss1):
+def mqmasFunc(x, freq, sw, axMult, extra, bgrnd, mult, spinspeed, pos, sigmaCS, cq, eta, amp, lor2, lor1, gauss2=0, gauss1=0):
"""
Calculates a 2-D FID of an MQMAS spectrum.
This function works for static, finite, and infinite spinnning.
@@ -1029,6 +1053,8 @@ def mqmasFunc(x, freq, sw, axMult, extra, bgrnd, mult, spinspeed, pos, cq, eta,
The spinning speed in kHz.
pos : float
The isotropic chemical shift value defined in terms of axMult.
+ sigmaCS : float
+ The Gaussian broadening along the chemical shift axis in units defined by axMult.
cq : float
The quadrupole coupling constant Cq given in MHz.
eta : float
@@ -1038,11 +1064,11 @@ def mqmasFunc(x, freq, sw, axMult, extra, bgrnd, mult, spinspeed, pos, cq, eta,
lor2 : float
The Lorentzian broadening in the direct dimension.
gauss2 : float
- The Gaussian broadening in the direct dimension.
+ The Gaussian broadening in the direct dimension defined (not used).
lor1 : float
The Lorentzian broadening in the indirect dimension.
gauss1 : float
- The Gaussian broadening in the indirect dimension.
+ The Gaussian broadening in the indirect dimension (not used).
Returns
-------
@@ -1057,6 +1083,7 @@ def mqmasFunc(x, freq, sw, axMult, extra, bgrnd, mult, spinspeed, pos, cq, eta,
elif MAStype == 2:
spinspeed = np.inf
pos /= axMult
+ sigmaCS /= axMult
spinspeed *= 1e3
cq *= 1e6
eta = 1 - abs(abs(eta)%2 - 1)
@@ -1070,13 +1097,14 @@ def mqmasFunc(x, freq, sw, axMult, extra, bgrnd, mult, spinspeed, pos, cq, eta,
v2 += pos
v1 += mq*pos - v2 * shear
v1 *= scale
- return mult * amp * makeMQMASSpectrum(x, sw, [np.real(v1.flatten()), np.real(v2.flatten())], [gauss1, gauss2], [lor1, lor2], np.real(tot).flatten())
+ slope = (mq-shear)*scale # t1/t2 slope along which to apply CS gaussian distribution
+ return mult * amp * makeMQMASSpectrum(x, sw, [np.real(v1.flatten()), np.real(v2.flatten())], [0, sigmaCS], [lor1, lor2], np.real(tot).flatten(), slope)
-def mqmasCzjzekFunc(x, freq, sw, axMult, extra, bgrnd, mult, pos, sigma, sigmaCS, cq0, eta0, amp, lor2, gauss2, lor1, gauss1):
+def mqmasCzjzekFunc(x, freq, sw, axMult, extra, bgrnd, mult, pos, sigmaCS, sigma, cq0, eta0, amp, lor2, lor1, gauss2=0, gauss1=0):
"""
Calculates a 2-D FID of an MQMAS spectrum with an (extended) Czjzek distribution using a library of 1-D spectra.
- Parameters
+ , shear_factorParameters
----------
x : list of ndarray
A list of axes values for the simulation.
@@ -1108,7 +1136,7 @@ def mqmasCzjzekFunc(x, freq, sw, axMult, extra, bgrnd, mult, pos, sigma, sigmaCS
sigma : float
The width of the Czjzek distribution in MHz.
sigmaCS : float
- The Gaussian broadening along the chemical shift axis in Hz.
+ The Gaussian broadening along the chemical shift axis in units defined by axMult.
cq0 : float
The extended Czjzek quadrupole coupling constant Cq0 given in MHz (only used when method=True).
eta0 : float
@@ -1118,11 +1146,11 @@ def mqmasCzjzekFunc(x, freq, sw, axMult, extra, bgrnd, mult, pos, sigma, sigmaCS
lor2 : float
The Lorentzian broadening in the direct dimension.
gauss2 : float
- The Gaussian broadening in the direct dimension.
+ The Gaussian broadening in the direct dimension (not used).
lor1 : float
The Lorentzian broadening in the indirect dimension.
gauss1 : float
- The Gaussian broadening in the indirect dimension.
+ The Gaussian broadening in the indirect dimension (not used).
Returns
-------
@@ -1138,6 +1166,7 @@ def mqmasCzjzekFunc(x, freq, sw, axMult, extra, bgrnd, mult, pos, sigma, sigmaCS
cq0 = 0
eta0 = 0
pos /= axMult
+ sigmaCS /= axMult
sigma *= 1e6
czjzek = Czjzek.czjzekIntensities(sigma, d, cq, eta, cq0, eta0)
length2 = len(x[-1])
@@ -1147,8 +1176,6 @@ def mqmasCzjzekFunc(x, freq, sw, axMult, extra, bgrnd, mult, pos, sigma, sigmaCS
t1 = np.fft.fftfreq(length1, sw[-2]/float(length1))
t1 = t1[:, np.newaxis]
t2 = np.fft.fftfreq(length2, sw[-1]/float(length2))
- apod2 = np.exp(-np.pi * np.abs(lor2 * t2) - ((np.pi * np.abs(gauss2) * t2)**2) / (4 * np.log(2)))
- apod1 = np.exp(-np.pi * np.abs(lor1 * t1) - ((np.pi * np.abs(gauss1) * t1)**2) / (4 * np.log(2)))
V40 = 1.0 / 140 * (18 + eta**2)
T40_m = mq * (18 * I * (I + 1) - 34 * (mq/2.0)**2 - 5)
T40_1 = (18 * I * (I + 1) - 34 * (0.5)**2 - 5)
@@ -1166,6 +1193,10 @@ def mqmasCzjzekFunc(x, freq, sw, axMult, extra, bgrnd, mult, pos, sigma, sigmaCS
posIndirect = pos * (mq - shearFactor) * scale
offsetMat = np.exp(2j * np.pi * (posIndirect * t1 + (pos - x[-1][length2//2])*t2))
shiftGauss = np.exp(-((np.pi * np.abs(sigmaCS) * (t2 + t1*(mq-shearFactor)*scale))**2) / (4 * np.log(2)))
+# apod2 = np.exp(-np.pi * np.abs(lor2 * t2) - ((np.pi * np.abs(gauss2) * t2)**2) / (4 * np.log(2)))
+# apod1 = np.exp(-np.pi * np.abs(lor1 * t1) - ((np.pi * np.abs(gauss1) * t1)**2) / (4 * np.log(2)))
+ apod2 = np.exp(-np.pi * np.abs(lor2 * t2) )
+ apod1 = np.exp(-np.pi * np.abs(lor1 * t1) )
fid *= offsetMat * apod1 * apod2 * shiftGauss
shearMat = np.exp((shearFactor-shear) * 2j * np.pi * t1 * x[-1])
fid = np.fft.fft(fid, axis=1) * shearMat
@@ -1207,5 +1238,5 @@ def genLib(length, minCq, maxCq, minEta, maxEta, numCq, numEta, extra, freq, sw,
x = np.fft.fftshift(np.fft.fftfreq(length, 1/float(sw)))
lib = np.zeros((len(cq), length), dtype=complex)
for i, (cqi, etai) in enumerate(zip(cq, eta)):
- lib[i] = quadFunc([x], [freq], [sw], 1.0, extra, 0.0, 1.0, spinspeed, 0.0, cqi, etai, 1.0, 0.0, 0.0)
+ lib[i] = quadFunc([x], [freq], [sw], 1.0, extra, 0.0, 1.0, spinspeed, 0.0, cqi, etai, 1.0, 0.0, 0.0, 0.0)
return lib, cq*1e6, eta
diff --git a/src/specIO.py b/src/specIO.py
index d1b4638..37af643 100644
--- a/src/specIO.py
+++ b/src/specIO.py
@@ -1,6 +1,6 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
-# Copyright 2016 - 2020 Bas van Meerten and Wouter Franssen
+# Copyright 2016 - 2021 Bas van Meerten and Wouter Franssen
# This file is part of ssNake.
#
@@ -409,9 +409,9 @@ def loadVarianFile(filePath):
fid = fid[0][:]
if spec: # flip if spectrum
fid = np.flipud(fid)
- masterData = sc.Spectrum(fid, (filePath, None), [freq], [sw], [bool(int(spec))], ref=[reffreq])
+ masterData = sc.Spectrum(fid, (filePath, None), [freq], [sw], spec=[bool(int(spec))], ref=[reffreq])
else:
- masterData = sc.Spectrum(fid, (filePath, None), [freq1, freq], [sw1, sw], [bool(int(spec))] * 2, ref=[reffreq1, reffreq])
+ masterData = sc.Spectrum(fid, (filePath, None), [freq1, freq], [sw1, sw], spec=[bool(int(spec))]*2, ref=[reffreq1, reffreq])
masterData.addHistory("Varian data loaded from " + filePath)
try:
masterData.metaData['# Scans'] = str(pars['nt'])
@@ -509,7 +509,7 @@ def loadPipe(filePath):
for i in range(NDIM):
if spec[-1 - i] == 1:
data[k] = np.flip(data[k], NDIM -1 - i)
- masterData = sc.Spectrum(hc.HComplexData(data, hyper), (filePath, None), freq[4 - NDIM:4], sw[4 - NDIM:4], spec[4 - NDIM:4], ref=ref[4 - NDIM:4])
+ masterData = sc.Spectrum(hc.HComplexData(data, hyper), (filePath, None), freq[4-NDIM:4], sw[4-NDIM:4], spec[4-NDIM:4], ref=ref[4-NDIM:4])
masterData.addHistory("NMRpipe data loaded from " + filePath)
return masterData
@@ -721,7 +721,7 @@ def loadJEOLDelta(filePath):
for i in range(NDIM):
if spec[-1 - i] == 1:
data[k] = np.flip(data[k], NDIM -1 - i)
- masterData = sc.Spectrum(hc.HComplexData(np.array(data), hyper), (filePath, None), freq, sw, spec, ref=ref, dFilter=dFilter)
+ masterData = sc.Spectrum(hc.HComplexData(np.array(data), hyper), (filePath, None), freq, sw, spec=spec, ref=ref, dFilter=dFilter)
masterData.addHistory("JEOL Delta data loaded from " + filePath)
return masterData
@@ -804,10 +804,10 @@ def loadJSONFile(filePath):
(filePath, None),
list(struct['freq']),
list(struct['sw']),
- list(struct['spec']),
- list(np.array(struct['wholeEcho'], dtype=bool)),
- list(ref),
- xaxA,
+ spec=list(struct['spec']),
+ wholeEcho=list(np.array(struct['wholeEcho'], dtype=bool)),
+ ref=list(ref),
+ xaxArray=xaxA,
history=history,
metaData=metaData,
dFilter=dFilter)
@@ -923,10 +923,10 @@ def loadMatlabFile(filePath):
(filePath, None),
list(mat['freq'][0, 0][0]),
list(mat['sw'][0, 0][0]),
- list(mat['spec'][0, 0][0]),
- list(np.array(mat['wholeEcho'][0, 0][0]) > 0),
- list(ref),
- xaxA,
+ spec=list(mat['spec'][0, 0][0]),
+ wholeEcho=list(np.array(mat['wholeEcho'][0, 0][0]) > 0),
+ ref=list(ref),
+ xaxArray=xaxA,
history=history,
metaData=metaData,
dFilter=dFilter)
@@ -988,10 +988,10 @@ def loadMatlabFile(filePath):
(filePath, None),
list(np.array(mat['freq'])[:, 0]),
list(np.array(mat['sw'])[:, 0]),
- list(np.array(mat['spec'])[:, 0]),
- list(np.array(mat['wholeEcho'])[:, 0] > 0),
- list(ref),
- xaxA,
+ spec=list(np.array(mat['spec'])[:, 0]),
+ wholeEcho=list(np.array(mat['wholeEcho'])[:, 0] > 0),
+ ref=list(ref),
+ xaxArray=xaxA,
history=history,
metaData=metaData,
dFilter=dFilter)
@@ -1040,7 +1040,7 @@ def loadMatNMRFile(filePath):
if mat['DefaultAxisRefkHzTD2'][0][0][0][0]:
ref[1] = freq[1] + 1e3*mat['DefaultAxisRefkHzTD2'][0][0][0][0]
history = list(mat['History'][0][0])
- masterData = sc.Spectrum(data, (filePath, None), freq, sw, spec, ref=ref, history=history)
+ masterData = sc.Spectrum(data, (filePath, None), freq, sw, spec=spec, ref=ref, history=history)
masterData.addHistory("MatNMR data loaded from " + filePath)
return masterData
@@ -1150,7 +1150,9 @@ def loadBrukerTopspin(filePath):
else:
Dir = filePath
pars = []
- for File in ['acqus', 'acqu2s', 'acqu3s']:
+ # makes list of par file names
+ parFileN = ['acqus'] + [f'acqu{int(x)}s' for x in range(2,9)]
+ for File in parFileN:
if os.path.exists(Dir + os.path.sep + File):
pars.append(brukerTopspinGetPars(Dir + os.path.sep + File))
SIZE = [x['TD'] for x in pars]
@@ -1177,7 +1179,7 @@ def loadBrukerTopspin(filePath):
newSize[0] = int(directSize / 2)
ComplexData = ComplexData.reshape(*newSize[-1::-1])
ComplexData = ComplexData[..., 0:int(SIZE[0]/2)] #Cut off placeholder data
- masterData = sc.Spectrum(ComplexData, (filePath, None), FREQ[-1::-1], SW[-1::-1], [False] * dim, ref = REF[-1::-1], dFilter=dFilter)
+ masterData = sc.Spectrum(ComplexData, (filePath, None), FREQ[-1::-1], SW[-1::-1], spec=[False]*dim, ref=REF[-1::-1], dFilter=dFilter)
# TODO: Inserting metadata should be made more generic
try:
masterData.metaData['# Scans'] = str(pars[0]['NS'])
@@ -1199,6 +1201,13 @@ def loadBrukerTopspin(filePath):
masterData.metaData['Recycle Delay [s]'] = str(pars[0]['D'][1])
except Exception:
pass
+ try:
+ import time
+ masterData.metaData['Time Completed'] = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(int(pars[0]['DATE'])))
+ except Exception:
+ pass
+
+
masterData.addHistory("Bruker TopSpin data loaded from " + filePath)
return masterData
@@ -1250,7 +1259,7 @@ def loadBrukerImagingTime(filePath):
newSize[0] = int(directSize / 2)
ComplexData = ComplexData.reshape(newSize[-1::-1])
ComplexData = ComplexData[..., 0:int(SIZE[0]/2)] #Cut off placeholder data
- masterData = sc.Spectrum(ComplexData, (filePath, None), FREQ, SW, [False] * dim)
+ masterData = sc.Spectrum(ComplexData, (filePath, None), FREQ, SW, spec=[False]*dim)
return masterData
def loadBrukerWinNMR(filePath):
@@ -1310,7 +1319,7 @@ def loadBrukerWinNMR(filePath):
raw = np.fromfile(f, np.float32, SIZE)
raw = raw.newbyteorder(ByteOrder) #Load with right byte order
ComplexData = np.array(raw[0:len(raw):2]) + 1j * np.array(raw[1:len(raw):2])
- masterData = sc.Spectrum(ComplexData, (filePath, None), [FREQ], [SW], [spec], ref=[REF])
+ masterData = sc.Spectrum(ComplexData, (filePath, None), [FREQ], [SW], spec=[spec], ref=[REF])
if not spec:
try:
masterData.metaData['# Scans'] = str(pars['NS'])
@@ -1347,12 +1356,22 @@ def loadBrukerSpectrum(filePath):
if os.path.exists(Dir + os.path.sep + File):
pars.append(brukerTopspinGetPars(Dir + os.path.sep + File))
SIZE = [x['SI'] for x in pars]
- XDIM = [x['XDIM'] for x in pars]
+ try:
+ XDIM = [x['XDIM'] for x in pars]
+ except KeyError:
+ XDIM = SIZE # If not specified the data is assumed to be 1D
SW = [x['SW_p'] for x in pars]
FREQ = [x['SF'] * 1e6 for x in pars]
OFFSET = [x['OFFSET'] for x in pars]
- DtypeP = [np.dtype(np.int32), np.dtype(np.float32), np.dtype(np.float64)][pars[0]['DTYPP']] #The byte orders that is used
- DtypeP = DtypeP.newbyteorder(['L', 'B'][pars[0]['BYTORDP']])
+ SCALE = 1
+ if 'NC_proc' in pars[0]: # Set intensity scaling parameter
+ SCALE = 2**pars[0]['NC_proc']
+ try:
+ DtypeP = [np.dtype(np.int32), np.dtype(np.float32), np.dtype(np.float64)][pars[0]['DTYPP']] #The byte orders that is used
+ DtypeP = DtypeP.newbyteorder(['L', 'B'][pars[0]['BYTORDP']])
+ except KeyError:
+ DtypeP = np.dtype(np.int32) # When these parameters are not available the defaults are used
+ DtypeP = DtypeP.newbyteorder('L')
# The byte orders that is used as stored in BYTORDP proc parameter:
# '< or L' =little endian, '>' or 'B' = big endian
REF = []
@@ -1391,7 +1410,8 @@ def loadBrukerSpectrum(filePath):
DATA[index] = np.reshape(DATA[index], [int(SIZE[2]/XDIM[2]), int(SIZE[1]/XDIM[1]), int(SIZE[0]/XDIM[0]), XDIM[2], XDIM[1], XDIM[0]])
DATA[index] = np.concatenate(np.concatenate(np.concatenate(DATA[index], 2), 2), 2)
spec = [True]
- masterData = sc.Spectrum(hc.HComplexData(DATA, hyper), (filePath, None), FREQ[-1::-1], SW[-1::-1], spec * dim, ref=REF[-1::-1])
+ DATA = [x * SCALE for x in DATA]
+ masterData = sc.Spectrum(hc.HComplexData(DATA, hyper), (filePath, None), FREQ[-1::-1], SW[-1::-1], spec=spec*dim, ref=REF[-1::-1])
masterData.addHistory("Bruker spectrum data loaded from " + filePath)
#Try to load main acqus and get some additional pars
try:
@@ -1441,7 +1461,7 @@ def loadBrukerImaging(filePath):
# DATA = np.flipud(raw)
DATA = raw.reshape(SIZE)
- masterData = sc.Spectrum(DATA, (filePath, None), FREQ, SW, SPEC)
+ masterData = sc.Spectrum(DATA, (filePath, None), FREQ, SW, spec=SPEC)
return masterData
def chemGetPars(folder):
@@ -1548,9 +1568,9 @@ def loadChemFile(filePath):
spec = [False]
if sizeTD1 == 1:
data = data[0][:]
- masterData = sc.Spectrum(data, (filePath, None), [freq * 1e6], [sw], spec)
+ masterData = sc.Spectrum(data, (filePath, None), [freq*1e6], [sw], specspec)
else:
- masterData = sc.Spectrum(data, (filePath, None), [freq * 1e6] * 2, [sw1, sw], spec * 2)
+ masterData = sc.Spectrum(data, (filePath, None), [freq*1e6]*2, [sw1, sw], spec=spec*2)
masterData.addHistory("Chemagnetics data loaded from " + filePath)
try:
if isinstance(pars['na'], list):
@@ -1618,7 +1638,7 @@ def loadMagritek(filePath):
ComplexData = Data[0:Data.shape[0]:2] - 1j * Data[1:Data.shape[0]:2]
ComplexData = ComplexData.reshape((sizeTD1, sizeTD2))
ComplexData[:, 0] *= 2
- masterData = sc.Spectrum(ComplexData, (filePath, None), [freq] * 2, [sw1, sw], [False] * 2, ref=[ref1, ref])
+ masterData = sc.Spectrum(ComplexData, (filePath, None), [freq]*2, [sw1, sw], spec=[False]*2, ref=[ref1, ref])
elif Files1D:
File = 'data.1d'
with open(Dir + os.path.sep + File, 'rb') as f:
@@ -1626,7 +1646,7 @@ def loadMagritek(filePath):
Data = raw[-2 * sizeTD2::]
ComplexData = Data[0:Data.shape[0]:2] - 1j * Data[1:Data.shape[0]:2]
ComplexData[0] *= 2
- masterData = sc.Spectrum(ComplexData, (filePath, None), [freq], [sw], [False], ref=[ref])
+ masterData = sc.Spectrum(ComplexData, (filePath, None), [freq], [sw], spec=[False], ref=[ref])
try:
masterData.metaData['# Scans'] = H['nrScans']
masterData.metaData['Acquisition Time [s]'] = str(int(H['nrPnts']) * float(H['dwellTime']) * 1e-6)
@@ -1754,9 +1774,9 @@ def LAST(f, x): return ((x) & (~0 << (8 - f)))
elif 'SPE' in TYPE:
spec = [True]
if NI == 1:
- masterData = sc.Spectrum(data, (filePath, None), [0], [SW], spec)
+ masterData = sc.Spectrum(data, (filePath, None), [0], [SW], spec=spec)
else:
- masterData = sc.Spectrum(data, (filePath, None), [0, 0], [SW1, SW], spec * 2)
+ masterData = sc.Spectrum(data, (filePath, None), [0, 0], [SW1, SW], spec=spec*2)
masterData.addHistory("SIMPSON data loaded from " + filePath)
return masterData
@@ -1926,7 +1946,7 @@ def loadJCAMP(filePath):
imagDat = imagDat * factor[2]
fullData = realDat - 1j * imagDat
sw = 1.0 / ((last - first) / (nPoints - 1))
- masterData = sc.Spectrum(fullData, (filePath, None), [freq], [sw], [False])
+ masterData = sc.Spectrum(fullData, (filePath, None), [freq], [sw], spec=[False])
elif 'NMRSPECTRUM' in dataType:
spectDat = np.array([])
for line in data[spectDataPos[0]:spectDataPos[1] + 1]:
@@ -1938,7 +1958,7 @@ def loadJCAMP(filePath):
elif Xunit == 'PPM':
sw = abs(FirstX - LastX) * freq
sw = sw + sw / NPoints
- masterData = sc.Spectrum(spectDat, (filePath, None), [freq], [sw], [True], ref=[None])
+ masterData = sc.Spectrum(spectDat, (filePath, None), [freq], [sw], spec=[True], ref=[None])
return masterData
def saveASCIIFile(filePath, spectrum, axMult=1):
@@ -2035,7 +2055,7 @@ def loadAscii(filePath, asciiInfo=None):
data = matrix
if xaxis is not None:
xaxis = [xaxis]
- masterData = sc.Spectrum(data, (filePath, asciiInfo), [freq], [sw], [dataSpec], ref=[None], xaxArray=xaxis)
+ masterData = sc.Spectrum(data, (filePath, asciiInfo), [freq], [sw], spec=[dataSpec], ref=[None], xaxArray=xaxis)
elif dataDimension == 2:
if dataOrder == 'XRI':
data = np.transpose(matrix[:, 1::2] + 1j * matrix[:, 2::2])
@@ -2049,7 +2069,7 @@ def loadAscii(filePath, asciiInfo=None):
data = np.transpose(matrix)
if xaxis is not None:
xaxis = [None, xaxis]
- masterData = sc.Spectrum(data, (filePath, asciiInfo), [freq, freq], [1, sw], [False, dataSpec], ref=[None, None], xaxArray=xaxis)
+ masterData = sc.Spectrum(data, (filePath, asciiInfo), [freq, freq], [1, sw], spec=[False, dataSpec], ref=[None, None], xaxArray=xaxis)
else:
return
masterData.addHistory("ASCII data loaded from " + filePath)
@@ -2088,7 +2108,7 @@ def loadMinispec(filePath):
if line:
temp = np.fromstring(line, sep='\t')
totaldata = np.append(totaldata, temp[0] + 1j * temp[1])
- masterData = sc.Spectrum(totaldata, (filePath, None), [0], [sw], [False])
+ masterData = sc.Spectrum(totaldata, (filePath, None), [0], [sw], spec=[False])
masterData.addHistory("Minispec data loaded from " + filePath)
return masterData
@@ -2131,9 +2151,9 @@ def loadBrukerEPR(filePath):
data = np.fromfile(f, np.float32, numOfPoints)
if dataIs2D:
data = np.reshape(data, (numYPoints, numXPoints))
- masterData = sc.Spectrum(data, (filePath, None), [centerField, centerField], [sweepWidth, sweepWidth], [False, True], ref=[None,0])
+ masterData = sc.Spectrum(data, (filePath, None), [centerField, centerField], [sweepWidth, sweepWidth], spec=[False, True], ref=[None,0])
else:
- masterData = sc.Spectrum(data, (filePath, None), [centerField], [sweepWidth], [True], ref=[0])
+ masterData = sc.Spectrum(data, (filePath, None), [centerField], [sweepWidth], spec=[True], ref=[0])
masterData.addHistory("Bruker EPR data loaded from " + filePath)
return masterData
@@ -2293,7 +2313,7 @@ def loadMestreC(filePath):
if dim == 2:
for i, _ in enumerate(data):
data[i] = data[i].reshape(*points[-1::-1])
- masterData = sc.Spectrum(hc.HComplexData(np.array(data), hyper), (filePath, None), freq, sw, [spec] * dim, ref=ref, dFilter=dFilter[0])
+ masterData = sc.Spectrum(hc.HComplexData(np.array(data), hyper), (filePath, None), freq, sw, spec=[spec]*dim, ref=ref, dFilter=dFilter[0])
return masterData
def loadDMfit(filePath):
@@ -2330,6 +2350,6 @@ def loadDMfit(filePath):
center = xaxis[len(xaxis)//2]
if center != 0.0:
ref = freq - center
- masterData = sc.Spectrum(data, (filePath, None), [freq], [sw], [True], ref=[ref], xaxArray=[xaxis])
+ masterData = sc.Spectrum(data, (filePath, None), [freq], [sw], spec=[True], ref=[ref], xaxArray=[xaxis])
masterData.addHistory("DMfit data loaded from " + filePath)
return masterData
diff --git a/src/spectrum.py b/src/spectrum.py
index 8b2249c..57ba585 100644
--- a/src/spectrum.py
+++ b/src/spectrum.py
@@ -1,6 +1,6 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
-# Copyright 2016 - 2020 Bas van Meerten and Wouter Franssen
+# Copyright 2016 - 2021 Bas van Meerten and Wouter Franssen
# This file is part of ssNake.
#
@@ -43,7 +43,7 @@ class Spectrum(object):
The functions for processing are methods of this object.
"""
- def __init__(self, data, filePath, freq, sw, spec=None, wholeEcho=None, ref=None, xaxArray=None, history=None, metaData=None, name='', dFilter=None):
+ def __init__(self, data, filePath, freq, sw, spec=None, wholeEcho=None, ref=None, xaxArray=None, customXax=None, history=None, metaData=None, name='', dFilter=None):
"""
Initializes the Spectrum object.
@@ -75,6 +75,9 @@ def __init__(self, data, filePath, freq, sw, spec=None, wholeEcho=None, ref=None
The x-axis values per dimension.
The list should have the same number of entries as the number of dimensions of data.
By default the x-axes are generated based on the sw values.
+ customXax : list of booleans, optional
+ Which of the arrays are custom values and have not been automatically generated based on frequency, reference, and spectral width.
+ By default all of them are False
history : list of strings, optional
The processing history of the data.
By default the history is set to an empty list.
@@ -118,6 +121,10 @@ def __init__(self, data, filePath, freq, sw, spec=None, wholeEcho=None, ref=None
self.resetXax()
else:
self.xaxArray = xaxArray
+ if customXax is not None and len(customXax) == len(self.xaxArray):
+ self.customXax = customXax
+ else:
+ self.customXax = [False] * len(self.xaxArray)
if history is None:
self.history = [] # list of strings describing all performed operations
else:
@@ -299,8 +306,10 @@ def resetXax(self, axis=None):
if axis is not None:
axis = self.checkAxis(axis)
val = [axis]
+ self.customXax[axis] = False
else:
val = range(self.ndim())
+ self.customXax = [False] * self.ndim()
for i in val:
if self.spec[i] == 0:
self.xaxArray[i] = np.arange(self.shape()[i]) / (self.sw[i])
@@ -309,7 +318,7 @@ def resetXax(self, axis=None):
if self.ref[i] is not None:
self.xaxArray[i] += self.freq[i] - self.ref[i]
- def setXax(self, xax, axis=-1):
+ def setXax(self, xax, axis=-1, custom=True):
"""
Sets the x-axis of a given dimension.
@@ -321,6 +330,9 @@ def setXax(self, xax, axis=-1):
axis : int, optional
The dimension for which to set the x-axis.
By default the last axis is used.
+ custom : bool, optional
+ Whether the new x-axis is a custom axis.
+ True by default
Raises
------
@@ -331,11 +343,13 @@ def setXax(self, xax, axis=-1):
if len(xax) != self.shape()[axis]:
raise SpectrumException("Length of new x-axis does not match length of the data")
oldXax = self.xaxArray[axis]
+ oldCustom = self.customXax[axis]
self.xaxArray[axis] = xax
+ self.customXax[axis] = custom
self.addHistory("X-axis of dimension " + str(axis + 1) + " was set to " + str(xax).replace('\n', ''))
self.redoList = []
if not self.noUndo:
- self.undoList.append(lambda self: self.setXax(oldXax, axis))
+ self.undoList.append(lambda self: self.setXax(oldXax, axis, oldCustom))
def insert(self, data, pos, axis=-1):
"""
@@ -356,7 +370,7 @@ def insert(self, data, pos, axis=-1):
if self.noUndo:
returnValue = None
else:
- if np.all(self.data.hyper == data.hyper): # If both sets have same hyper: easy undo can be used
+ if np.all(self.data.hyper == data.hyper) and not self.customXax[axis]: # If both sets have same hyper and it does not have a custom x-axis: easy undo can be used
returnValue = lambda self: self.delete(range(pos, pos + data.shape()[axis]), axis)
else: # Otherwise: do a deep copy of the class
copyData = copy.deepcopy(self)
@@ -395,6 +409,7 @@ def delete(self, pos, axis=-1):
raise SpectrumException('Cannot delete all data')
self.data = tmpData
self.xaxArray[axis] = np.delete(self.xaxArray[axis], pos)
+ self.customXax[axis] = True
if isinstance(pos, np.ndarray):
if pos.ndim == 0:
pos = int(pos)
@@ -650,7 +665,7 @@ def normalize(self, mult, scale=1.0, type=0, axis=-1, select=slice(None)):
"""
axis = self.checkAxis(axis)
try:
- self.data *= mult * scale
+ self.data[select] *= mult * scale
except ValueError as error:
raise SpectrumException('Normalize: ' + str(error))
if type == 0:
@@ -703,22 +718,24 @@ def concatenate(self, axis=-1):
By default the last dimension is used.
"""
axis = self.checkAxis(axis)
- splitVal = self.shape()[axis]
+ splitVal = self.shape()[0]
copyData = None
- if self.data.isComplex(axis):
+ if self.data.isComplex(axis) or self.customXax[0] or self.customXax[axis]:
if not self.noUndo:
copyData = copy.deepcopy(self)
- self.data = self.data.real(axis)
+ if self.data.isComplex(axis):
+ self.data = self.data.real(axis)
invAxis = self.ndim() - axis
self.data = self.data.concatenate(axis)
self.data.removeDim(invAxis)
- self.freq = np.delete(self.freq, axis)
- self.sw = np.delete(self.sw, axis)
- self.spec = np.delete(self.spec, axis)
- self.wholeEcho = np.delete(self.wholeEcho, axis)
- self.ref = np.delete(self.ref, axis)
- del self.xaxArray[axis]
- self.resetXax()
+ self.freq = np.delete(self.freq, 0)
+ self.sw = np.delete(self.sw, 0)
+ self.spec = np.delete(self.spec, 0)
+ self.wholeEcho = np.delete(self.wholeEcho, 0)
+ self.ref = np.delete(self.ref, 0)
+ del self.xaxArray[0]
+ del self.customXax[0]
+ self.resetXax(axis)
self.addHistory("Concatenated dimension " + str(axis + 1))
self.redoList = []
if not self.noUndo:
@@ -741,6 +758,10 @@ def split(self, sections, axis=-1):
By default the last dimension is used.
"""
axis = self.checkAxis(axis)
+ copyData = None
+ if self.customXax[axis]:
+ if not self.noUndo:
+ copyData = copy.deepcopy(self)
self.data = self.data.split(sections, axis)
self.data.insertDim(0)
self.freq = np.insert(self.freq, 0, self.freq[axis])
@@ -749,12 +770,16 @@ def split(self, sections, axis=-1):
self.wholeEcho = np.insert(self.wholeEcho, 0, self.wholeEcho[axis])
self.ref = np.insert(self.ref, 0, self.ref[axis])
self.xaxArray.insert(0, [])
+ self.customXax.insert(0, False)
self.resetXax(0)
self.resetXax(axis + 1)
self.addHistory("Split dimension " + str(axis + 1) + " into " + str(sections) + " sections")
self.redoList = []
if not self.noUndo:
- self.undoList.append(lambda self: self.concatenate(axis))
+ if copyData is not None:
+ self.undoList.append(lambda self: self.restoreData(copyData, lambda self: self.split(sections, axis)))
+ else:
+ self.undoList.append(lambda self: self.concatenate(axis))
def real(self, axis=-1):
"""
@@ -1020,6 +1045,7 @@ def matrixManip(self, pos1=None, pos2=None, axis=-1, which=0):
self.spec = np.delete(self.spec, axis)
self.wholeEcho = np.delete(self.wholeEcho, axis)
del self.xaxArray[axis]
+ del self.customXax[axis]
self.data.removeDim(axis)
else:
self.data = tmpdata[0]
@@ -1691,6 +1717,9 @@ def setFreq(self, freq=None, sw=None, axis=-1):
By default the last dimension is used.
"""
axis = self.checkAxis(axis)
+ copyData = None
+ if self.customXax[axis] and not self.noUndo:
+ copyData = copy.deepcopy(self)
oldFreq = self.freq[axis]
oldSw = self.sw[axis]
if freq is None:
@@ -1703,7 +1732,10 @@ def setFreq(self, freq=None, sw=None, axis=-1):
self.addHistory("Frequency set to " + str(freq * 1e-6) + " MHz and sw set to " + str(sw * 1e-3) + " kHz for dimension " + str(axis + 1))
self.redoList = []
if not self.noUndo:
- self.undoList.append(lambda self: self.setFreq(oldFreq, oldSw, axis))
+ if copyData is not None:
+ self.undoList.append(lambda self: self.restoreData(copyData, lambda self: self.setFreq(freq, sw, axis)))
+ else:
+ self.undoList.append(lambda self: self.setFreq(oldFreq, oldSw, axis))
def scaleSw(self, scale, axis=-1):
"""
@@ -1718,13 +1750,19 @@ def scaleSw(self, scale, axis=-1):
By default the last dimension is used.
"""
axis = self.checkAxis(axis)
+ copyData = None
+ if self.customXax[axis] and not self.noUndo:
+ copyData = copy.deepcopy(self)
oldSw = self.sw[axis]
self.sw[axis] = float(scale) * oldSw
self.resetXax(axis)
self.addHistory("Sw scaled by factor " + str(scale) + " for dimension " + str(axis + 1))
self.redoList = []
if not self.noUndo:
- self.undoList.append(lambda self: self.scaleSw(1.0 / scale, axis))
+ if copyData is not None:
+ self.undoList.append(lambda self: self.restoreData(copyData, lambda self: self.scaleSw(scale, axis)))
+ else:
+ self.undoList.append(lambda self: self.scaleSw(1.0 / scale, axis))
def setRef(self, ref=None, axis=-1):
"""
@@ -1741,6 +1779,9 @@ def setRef(self, ref=None, axis=-1):
By default the last dimension is used.
"""
axis = self.checkAxis(axis)
+ copyData = None
+ if self.customXax[axis] and not self.noUndo:
+ copyData = copy.deepcopy(self)
oldRef = self.ref[axis]
if ref is None:
self.ref[axis] = None
@@ -1751,7 +1792,10 @@ def setRef(self, ref=None, axis=-1):
self.resetXax(axis)
self.redoList = []
if not self.noUndo:
- self.undoList.append(lambda self: self.setRef(oldRef, axis))
+ if copyData is not None:
+ self.undoList.append(lambda self: self.restoreData(copyData, lambda self: self.setRef(ref, axis)))
+ else:
+ self.undoList.append(lambda self: self.setRef(oldRef, axis))
def regrid(self, limits, numPoints, axis=-1):
"""
@@ -1900,6 +1944,9 @@ def setSpec(self, val, axis=-1):
By default the last dimension is used.
"""
axis = self.checkAxis(axis)
+ copyData = None
+ if self.customXax[axis] and not self.noUndo:
+ copyData = copy.deepcopy(self)
oldVal = self.spec[axis]
self.spec[axis] = val
self.resetXax(axis)
@@ -1909,7 +1956,10 @@ def setSpec(self, val, axis=-1):
self.addHistory("Dimension " + str(axis + 1) + " set to spectrum")
self.redoList = []
if not self.noUndo:
- self.undoList.append(lambda self: self.setSpec(oldVal, axis))
+ if copyData is not None:
+ self.undoList.append(lambda self: self.restoreData(copyData, lambda self: self.setSpec(val, axis)))
+ else:
+ self.undoList.append(lambda self: self.setSpec(oldVal, axis))
def swapEcho(self, idx, axis=-1):
"""
@@ -2415,11 +2465,12 @@ def getSlice(self, axes, locList, stack=None):
self.filePath,
[self.freq[axis] for axis in axes],
[self.sw[axis] for axis in axes],
- [self.spec[axis] for axis in axes],
- [self.wholeEcho[axis] for axis in axes],
- [self.ref[axis] for axis in axes],
- [self.xaxArray[axis][stack[i]] for i, axis in enumerate(axes)],
- self.history,
+ spec=[self.spec[axis] for axis in axes],
+ wholeEcho=[self.wholeEcho[axis] for axis in axes],
+ ref=[self.ref[axis] for axis in axes],
+ xaxArray=[self.xaxArray[axis][stack[i]] for i, axis in enumerate(axes)],
+ customXax=[self.customXax[axis] for axis in axes],
+ history=self.history,
name=self.name))
sliceSpec.noUndo = True
return sliceSpec
@@ -2445,6 +2496,7 @@ def restoreData(self, copyData, returnValue):
self.spec = copyData.spec
self.wholeEcho = copyData.wholeEcho
self.xaxArray = copyData.xaxArray
+ self.customXax = copyData.customXax
self.ref = copyData.ref
self.addHistory("Data was restored to a previous state ")
self.redoList = []
diff --git a/src/spectrumFrame.py b/src/spectrumFrame.py
index b927e50..7f7ac89 100644
--- a/src/spectrumFrame.py
+++ b/src/spectrumFrame.py
@@ -1,7 +1,7 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# -*- coding: utf-8 -*-
-# Copyright 2016 - 2020 Bas van Meerten and Wouter Franssen
+# Copyright 2016 - 2021 Bas van Meerten and Wouter Franssen
# This file is part of ssNake.
#
diff --git a/src/ssNake.py b/src/ssNake.py
index caa88d3..3a9e1d5 100644
--- a/src/ssNake.py
+++ b/src/ssNake.py
@@ -1,7 +1,7 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# -*- coding: utf-8 -*-
-# Copyright 2016 - 2020 Bas van Meerten and Wouter Franssen
+# Copyright 2016 - 2021 Bas van Meerten and Wouter Franssen
# This file is part of ssNake.
#
@@ -21,29 +21,16 @@
EXE = False
import sys
-if sys.version_info.major == 2:
- import sip
- sip.setapi('QString', 2)
- print('DEPRECATION WARNING: From version 1.4 onwards, python2 is no longer supported. Consider upgrading to python3.')
import os
import importlib
-try:
- from PyQt5 import QtGui, QtCore, QtWidgets
- QT = 5
-except ImportError:
- from PyQt4 import QtGui, QtCore
- from PyQt4 import QtGui as QtWidgets
- QT = 4
- print('DEPRECATION WARNING: From version 1.4 onwards, PyQt4 is no longer supported. Consider upgrading to PyQt5.')
+from PyQt5 import QtGui, QtCore, QtWidgets
+QT = 5
+
QtCore.pyqtRemoveInputHook()
import matplotlib
# First import matplotlib and Qt
-if QT == 4:
- matplotlib.use('Qt4Agg')
- from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
-else:
- matplotlib.use('Qt5Agg')
- from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
+matplotlib.use('Qt5Agg')
+from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import multiprocessing
# Create splash window
@@ -109,7 +96,7 @@ def import_lib(name, nameAs, className, splashStep):
np.set_printoptions(threshold=sys.maxsize)
QtCore.QLocale.setDefault(QtCore.QLocale('en_US'))
-VERSION = 'v1.3'
+VERSION = 'v1.4b'
# Required library version
NPVERSION = '1.11.0'
MPLVERSION = '1.5.0'
@@ -230,15 +217,13 @@ def handleCopy(self):
canvas = self.mainWindow.tabs.currentWidget().canvas
else:
canvas = self.mainWindow.canvas
- if QT == 5:
- screen = self.root.primaryScreen()
- pixmap = screen.grabWindow(canvas.winId())
- else:
- pixmap = QtGui.QPixmap.grabWidget(canvas)
+ screen = self.root.primaryScreen()
+ pixmap = screen.grabWindow(canvas.winId())
QtWidgets.QApplication.clipboard().setPixmap(pixmap)
def resetDefaults(self):
self.defaultUnits = 1
+ self.defaultPrecis = 4
self.defaultShowTitle = True
self.defaultPPM = False
self.defaultWidth = 1
@@ -344,6 +329,7 @@ def loadDefaults(self):
self.defaultDiagonalMult = settings.value("contour/diagonalmult", self.defaultDiagonalMult, float)
except TypeError:
self.dispMsg("Incorrect value in the config file for the diagonal multiplier")
+ self.defaultPrecis = settings.value("precision", self.defaultPrecis, int)
self.defaultMaximized = settings.value("maximized", self.defaultMaximized, bool)
try:
self.defaultWidth = settings.value("width", self.defaultWidth, int)
@@ -385,6 +371,7 @@ def saveDefaults(self):
settings.setValue("plot/ygrid", self.defaultGrids[1])
settings.setValue("plot/zeroscroll", self.defaultZeroScroll)
settings.setValue("plot/zoomstep", self.defaultZoomStep)
+ settings.setValue("precision", self.defaultPrecis)
settings.setValue("maximized", self.defaultMaximized)
settings.setValue("width", self.defaultWidth)
settings.setValue("height", self.defaultHeight)
@@ -975,9 +962,9 @@ def menuCheck(self):
if type(self.mainWindow) is Main1DWindow:
self.menuEnable(True)
for act in self.specOnlyList:
- act.setEnabled(self.mainWindow.current.spec() == 1) # Only on for spec
+ act.setEnabled(int(self.mainWindow.current.spec() == 1)) # Only on for spec
for act in self.fidOnlyList:
- act.setEnabled(self.mainWindow.current.spec() == 0) # Only on for FID
+ act.setEnabled(int(self.mainWindow.current.spec() == 0)) # Only on for FID
#Limit functions based on plot type
if type(self.mainWindow.current) == views.CurrentMulti or type(self.mainWindow.current) == views.CurrentStacked or type(self.mainWindow.current) == views.CurrentArrayed:
for act in self.Only1DPlot:
@@ -1551,10 +1538,10 @@ def dataFromFit(self, data, filePath, freq, sw, spec, wholeEcho, ref, xaxArray,
filePath,
freq,
sw,
- spec,
- wholeEcho,
- ref,
- xaxArray,
+ spec=spec,
+ wholeEcho=wholeEcho,
+ ref=ref,
+ xaxArray=xaxArray,
history=['Data obtained from fit'],
name=name)
masterData.resetXax(axes)
@@ -3141,14 +3128,14 @@ def frameEnable(self, enable=True):
def setLabels(self, position):
if len(position) > 3:
self.ypos.setText(str(position[3]))
- self.deltaypoint.setText('%#.4g' % np.abs(self.oldy - position[4]))
- self.ypoint.setText('%#.4g' % position[4])
+ self.deltaypoint.setText(('%#.'+str(self.father.father.defaultPrecis)+'g') % np.abs(self.oldy - position[4]))
+ self.ypoint.setText(('%#.'+str(self.father.father.defaultPrecis)+'g') % position[4])
self.oldy = position[4]
- self.deltaxpoint.setText('%#.4g' % np.abs(self.oldx - position[1]))
- self.deltaamppoint.setText('%#.4g' % np.abs(self.oldamp - position[2]))
+ self.deltaxpoint.setText(('%#.'+str(self.father.father.defaultPrecis)+'g') % np.abs(self.oldx - position[1]))
+ self.deltaamppoint.setText(('%#.'+str(self.father.father.defaultPrecis)+'g') % np.abs(self.oldamp - position[2]))
self.xpos.setText(str(position[0]))
- self.xpoint.setText('%#.4g' % position[1])
- self.amppoint.setText('%#.4g' % position[2])
+ self.xpoint.setText(('%#.'+str(self.father.father.defaultPrecis)+'g') % position[1])
+ self.amppoint.setText(('%#.'+str(self.father.father.defaultPrecis)+'g') % position[2])
self.oldx = position[1]
self.oldamp = position[2]
@@ -3832,7 +3819,7 @@ def checkEval(self, key):
def setLorGauss(self,value, type, *args):
#type: 'lor' or 'gauss'
if self.available:
- self.entries[type][0].setText('%.4g' % (float(value) * self.maximum / self.RESOLUTION))
+ self.entries[type][0].setText(('%.'+str(self.father.father.defaultPrecis)+'g') % (float(value) * self.maximum / self.RESOLUTION))
if not self.ticks[type].isChecked():
self.ticks[type].setChecked(1)
self.apodPreview()
@@ -3860,9 +3847,9 @@ def stepLB(self, incr, type):
self.ticks[type].setChecked(1)
lor, gauss, cos2, cos2Ph, hamming, shift, shifting, shiftingAxis = self.checkInput()
if type == 'lor':
- self.entries[type][0].setText('%.4g' % (lor + step))
+ self.entries[type][0].setText(('%.'+str(self.father.father.defaultPrecis)+'g') % (lor + step))
elif type == 'gauss':
- self.entries[type][0].setText('%.4g' % (gauss + step))
+ self.entries[type][0].setText(('%.'+str(self.father.father.defaultPrecis)+'g') % (gauss + step))
self.apodPreview()
def checkInput(self):
@@ -6974,6 +6961,10 @@ def __init__(self, parent):
self.showTitleCheck = QtWidgets.QCheckBox("Show title in plot")
self.showTitleCheck.setChecked(self.father.defaultShowTitle)
grid2.addWidget(self.showTitleCheck, 15, 0, 1, 2)
+ grid2.addWidget(QtWidgets.QLabel("Significant digits:"), 16, 0)
+ self.precisSpinBox = wc.SsnakeSpinBox()
+ self.precisSpinBox.setValue(self.father.defaultPrecis)
+ grid2.addWidget(self.precisSpinBox, 16, 1)
# grid3 definitions
grid3.addWidget(QtWidgets.QLabel("Colourmap:"), 0, 0)
self.cmEntry = QtWidgets.QComboBox(self)
@@ -7065,6 +7056,7 @@ def applyAndClose(self, *args):
self.father.defaultGrids[1] = self.ygridCheck.isChecked()
self.father.defaultZeroScroll = self.zeroScrollCheck.isChecked()
self.father.defaultShowTitle = self.showTitleCheck.isChecked()
+ self.father.defaultPrecis = self.precisSpinBox.value()
self.father.defaultZoomStep = self.ZoomStepSpinBox.value()
self.father.defaultColorMap = self.cmEntry.currentText()
self.father.defaultContourConst = self.constColorCheck.isChecked()
@@ -7181,7 +7173,7 @@ def __init__(self, parent):
pythonVersion = pythonVersion[:pythonVersion.index(' ')]
from scipy import __version__ as scipyVersion
self.text.setText('ssNake ' + VERSION + '
' +
- 'Copyright (©) 2016–2020 Bas van Meerten & Wouter Franssen
' + 'Email: ssnake@science.ru.nl
' +
+ 'Copyright (©) 2016–2021 Bas van Meerten & Wouter Franssen
' + 'Email: ssnake@science.ru.nl
' +
'Publication: https://doi.org/10.1016/j.jmr.2019.02.006
' +
'Library versions:
Python ' + pythonVersion + '
numpy ' + np.__version__ +
'
SciPy ' + scipyVersion +
@@ -7350,25 +7342,25 @@ def shiftCalc(self, Type):
raise SsnakeException("Shift Conversion: Invalid input in Hertzfeld-Berger Convention")
Results = func.shiftConversion(Values, Type) # Do the actual conversion
# Standard convention
- self.D11.setText('%#.4g' % Results[0][0])
- self.D22.setText('%#.4g' % Results[0][1])
- self.D33.setText('%#.4g' % Results[0][2])
+ self.D11.setText(('%#.'+str(self.father.defaultPrecis)+'g') % Results[0][0])
+ self.D22.setText(('%#.'+str(self.father.defaultPrecis)+'g') % Results[0][1])
+ self.D33.setText(('%#.'+str(self.father.defaultPrecis)+'g') % Results[0][2])
# Convert to haeberlen convention and xxyyzz
- self.dxx.setText('%#.4g' % Results[1][0])
- self.dyy.setText('%#.4g' % Results[1][1])
- self.dzz.setText('%#.4g' % Results[1][2])
+ self.dxx.setText(('%#.'+str(self.father.defaultPrecis)+'g') % Results[1][0])
+ self.dyy.setText(('%#.'+str(self.father.defaultPrecis)+'g') % Results[1][1])
+ self.dzz.setText(('%#.'+str(self.father.defaultPrecis)+'g') % Results[1][2])
# Haeberlen def
- self.diso.setText('%#.4g' % Results[2][0])
- self.daniso.setText('%#.4g' % Results[2][1])
+ self.diso.setText(('%#.'+str(self.father.defaultPrecis)+'g') % Results[2][0])
+ self.daniso.setText(('%#.'+str(self.father.defaultPrecis)+'g') % Results[2][1])
try: # If a number
- self.eta.setText('%#.4g' % Results[2][2])
+ self.eta.setText(('%#.'+str(self.father.defaultPrecis)+'g') % Results[2][2])
except Exception:
self.eta.setText('ND')
# Convert to Herzfeld-Berger Convention
- self.hbdiso.setText('%#.4g' % Results[3][0])
- self.hbdaniso.setText('%#.4g' % Results[3][1])
+ self.hbdiso.setText(('%#.'+str(self.father.defaultPrecis)+'g') % Results[3][0])
+ self.hbdaniso.setText(('%#.'+str(self.father.defaultPrecis)+'g') % Results[3][1])
try:
- self.hbskew.setText('%#.4g' % Results[3][2])
+ self.hbskew.setText(('%#.'+str(self.father.defaultPrecis)+'g') % Results[3][2])
except Exception:
self.hbskew.setText('ND')
@@ -7460,7 +7452,9 @@ def __init__(self, parent):
self.grid.addWidget(self.WqGroup, 7, 0, 1, 2)
self.fieldGroup = QtWidgets.QGroupBox('Field Gradients:')
self.fieldFrame = QtWidgets.QGridLayout()
- Vxxlabel = wc.QLabel('Vxx [V/m2]:')
+ # Vxx and Vyy labels interchanged to follow the Quad+CSa fitting deifnitions
+ # WF: 2021-01
+ Vxxlabel = wc.QLabel('Vyy [V/m2]:')
self.fieldFrame.addWidget(Vxxlabel, 9, 1)
VGO = QtWidgets.QPushButton("Go")
self.fieldFrame.addWidget(VGO, 10, 0)
@@ -7468,7 +7462,7 @@ def __init__(self, parent):
self.Vxx = wc.QLineEdit("ND")
self.Vxx.setMinimumWidth(100)
self.fieldFrame.addWidget(self.Vxx, 10, 1)
- Vyylabel = wc.QLabel('Vyy [V/m2]:')
+ Vyylabel = wc.QLabel('Vxx [V/m2]:')
self.fieldFrame.addWidget(Vyylabel, 9, 2)
self.Vyy = wc.QLineEdit("ND")
self.Vyy.setMinimumWidth(100)
@@ -7534,18 +7528,18 @@ def quadCalc(self, Type):
if Result[0][1] is None:
self.Eta.setText('ND')
else:
- self.Eta.setText('%#.4g' % Result[0][1])
- self.Cq.setText('%#.4g' % Result[0][0])
- self.Wq.setText('%#.4g' % Result[1][0])
+ self.Eta.setText(('%#.'+str(self.father.defaultPrecis)+'g') % Result[0][1])
+ self.Cq.setText(('%#.'+str(self.father.defaultPrecis)+'g') % Result[0][0])
+ self.Wq.setText(('%#.'+str(self.father.defaultPrecis)+'g') % Result[1][0])
if Result[2][0] is None:
self.Moment.setText('ND')
self.Vxx.setText('ND')
self.Vyy.setText('ND')
self.Vzz.setText('ND')
else:
- self.Vxx.setText('%#.4g' % Result[2][0])
- self.Vyy.setText('%#.4g' % Result[2][1])
- self.Vzz.setText('%#.4g' % Result[2][2])
+ self.Vxx.setText(('%#.'+str(self.father.defaultPrecis)+'g') % Result[2][0])
+ self.Vyy.setText(('%#.'+str(self.father.defaultPrecis)+'g') % Result[2][1])
+ self.Vzz.setText(('%#.'+str(self.father.defaultPrecis)+'g') % Result[2][2])
def valueReset(self): # Resets all the boxes to 0
self.Cq.setText('0')
@@ -8077,10 +8071,7 @@ def checkVersions():
libs = [['numpy', np.__version__, NPVERSION],
['matplotlib', matplotlib.__version__, MPLVERSION],
['scipy', scipyVersion, SPVERSION]]
- if sys.version_info.major == 3:
- libs.append(['python', str(sys.version_info.major) + '.' + str(sys.version_info.minor), PY3VERSION])
- elif sys.version_info.major == 2:
- libs.append(['python', str(sys.version_info.major) + '.' + str(sys.version_info.minor), PY2VERSION])
+ libs.append(['python', str(sys.version_info.major) + '.' + str(sys.version_info.minor), PY3VERSION])
messages = []
error = False
for elem in libs:
diff --git a/src/updateWindow.py b/src/updateWindow.py
index addaa16..aef8db3 100644
--- a/src/updateWindow.py
+++ b/src/updateWindow.py
@@ -1,6 +1,6 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
-# Copyright 2016 - 2020 Bas van Meerten and Wouter Franssen
+# Copyright 2016 - 2021 Bas van Meerten and Wouter Franssen
# This file is part of ssNake.
#
diff --git a/src/views.py b/src/views.py
index 0798343..007bb3d 100644
--- a/src/views.py
+++ b/src/views.py
@@ -1,6 +1,6 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
-# Copyright 2016 - 2020 Bas van Meerten and Wouter Franssen
+# Copyright 2016 - 2021 Bas van Meerten and Wouter Franssen
# This file is part of ssNake.
#
@@ -409,11 +409,13 @@ def fixAxes(self, axes):
list:
The new axis list
"""
- if len(axes) != self.NDIM_PLOT:
+ if len(axes) < self.NDIM_PLOT:
fullAxes = np.arange(self.data.ndim())
fullAxes = np.delete(fullAxes, axes)
diff = self.NDIM_PLOT - len(axes)
return np.append(fullAxes[-diff:], axes[-self.NDIM_PLOT:])
+ elif len(axes) > self.NDIM_PLOT:
+ return axes[-self.NDIM_PLOT:]
return axes
def rename(self, name):
@@ -3246,8 +3248,11 @@ def altScroll(self, event):
def plotReset_x_ax(self):
if not self.line_xProjData:
return
- minz = min([min(i) for i in self.line_xProjData])
- maxz = max([max(i) for i in self.line_xProjData])
+ minz = min([np.nanmin(i) for i in self.line_xProjData])
+ maxz = max([np.nanmax(i) for i in self.line_xProjData])
+ if np.isnan(minz): # If there are no acceptable values minz and maxz will be NaN
+ minz = -0.01
+ maxz = 0.01
if minz == maxz: # Prevents setting the limits equal
minz -= 0.01
maxz += 0.01
@@ -3260,8 +3265,11 @@ def plotReset_x_ax(self):
def plotReset_y_ax(self):
if not self.line_yProjData:
return
- minz = min([min(i) for i in self.line_yProjData])
- maxz = max([max(i) for i in self.line_yProjData])
+ minz = min([np.nanmin(i) for i in self.line_yProjData])
+ maxz = max([np.nanmax(i) for i in self.line_yProjData])
+ if np.isnan(minz): # If there are no acceptable values minz and maxz will be NaN
+ minz = -0.01
+ maxz = 0.01
if minz == maxz: # Prevents setting the limits equal
minz -= 0.01
maxz += 0.01
@@ -3571,16 +3579,17 @@ def plotContour(self, line_xdata, line_ydata, line_zdata, color=None, updateOnly
PlotNegative = True
vmax = max(np.abs(self.viewSettings["minLevels"] * self.differ), np.abs(self.viewSettings["maxLevels"] * self.differ))
vmin = -vmax
- if color is not None:
- if PlotPositive:
- self.ax.contour(X[YposMax[:, None], XposMax], Y[YposMax[:, None], XposMax], line_zdata[YposMax[:, None], XposMax], colors=[color[0]], levels=contourLevels, vmax=vmax, vmin=vmin, linewidths=self.viewSettings["linewidth"], linestyles='solid')
- if PlotNegative:
- self.ax.contour(X[YposMin[:, None], XposMin], Y[YposMin[:, None], XposMin], line_zdata[YposMin[:, None], XposMin], colors=[color[1]], levels=-contourLevels[::-1], vmax=vmax, vmin=vmin, linewidths=self.viewSettings["linewidth"], linestyles='solid')
- else:
- if PlotPositive:
- self.ax.contour(X[YposMax[:, None], XposMax], Y[YposMax[:, None], XposMax], line_zdata[YposMax[:, None], XposMax], cmap=get_cmap(self.viewSettings["colorMap"]), levels=contourLevels, vmax=vmax, vmin=vmin, linewidths=self.viewSettings["linewidth"], linestyles='solid')
- if PlotNegative:
- self.ax.contour(X[YposMin[:, None], XposMin], Y[YposMin[:, None], XposMin], line_zdata[YposMin[:, None], XposMin], cmap=get_cmap(self.viewSettings["colorMap"]), levels=-contourLevels[::-1], vmax=vmax, vmin=vmin, linewidths=self.viewSettings["linewidth"], linestyles='solid')
+ if len(line_xdata) > 1 and len(line_ydata) > 1: # Do not plot if too few points
+ if color is not None:
+ if PlotPositive:
+ self.ax.contour(X[YposMax[:, None], XposMax], Y[YposMax[:, None], XposMax], line_zdata[YposMax[:, None], XposMax], colors=[color[0]], levels=contourLevels, vmax=vmax, vmin=vmin, linewidths=self.viewSettings["linewidth"], linestyles='solid')
+ if PlotNegative:
+ self.ax.contour(X[YposMin[:, None], XposMin], Y[YposMin[:, None], XposMin], line_zdata[YposMin[:, None], XposMin], colors=[color[1]], levels=-contourLevels[::-1], vmax=vmax, vmin=vmin, linewidths=self.viewSettings["linewidth"], linestyles='solid')
+ else:
+ if PlotPositive:
+ self.ax.contour(X[YposMax[:, None], XposMax], Y[YposMax[:, None], XposMax], line_zdata[YposMax[:, None], XposMax], cmap=get_cmap(self.viewSettings["colorMap"]), levels=contourLevels, vmax=vmax, vmin=vmin, linewidths=self.viewSettings["linewidth"], linestyles='solid')
+ if PlotNegative:
+ self.ax.contour(X[YposMin[:, None], XposMin], Y[YposMin[:, None], XposMin], line_zdata[YposMin[:, None], XposMin], cmap=get_cmap(self.viewSettings["colorMap"]), levels=-contourLevels[::-1], vmax=vmax, vmin=vmin, linewidths=self.viewSettings["linewidth"], linestyles='solid')
self.setTicks()
if updateOnly:
self.canvas.draw()
@@ -3802,7 +3811,11 @@ def plotContour(self, line_xdata, line_ydata, line_zdata, color=None, updateOnly
if updateOnly: # Set some extra stuff if only the contour plot needs updating
del self.ax.collections[:] # Clear all plot collections
- self.ax.imshow(np.flipud(line_zdata), extent=[line_xdata[0],line_xdata[-1],line_ydata[0],line_ydata[-1]],aspect='auto',cmap=get_cmap(self.viewSettings["pColorMap"]))
+ vmax = np.max(np.abs(line_zdata))
+ vmin = -vmax
+
+ self.ax.imshow(np.flipud(line_zdata), extent=[line_xdata[0],line_xdata[-1],line_ydata[0],line_ydata[-1]],
+ aspect='auto',cmap=get_cmap(self.viewSettings["pColorMap"]),vmax=vmax,vmin=vmin,interpolation='hanning')
self.setTicks()
if updateOnly:
self.canvas.draw()
diff --git a/src/widgetClasses.py b/src/widgetClasses.py
index b6777c3..2bc36ca 100644
--- a/src/widgetClasses.py
+++ b/src/widgetClasses.py
@@ -1,6 +1,6 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
-# Copyright 2016 - 2020 Bas van Meerten and Wouter Franssen
+# Copyright 2016 - 2021 Bas van Meerten and Wouter Franssen
# This file is part of ssNake.
#
@@ -20,7 +20,7 @@
import os
import sys
from safeEval import safeEval
-from ssNake import QtGui, QtCore, QtWidgets, QT
+from ssNake import QtGui, QtCore, QtWidgets
class SsnakeTabs(QtWidgets.QTabWidget):
"""
@@ -68,10 +68,7 @@ def __init__(self, parent):
self.customContextMenuRequested.connect(self.openMenu)
self.setModel(self.dirmodel)
self.setRootIndex(self.dirmodel.index(''))
- if QT == 4:
- self.header().setResizeMode(0, QtGui.QHeaderView.ResizeToContents)
- elif QT == 5:
- self.header().setSectionResizeMode(0, QtWidgets.QHeaderView.ResizeToContents)
+ self.header().setSectionResizeMode(0, QtWidgets.QHeaderView.ResizeToContents)
self.header().setStretchLastSection(False)
self.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
#self.setToolTip(index.model()->data(index,Qt:isplayRole).toString());
@@ -212,10 +209,7 @@ def wheelEvent(self, event):
event : QMouseEvent
The mouse event.
"""
- if QT == 4:
- delta = event.delta()
- else:
- delta = event.angleDelta().y()
+ delta = event.angleDelta().y()
step = self.singleStep() * 3
if QtWidgets.qApp.keyboardModifiers() & QtCore.Qt.ControlModifier and QtWidgets.qApp.keyboardModifiers() & QtCore.Qt.ShiftModifier:
step *= 1000
@@ -564,10 +558,7 @@ def wheelEvent(self, event):
event : QWheelEvent
The event on the spinbox.
"""
- if QT == 4:
- delta = event.delta()
- else:
- delta = event.angleDelta().y() + event.angleDelta().x()
+ delta = event.angleDelta().y() + event.angleDelta().x()
step = 1
if delta > 0:
self.stepBy(step)
@@ -615,10 +606,7 @@ def wheelEvent(self, event):
event : QWheelEvent
The event on the spinbox.
"""
- if QT == 4:
- delta = event.delta()
- else:
- delta = event.angleDelta().y() + event.angleDelta().x()
+ delta = event.angleDelta().y() + event.angleDelta().x()
step = 1
if delta > 0:
self.stepBy(step)
@@ -662,10 +650,7 @@ def wheelEvent(self, event):
event : QWheelEvent
The event on the spinbox.
"""
- if QT == 4:
- delta = event.delta()
- else:
- delta = event.angleDelta().y() + event.angleDelta().x()
+ delta = event.angleDelta().y() + event.angleDelta().x()
step = 1
if delta > 0:
self.stepBy(step)