Skip to content
Commits on Source (7)
1.1.6
- fix: improve support for Confocor FCS file format
(see discussion in #37)
- ref: make pathlib.Path a standard in readfiles
- code cleanup
- drop support for Python<3.6
1.1.5
- docs: fix build with recent version of latex (#191)
1.1.4
......
......@@ -17,7 +17,7 @@ at the `issues page <https://github.com/FCS-analysis/PyCorrFit/wiki/Creating-a-n
.. |PyCorrFit| image:: https://raw.github.com/FCS-analysis/PyCorrFit/master/doc/Images/PyCorrFit_logo_dark.png
.. |PyPI Version| image:: http://img.shields.io/pypi/v/PyCorrFit.svg
.. |PyPI Version| image:: https://img.shields.io/pypi/v/PyCorrFit.svg
:target: https://pypi.python.org/pypi/pycorrfit
.. |Build Status Win| image:: https://img.shields.io/appveyor/ci/paulmueller/PyCorrFit/master.svg?label=win
:target: https://ci.appveyor.com/project/paulmueller/pycorrfit
......
pycorrfit (1.1.6+dfsg-1) UNRELEASED; urgency=medium
* Update d/watch, normalize upstream version from d/changelog
* New upstream version 1.1.6+dfsg
* Bump Policy to 4.3.0
* Add X-Python3-Version: >= 3.6 to d/control
* Use debhelper-compat, drop d/compat
-- Alexandre Mestiashvili <mestia@debian.org> Mon, 06 May 2019 10:44:58 +0200
pycorrfit (1.1.5+dfsg-1) unstable; urgency=medium
* New upstream version 1.1.5+dfsg
......
......@@ -5,7 +5,7 @@ Uploaders: Alexandre Mestiashvili <mestia@debian.org>,
Section: python
Priority: optional
Build-Depends: cython3,
debhelper (>= 11),
debhelper-compat (= 12),
dh-python,
faketime,
imagemagick,
......@@ -27,10 +27,11 @@ Build-Depends: cython3,
texlive-latex-extra,
texlive-latex-recommended,
texlive-science
Standards-Version: 4.2.1
Standards-Version: 4.3.0
Vcs-Browser: https://salsa.debian.org/med-team/pycorrfit
Vcs-Git: https://salsa.debian.org/med-team/pycorrfit.git
Homepage: http://fcs-analysis.github.io/PyCorrFit/
X-Python3-Version: >= 3.6
Package: pycorrfit
Architecture: any
......@@ -44,7 +45,9 @@ Depends: python3-matplotlib,
${misc:Depends},
${python3:Depends},
${shlibs:Depends}
Recommends: dvipng, texlive-latex-base, texlive-science
Recommends: dvipng,
texlive-latex-base,
texlive-science
Description: tool for fitting correlation curves on a logarithmic plot
PyCorrFit is a general-purpose FCS evaluation software that,
amongst other formats, supports the established Zeiss ConfoCor3 ~.fcs
......
version=4
opts=uversionmangle=s/(\d)[_\.\-\+]?((RC|rc|pre|dev|beta|alpha)\d*)$/$1~$2/,\
filenamemangle=s/.+\/v?(\d\S*)\.tar\.gz/pycorrfit-$1\.tar\.gz/,dversionmangle=s/\+dfsg(\.\d+)?$//,repacksuffix=+dfsg,repack \
filenamemangle=s/.+\/v?(\d\S*)\.tar\.gz/pycorrfit-$1\.tar\.gz/,dversionmangle=s/\+dfsg.*$//,repacksuffix=+dfsg,repack \
https://github.com/paulmueller/PyCorrFit/tags .*/v?(\d\S*)\.tar\.gz
.. _index:
PyCorrFit documentation
=======================
.. image:: _static/PyCorrFit_logo_dark.png
|
Welcome to the documentation of PyCorrFit (version |release|), a data analysis software for
fluorescence correlation spectroscopy (FCS).
Documentation
=============
.. toctree::
:maxdepth: 1
:caption: Contents:
:maxdepth: 2
sec_about
sec_gallery
sec_getting_started
sec_contribute
.. toctree::
:maxdepth: 1
sec_changelog
......
......@@ -3,8 +3,7 @@ from os.path import dirname, abspath, split
import sys
sys.path = [split(abspath(dirname(__file__)))[0]] + sys.path
from pycorrfit.gui import main
from pycorrfit.gui import main # noqa: E402
if __name__ == "__main__":
......
......@@ -138,4 +138,4 @@ if True: # pragma: no cover
save_version(longversion, versionfile)
# PEP 440-conform development version:
version = ".dev".join(longversion.split("-")[:2])
version = ".post".join(longversion.split("-")[:2])
......@@ -12,6 +12,7 @@ from .trace import Trace
class Correlation(object):
""" unifies correlation curve handling
"""
def __init__(self, backgrounds=[], correlation=None, corr_type="AC",
filename=None, fit_algorithm="Lev-Mar",
fit_model=6000, fit_ival=(0, 0),
......@@ -144,7 +145,8 @@ class Correlation(object):
elif isinstance(v, Trace):
backgrounds.append(v)
else:
raise ValueError("Each background must be instance of Trace or ndarray")
raise ValueError(
"Each background must be instance of Trace or ndarray")
self._backgrounds = backgrounds
@property
......@@ -326,7 +328,8 @@ class Correlation(object):
# overwrite fitting parameters
self._fit_parameters = self._fit_model.default_values
self._fit_parameters_variables = self._fit_model.default_variables
self._fit_parameters_range = np.zeros((len(self._fit_parameters), 2))
self._fit_parameters_range = np.zeros(
(len(self._fit_parameters), 2))
self.normparm = None
@property
......@@ -399,7 +402,8 @@ class Correlation(object):
def fit_parameters_variable(self):
"""which parameters are variable during fitting"""
if self._fit_parameters_variable is None:
self._fit_parameters_variable = np.array(self.fit_model.default_variables, dtype=bool)
self._fit_parameters_variable = np.array(
self.fit_model.default_variables, dtype=bool)
return self._fit_parameters_variable
@fit_parameters_variable.setter
......@@ -426,7 +430,8 @@ class Correlation(object):
@lag_time.setter
def lag_time(self, value):
if self.correlation is not None:
warnings.warn("Setting lag time not possible, because of existing correlation")
warnings.warn(
"Setting lag time not possible, because of existing correlation")
else:
self._lag_time = value
......@@ -532,7 +537,8 @@ class Correlation(object):
elif isinstance(v, Trace):
traces.append(v)
else:
raise ValueError("Each trace must be instance of Trace or ndarray")
raise ValueError(
"Each trace must be instance of Trace or ndarray")
self._traces = traces
if len(self._traces) == 2:
......
......@@ -7,9 +7,14 @@ import numpy as np
import scipy.interpolate as spintp
class StuckParameterWarning(UserWarning):
pass
class Constraint(object):
""" Class to translate fit constraints to lmfit syntax.
"""
def __init__(self, constraint, fit_bool, fit_bounds, fit_values):
"""
Parameters
......@@ -160,7 +165,8 @@ class Constraint(object):
deltaname = "delta_{}_{}".format(p1["id"], p2["id"])
kwdelt = {}
kwdelt["name"] = deltaname
kwdelt["value"] = p2["bool"]*self.fit_values[p2["id"]] - self.fit_values[p1["id"]]
kwdelt["value"] = p2["bool"] * \
self.fit_values[p2["id"]] - self.fit_values[p1["id"]]
kwdelt["vary"] = True
kwdelt["min"] = 0 # note: enforces "<=" (not "<")
kwdelt["max"] = np.inf
......@@ -169,7 +175,8 @@ class Constraint(object):
kwp1["name"] = "parm{:04d}".format(p1["id"])
# this condition deals with negative numbers
kwp1["expr"] = "{MIN} if {COMP} < {MIN} else {MAX} if {COMP} > {MAX} else {COMP}".format(
COMP="{}*parm{:04d}-{}+{:.14f}".format(p2["sign"], p2["id"], deltaname, ofs),
COMP="{}*parm{:04d}-{}+{:.14f}".format(
p2["sign"], p2["id"], deltaname, ofs),
MIN=self.fit_bounds[p1["id"]][0],
MAX=self.fit_bounds[p1["id"]][1])
kwargs = [kwdelt, kwp1]
......@@ -181,16 +188,19 @@ class Constraint(object):
deltaname = "delta_{}_{}".format(p1["id"], p2["id"])
kwdelt = {}
kwdelt["name"] = deltaname
kwdelt["value"] = self.fit_values[p1["id"]] - p2["bool"]*self.fit_values[p2["id"]]
kwdelt["value"] = self.fit_values[p1["id"]] - \
p2["bool"]*self.fit_values[p2["id"]]
kwdelt["vary"] = True
kwdelt["min"] = 0 # note: enforces ">=" (not ">")
kwdelt["max"] = np.inf #self.fit_bounds[p1["id"]][1] + max(-p2["sign"]*self.fit_bounds[p2["id"]]) - ofs
# self.fit_bounds[p1["id"]][1] + max(-p2["sign"]*self.fit_bounds[p2["id"]]) - ofs
kwdelt["max"] = np.inf
kwp1 = {}
kwp1["name"] = "parm{:04d}".format(p1["id"])
# this condition deals with negative numbers
kwp1["expr"] = "{MIN} if {COMP} < {MIN} else {MAX} if {COMP} > {MAX} else {COMP}".format(
COMP="{}*parm{:04d}+{}+{:.14f}".format(p2["sign"], p2["id"], deltaname, ofs),
COMP="{}*parm{:04d}+{}+{:.14f}".format(
p2["sign"], p2["id"], deltaname, ofs),
MIN=self.fit_bounds[p1["id"]][0],
MAX=self.fit_bounds[p1["id"]][1])
......@@ -202,10 +212,10 @@ class Constraint(object):
return kwargs
class Fit(object):
""" Used for fitting FCS data to models.
"""
def __init__(self, correlations=[], global_fit=False,
global_fit_variables=[],
uselatex=False, verbose=0):
......@@ -320,8 +330,8 @@ class Fit(object):
self.fit_parm_names = varin
self.fit_bound = varbound
self.constraints = []
warnings.warn("Constraints are not supported yet for global fitting.")
warnings.warn(
"Constraints are not supported yet for global fitting.")
def parameters_global_to_local(parameters, iicorr, varin=varin,
initpar=initpar,
......@@ -337,7 +347,8 @@ class Fit(object):
for kk, pn in enumerate(mod.parameters[0]):
if pn in varin:
# edit that parameter
fit_parm[kk] = parameters[np.where(np.array(varin)==pn)[0]]
fit_parm[kk] = parameters[np.where(
np.array(varin) == pn)[0]]
return fit_parm
def parameters_local_to_global(parameters, iicorr, fit_parm,
......@@ -351,7 +362,8 @@ class Fit(object):
for kk, pn in enumerate(mod.parameters[0]):
if pn in varin:
# edit that parameter
parameters[np.where(np.array(varin)==pn)[0]] = fit_parm[kk]
parameters[np.where(np.array(varin) == pn)[
0]] = fit_parm[kk]
return parameters
# Create function for fitting using ids
......@@ -394,7 +406,6 @@ class Fit(object):
# save fit data in correlation class
corr.fit_results = self.get_fit_results(corr)
def get_fit_results(self, correlation):
"""
Return a dictionary with all information about the performed fit.
......@@ -422,7 +433,6 @@ class Fit(object):
return d
@property
def chi_squared(self):
""" Calculate displayed Chi²
......@@ -445,12 +455,11 @@ class Fit(object):
variance = self.fit_weights**2
chi2 = np.sum((self.y-fitted)**2/variance) / dof
else:
chi2 = self.fit_function_scalar(self.fit_parm, self.x, self.y, self.fit_weights)
chi2 = self.fit_function_scalar(
self.fit_parm, self.x, self.y, self.fit_weights)
return chi2
@property
def chi_squared_type(self):
""" The type of Chi² that currently applies.
......@@ -470,7 +479,6 @@ class Fit(object):
else:
raise ValueError("Unknown weight type!")
@staticmethod
def compute_weights(correlation, verbose=0, uselatex=False):
""" computes and returns weights of the same length as
......@@ -503,7 +511,8 @@ class Fit(object):
weight_spread = int(weight_data)
except:
if verbose > 1:
warnings.warn("Could not get weight spread for spline. Setting it to 3.")
warnings.warn(
"Could not get weight spread for spline. Setting it to 3.")
weight_spread = 3
if weight_type[:6] == "spline":
......@@ -541,11 +550,11 @@ class Fit(object):
ys = spintp.splev(xs, tck, der=0)
except:
if verbose > 0:
raise ValueError("Could not find spline fit with "+\
raise ValueError("Could not find spline fit with " +
"{} knots.".format(knotnumber))
return
if verbose > 0:
## If plotting module is available:
# If plotting module is available:
#name = "spline fit: "+str(knotnumber)+" knots"
# plotting.savePlotSingle(name, 1*x, 1*y, 1*ys,
# dirname=".",
......@@ -560,7 +569,7 @@ class Fit(object):
# Tell the user to install matplotlib
print("Couldn't import pylab! - not Plotting")
## Calculation of variance
# Calculation of variance
# In some cases, the actual cropping interval from ival[0]
# to ival[1] is chosen, such that the dataweights must be
# calculated from unknown datapoints.
......@@ -646,7 +655,8 @@ class Fit(object):
dataweights[i] *= reference/dividor
# Do not substitute len(diff[start:end]) with end-start!
# It is not the same!
backset = 2*weight_spread + 1 - len(diff[start:end]) - offsetstart
backset = 2*weight_spread + 1 - \
len(diff[start:end]) - offsetstart
if backset != 0:
reference = 2*weight_spread + 1
dividor = reference - backset
......@@ -673,7 +683,6 @@ class Fit(object):
return dataweights
def fit_function(self, params, x, y, weights=1):
"""
objective function that returns the residual (difference between
......@@ -686,7 +695,7 @@ class Fit(object):
with np.errstate(divide='ignore'):
tominimize = np.where(weights != 0,
tominimize/weights, 0)
## There might be NaN values because of zero weights:
# There might be NaN values because of zero weights:
#tominimize = tominimize[~np.isinf(tominimize)]
return tominimize
......@@ -856,11 +865,12 @@ class Fit(object):
# write changes
self.fit_parm = parmsres
params = self.get_lmfitparm()
warnings.warn(u"PyCorrFit detected problems in fitting, "+\
u"detected a stuck parameter, multiplied "+\
u"it by {}, and fitted again. ".format(multby)+\
warnings.warn(u"PyCorrFit detected problems in fitting, " +
u"detected a stuck parameter, multiplied " +
u"it by {}, and fitted again. ".format(multby) +
u"The stuck parameters are: {}".format(
np.array(self.fit_parm_names)[parmstuck]))
np.array(self.fit_parm_names)[parmstuck]),
StuckParameterWarning)
elif diff < 1e-8:
# Experience tells us this is good enough.
break
......@@ -883,17 +893,16 @@ class Fit(object):
try:
self.parmoptim_error = np.diag(covar)
except:
warnings.warn("PyCorrFit Warning: Error estimate not "+\
"possible, because we could not "+\
"calculate covariance matrix. Please "+\
"try reducing the number of fitting "+\
warnings.warn("PyCorrFit Warning: Error estimate not " +
"possible, because we could not " +
"calculate covariance matrix. Please " +
"try reducing the number of fitting " +
"parameters.")
self.parmoptim_error = None
else:
self.parmoptim_error = None
def GetAlgorithmStringList():
"""
Get supported fitting algorithms as strings.
......
......@@ -61,10 +61,10 @@ def info(version):
texta = textlin
one = u" PyCorrFit version "+version+"\n\n"
two = u"\n\n Supported file types:"
keys = readfiles.Filetypes.keys()
keys = readfiles.filetypes_dict.keys()
keys = sorted(list(keys))
for item in keys:
if item.split("|")[0] != readfiles.Allsupfilesstring:
if item.split("|")[0] != readfiles.ALL_SUP_STRING:
two = two + "\n - "+item.split("|")[0]
lizenz = ""
for line in licence().splitlines():
......
......@@ -15,7 +15,8 @@ import wx
with warnings.catch_warnings():
warnings.simplefilter("ignore")
try:
matplotlib.use('WXAgg') # Tells matplotlib to use WxWidgets for dialogs
# Tells matplotlib to use WxWidgets for dialogs
matplotlib.use('WXAgg')
except:
pass
......@@ -27,7 +28,7 @@ class ChoicesDialog(wx.Dialog):
# super(ChoicesDialog, self).__init__(parent=parent,
# title=title)
wx.Dialog.__init__(self, parent, -1, title)
## Controls
# Controls
panel = wx.Panel(self)
# text1
textopen = wx.StaticText(panel, label=text)
......@@ -57,12 +58,10 @@ class ChoicesDialog(wx.Dialog):
self.SelcetedID = self.dropdown.GetSelection()
self.EndModal(wx.ID_OK)
def OnAbort(self, event=None):
self.EndModal(wx.ID_CANCEL)
def save_figure(self, evt=None):
"""
A substitude function for save in:
......@@ -138,7 +137,8 @@ class MyScrolledDialog(wx.Dialog):
btnsizer.Add(btn, 0, wx.ALL, 5)
sizer.Add(overtext, 0, wx.EXPAND | wx.ALL, 5)
sizer.Add(text, 0, wx.EXPAND | wx.ALL, 5)
sizer.Add(btnsizer, 0, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
sizer.Add(btnsizer, 0, wx.EXPAND |
wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
self.SetSizerAndFit(sizer)
......@@ -154,7 +154,8 @@ class MyOKAbortDialog(wx.Dialog):
btn = wx.Button(self, wx.ID_CANCEL) # , "Abort ")
btnsizer.Add(btn, 0, wx.ALL, 5)
sizer.Add(overtext, 0, wx.EXPAND | wx.ALL, 5)
sizer.Add(btnsizer, 0, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
sizer.Add(btnsizer, 0, wx.EXPAND |
wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
self.SetSizerAndFit(sizer)
......@@ -174,7 +175,8 @@ class MyYesNoAbortDialog(wx.Dialog):
btn3 = wx.Button(self, wx.ID_CANCEL)
btnsizer.Add(btn3, 0, wx.ALL, 5)
sizer.Add(overtext, 0, wx.EXPAND | wx.ALL, 5)
sizer.Add(btnsizer, 0, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
sizer.Add(btnsizer, 0, wx.EXPAND |
wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
self.SetSizerAndFit(sizer)
self.SetFocus()
self.Show()
......
This diff is collapsed.
"""Main execution script"""
from distutils.version import LooseVersion
import os
import sys
import warnings
import yaml
import numpy as np
import scipy
class Fake(object):
""" Fake module.
"""
def __init__(self):
self.__version__ = "0.0 unknown"
self.version = "0.0 unknown"
......@@ -21,12 +26,9 @@ except ImportError:
matplotlib = Fake()
# We do catch warnings about performing this before matplotlib.backends stuff
# matplotlib.use('WXAgg') # Tells matplotlib to use WxWidgets
import warnings
with warnings.catch_warnings():
warnings.simplefilter("ignore")
matplotlib.use('WXAgg') # Tells matplotlib to use WxWidgets for dialogs
import numpy as np # NumPy
import scipy
# Sympy is optional:
......@@ -38,16 +40,14 @@ except ImportError:
# We create a fake module sympy with a __version__ property.
# This way users can run PyCorrFit without having installed sympy.
sympy = Fake()
# We must not import wx here. frontend/gui does that. If we do import wx here,
# somehow unicode characters will not be displayed correctly on windows.
# import wx
import yaml
## Continue with the import:
sys.path.append(os.path.abspath(os.path.dirname(__file__)))
from . import doc
from . import frontend as gui # The actual program
# Continue with the import:
from . import frontend as gui # noqa: E402
from . import doc # noqa: E402
def CheckVersion(given, required, name):
......@@ -62,22 +62,22 @@ def CheckVersion(given, required, name):
print(" WARNING: Could not verify version of "+name+".")
return
if req > giv:
print(" WARNING: You are using "+name+" v. "+given+\
print(" WARNING: You are using "+name+" v. "+given +
" | Required: "+name+" " + required)
else:
print(" OK: "+name+" v. "+given+" | "+required+" required")
## Start gui
# Start gui
def Main():
## VERSION
# VERSION
version = doc.__version__
__version__ = version
print(gui.doc.info(version))
## Check important module versions
# Check important module versions
print("\n\nChecking module versions...")
CheckVersion(matplotlib.__version__, "2.2.2", "matplotlib")
CheckVersion(np.__version__, "1.14.2", "NumPy")
......@@ -86,7 +86,7 @@ def Main():
CheckVersion(sympy.__version__, "1.1.1", "sympy")
CheckVersion(gui.wx.__version__, "4.0.1", "wxPython")
## Start gui
# Start gui
app = gui.MyApp(False)
frame = gui.MyFrame(None, -1, version)
......
......@@ -110,4 +110,3 @@ def getMainIcon(pxlength=32):
iconBMP = wx.Bitmap(image)
iconICO = wx.Icon(iconBMP)
return iconICO
......@@ -19,11 +19,11 @@ from . import tools
from . import wxutils
class FittingPanel(wx.Panel):
"""
Those are the Panels that show the fitting dialogs with the Plots.
"""
def __init__(self, parent, counter, modelid, active_parms, tau=None):
""" Initialize with given parameters. """
wx.Panel.__init__(self, parent=parent, id=wx.ID_ANY)
......@@ -47,7 +47,6 @@ class FittingPanel(wx.Panel):
self.weighted_fittype_id = 0 # integer (drop down item)
self.weighted_nuvar = 3 # bins for std-dev. (left and rigth)
# The weights that are plotted in the page
# This is set by the PlotAll function
self.weights_plot_fill_area = None
......@@ -66,7 +65,7 @@ class FittingPanel(wx.Panel):
# Tool statistics uses this list:
self.StatisticsCheckboxes = None
### Splitter window
# Splitter window
# Sizes
size = parent.notebook.GetSize()
tabsize = 33
......@@ -78,11 +77,11 @@ class FittingPanel(wx.Panel):
self.sp = wx.SplitterWindow(self, size=size, style=wx.SP_3DSASH)
# This is necessary to prevent "Unsplit" of the SplitterWindow:
self.sp.SetMinimumPaneSize(1)
## Settings Section (left side)
# Settings Section (left side)
#self.panelsettings = wx.Panel(self.sp, size=sizepanel)
self.panelsettings = scrolled.ScrolledPanel(self.sp, size=sizepanel)
self.panelsettings.SetupScrolling(scroll_x=False)
## Setting up Plot (correlation + chi**2)
# Setting up Plot (correlation + chi**2)
self.spcanvas = wx.SplitterWindow(self.sp, size=sizecanvas,
style=wx.SP_3DSASH)
# This is necessary to prevent "Unsplit" of the SplitterWindow:
......@@ -256,7 +255,6 @@ class FittingPanel(wx.Panel):
# function, write them back.
self.apply_parameters_reverse()
def apply_parameters_reverse(self, event=None):
""" Read the values from the pages parameters and write
it to the GUI form.
......@@ -295,14 +293,12 @@ class FittingPanel(wx.Panel):
self.AlgorithmDropdown.SetSelection(idalg)
self.updateChi2()
def calculate_corr(self):
"""
Calculate model correlation function
"""
return self.corr.modeled
def Fit_enable_fitting(self):
""" Enable the fitting button and the weighted fit control"""
# self.Fitbox = [ fitbox, weightedfitdrop, fittext, fittext2,
......@@ -314,7 +310,6 @@ class FittingPanel(wx.Panel):
self.Fitbox[7].Enable()
self.Fitbox[8].Enable()
def Fit_function(self, event=None, noplots=False, trigger=None):
""" Calls the fit function.
......@@ -327,7 +322,6 @@ class FittingPanel(wx.Panel):
"""
tools.batchcontrol.FitProgressDlg(self, self)
def Fit_finalize(self, trigger):
""" Things that need be done after fitting
"""
......@@ -350,7 +344,6 @@ class FittingPanel(wx.Panel):
# update displayed chi2
self.updateChi2()
def Fit_WeightedFitCheck(self, event=None):
""" Enable Or disable variance calculation, dependent on
"Weighted Fit" checkbox
......@@ -371,7 +364,6 @@ class FittingPanel(wx.Panel):
self.Fitbox[4].Disable()
self.Fitbox[5].Disable()
def MakeStaticBoxSizer(self, boxlabel):
""" Create a Box with check boxes (fit yes/no) and possibilities to
change initial values for fitting.
......@@ -410,26 +402,25 @@ class FittingPanel(wx.Panel):
sizer.Add(sizerh)
return sizer, check, spin
def OnAmplitudeCheck(self, event=None):
""" Enable/Disable BG rate text line.
New feature introduced in 0.7.8
"""
modelid = self.corr.fit_model.id
## Normalization to a certain parameter in plots
# Normalization to a certain parameter in plots
# Find all parameters that start with an "N"
# ? and "C" ?
# Create List
normlist = list()
normlist.append("None")
## Add parameters
# Add parameters
parameterlist = list()
for i in np.arange(len(self.active_parms[0])):
label = self.active_parms[0][i]
if label[0].lower() == "n":
normlist.append("*"+label)
parameterlist.append(i)
## Add supplementary parameters
# Add supplementary parameters
# Get them from models
supplement = mdls.GetMoreInfo(modelid, self)
if supplement is not None:
......@@ -457,7 +448,7 @@ class FittingPanel(wx.Panel):
# Set dropdown values
self.AmplitudeInfo[2].SetItems(normlist)
self.AmplitudeInfo[2].SetSelection(normsel)
## Plot intensities
# Plot intensities
# Quick reminder:
# self.AmplitudeInfo = [ [intlabel1, intlabel2],
# [bgspin1, bgspin2],
......@@ -473,10 +464,10 @@ class FittingPanel(wx.Panel):
else:
self.AmplitudeInfo[0][1].Disable()
# Background
## self.parent.Background[self.bgselected][i]
## [0] average signal [kHz]
## [1] signal name (edited by user)
## [2] signal trace (tuple) ([ms], [kHz])
# self.parent.Background[self.bgselected][i]
# [0] average signal [kHz]
# [1] signal name (edited by user)
# [2] signal trace (tuple) ([ms], [kHz])
if len(self.corr.backgrounds) >= 1:
self.AmplitudeInfo[1][0].SetValue(
self.corr.backgrounds[0].countrate)
......@@ -495,7 +486,6 @@ class FittingPanel(wx.Panel):
for item in self.WXAmplitudeCCOnlyStuff:
item.Enable(boolval)
def OnBGSpinChanged(self, e):
""" Calls tools.background.ApplyAutomaticBackground
to update background information
......@@ -529,7 +519,6 @@ class FittingPanel(wx.Panel):
self.parent)
e.Skip()
def OnTitleChanged(self, e):
modelid = self.corr.fit_model.id
pid = self.parent.notebook.GetPageIndex(self)
......@@ -563,7 +552,6 @@ class FittingPanel(wx.Panel):
pass
self.parent.RangeSelector = None
def OnSize(self, event):
""" Resize the fitting Panel, when Window is resized. """
size = self.parent.notebook.GetSize()
......@@ -571,7 +559,6 @@ class FittingPanel(wx.Panel):
size[1] = size[1] - tabsize
self.sp.SetSize(size)
def PlotAll(self, event=None, trigger=None):
"""
This function plots the whole correlation and residuals canvas.
......@@ -598,12 +585,12 @@ class FittingPanel(wx.Panel):
return
else:
self.InitialPlot = True
## Enable/Disable, set values frontend normalization
# Enable/Disable, set values frontend normalization
self.OnAmplitudeCheck()
## Apply parameters
# Apply parameters
self.apply_parameters()
# Calculate correlation function from parameters
## Drawing of correlation plot
# Drawing of correlation plot
# Plots corr.correlation_fit and the calcualted correlation function
# self.datacorr into the upper canvas.
# Create a line @ y=zero:
......@@ -640,7 +627,8 @@ class FittingPanel(wx.Panel):
weights = 0
elif weights.shape[0] != self.corr.modeled_fit.shape[0]:
# non-matching weigths
warnings.warn("Unmatching weights found. Probably from previous data set.")
warnings.warn(
"Unmatching weights found. Probably from previous data set.")
weights = 0
# Add the weights to the graph.
......@@ -656,8 +644,9 @@ class FittingPanel(wx.Panel):
if np.all(w[:, 0] == self.corr.correlation_fit[:, 0]):
pass
else:
raise ValueError("This should not have happened: size of weights is wrong.")
## Normalization with self.normfactor
raise ValueError(
"This should not have happened: size of weights is wrong.")
# Normalization with self.normfactor
w1[:, 1] *= self.corr.normalize_factor
w2[:, 1] *= self.corr.normalize_factor
self.weights_plot_fill_area = [w1, w2]
......@@ -670,7 +659,7 @@ class FittingPanel(wx.Panel):
else:
self.weights_plot_fill_area = None
## Plot Correlation curves
# Plot Correlation curves
# Plot both, experimental and calculated data
# Normalization with self.normfactor, new feature in 0.7.8
datacorr_norm = self.corr.modeled_plot
......@@ -686,7 +675,7 @@ class FittingPanel(wx.Panel):
xLabel=u'lag time τ [ms]', yLabel=u'G(τ)')
self.canvascorr.Draw(PlotCorr)
## Calculate residuals
# Calculate residuals
resid_norm = self.corr.residuals_plot
lineres = plot.PolyLine(resid_norm, legend='', colour=colfit,
width=width)
......@@ -711,7 +700,6 @@ class FittingPanel(wx.Panel):
self.Refresh()
self.parent.OnFNBPageChanged(trigger=trigger)
def settings(self):
""" Here we define, what should be displayed at the left side
of the fitting page/tab.
......@@ -769,8 +757,9 @@ class FittingPanel(wx.Panel):
box1.Add(horzs)
# Set horizontal size
box1.SetMinSize((horizontalsize, -1))
## More info
normbox = wx.StaticBox(self.panelsettings, label="Amplitude corrections")
# More info
normbox = wx.StaticBox(
self.panelsettings, label="Amplitude corrections")
miscsizer = wx.StaticBoxSizer(normbox, wx.VERTICAL)
miscsizer.SetMinSize((horizontalsize, -1))
# Intensities and Background
......@@ -797,7 +786,7 @@ class FittingPanel(wx.Panel):
sizeint.Add(intlabel2)
sizeint.Add(bgspin2)
miscsizer.Add(sizeint)
## Normalize to n?
# Normalize to n?
textnor = wx.StaticText(self.panelsettings, label="Plot normalization")
miscsizer.Add(textnor)
normtoNDropdown = wx.ComboBox(self.panelsettings)
......@@ -808,7 +797,7 @@ class FittingPanel(wx.Panel):
normtoNDropdown, textnor]
self.WXAmplitudeCCOnlyStuff = [chtext2, intlabel2, bgspin2]
self.panelsettings.sizer.Add(miscsizer, 0, wx.EXPAND, 0)
## Add fitting Box
# Add fitting Box
fitbox = wx.StaticBox(self.panelsettings, label="Fitting options")
fitsizer = wx.StaticBoxSizer(fitbox, wx.VERTICAL)
fitsizer.SetMinSize((horizontalsize, -1))
......@@ -834,7 +823,8 @@ class FittingPanel(wx.Panel):
fitsizer.Add(fittext2)
fitsizerspin = wx.BoxSizer(wx.HORIZONTAL)
fittextvar = wx.StaticText(self.panelsettings, label="j = ")
fitspin = wx.SpinCtrl(self.panelsettings, -1, initial=3, min=1, max=100)
fitspin = wx.SpinCtrl(self.panelsettings, -1,
initial=3, min=1, max=100)
fitsizerspin.Add(fittextvar)
fitsizerspin.Add(fitspin)
fitsizer.Add(fitsizerspin)
......@@ -854,8 +844,9 @@ class FittingPanel(wx.Panel):
self.Bind(wx.EVT_BUTTON, self.Fit_function, buttonfit)
fitbuttonsizer.Add(buttonfit)
## add shortcut
acctbl = wx.AcceleratorTable([(wx.ACCEL_CTRL, ord('F'), buttonfit.GetId())])
# add shortcut
acctbl = wx.AcceleratorTable(
[(wx.ACCEL_CTRL, ord('F'), buttonfit.GetId())])
self.SetAcceleratorTable(acctbl)
##
......@@ -879,7 +870,6 @@ class FittingPanel(wx.Panel):
self.panelsettings.sizer.Fit(self.panelsettings)
self.parent.Layout()
def updateChi2(self):
"""
updates the self.WXTextChi2 text control
......
......@@ -13,15 +13,16 @@ import re
with warnings.catch_warnings():
warnings.simplefilter("ignore")
matplotlib.use('WXAgg') # Tells matplotlib to use WxWidgets for dialogs
import matplotlib.gridspec as gridspec
import matplotlib.pyplot as plt
# Text rendering with matplotlib
from matplotlib import rcParams
import unicodedata
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
# For finding latex tools
from pycorrfit.meta import find_program
from pycorrfit import models as mdls
import unicodedata
from .. import models as mdls
from ..meta import find_program
def greek2tex(char):
......@@ -168,9 +169,10 @@ def savePlotCorrelation(parent, dirname, Page, uselatex=False,
if tabtitle.strip() == "":
tabtitle = "page"+str(Page.counter).strip().strip(":")
if Page.corr.normparm is not None:
fitlabel += r", normalized to "+Page.corr.fit_model.parameters[0][Page.corr.normparm]
fitlabel += r", normalized to " + \
Page.corr.fit_model.parameters[0][Page.corr.normparm]
## Check if we can use latex for plotting:
# Check if we can use latex for plotting:
r1 = find_program("latex")[0]
r2 = find_program("dvipng")[0]
# Ghostscript
......@@ -240,7 +242,7 @@ def savePlotCorrelation(parent, dirname, Page, uselatex=False,
text += r'\['
text += r'\begin{split}'
text += genLatexText(parms, labels)
## According to issue #54, we remove fitting errors from plots
# According to issue #54, we remove fitting errors from plots
# if errparms is not None:
# keys = errparms.keys()
# keys.sort()
......@@ -252,15 +254,13 @@ def savePlotCorrelation(parent, dirname, Page, uselatex=False,
text = r""
for i in np.arange(len(parms)):
text += u"{} = {:.3g}\n".format(labels[i], parms[i])
## According to issue #54, we remove fitting errors from plots
# According to issue #54, we remove fitting errors from plots
# if errparms is not None:
# keys = errparms.keys()
# keys.sort()
# for key in keys:
# text += "Err "+key+" = " + str(errparms[key]) +"\n"
logmax = np.log10(xmax)
logmin = np.log10(xmin)
logtext = 0.6*(logmax-logmin)+logmin
......@@ -294,14 +294,13 @@ def savePlotCorrelation(parent, dirname, Page, uselatex=False,
ax2.set_ylim(-maxy, maxy)
ticks = ax2.get_yticks()
ax2.set_yticks([ticks[0], ticks[-1], 0])
## Hack
# Hack
# We need this for hacking. See edclasses.
fig.canvas.HACK_parent = parent
fig.canvas.HACK_fig = fig
fig.canvas.HACK_Page = Page
fig.canvas.HACK_append = ".png"
# Legend outside of plot
# Decrease size of plot to fit legend
box = ax.get_position()
......@@ -317,7 +316,6 @@ def savePlotCorrelation(parent, dirname, Page, uselatex=False,
ax.legend(loc='upper center', bbox_to_anchor=(0.5, -0.55),
prop={'size': 9})
if verbose == True:
plt.show()
else:
......@@ -364,7 +362,7 @@ def savePlotTrace(parent, dirname, Page, uselatex=False, verbose=False):
for ii, tr in enumerate(traces):
labels.append("Channel {}: {}".format(ii+1, tr.name))
## Check if we can use latex for plotting:
# Check if we can use latex for plotting:
r1 = find_program("latex")[0]
r2 = find_program("dvipng")[0]
# Ghostscript
......@@ -417,7 +415,7 @@ def savePlotTrace(parent, dirname, Page, uselatex=False, verbose=False):
prop={'size': 9},
)
## Hack
# Hack
# We need this for hacking. See edclasses.
fig.canvas.HACK_parent = parent
fig.canvas.HACK_fig = fig
......@@ -441,5 +439,6 @@ def savePlotTrace(parent, dirname, Page, uselatex=False, verbose=False):
except:
pass
# set dpi to 300
matplotlib.rcParams['savefig.dpi'] = 300
......@@ -20,6 +20,7 @@ class KThread(threading.Thread):
thread will not actually be killed until the next Python statement is
executed.
"""
def __init__(self, *args, **keywords):
threading.Thread.__init__(self, *args, **keywords)
self.killed = False
......@@ -53,9 +54,9 @@ class KThread(threading.Thread):
self.killed = True
class WorkerThread(KThread):
"""Worker Thread Class."""
def __init__(self, target, args, kwargs):
"""Init Worker Thread Class."""
KThread.__init__(self)
......@@ -142,7 +143,6 @@ class ThreadedProgressDlg(object):
if not messages:
messages = ["item {} of {}".format(a+1, nums) for a in range(nums)]
time1 = time.time()
sty = wx.PD_SMOOTH | wx.PD_AUTO_HIDE | wx.PD_CAN_ABORT
if len(targets) > 1:
......@@ -207,11 +207,11 @@ class ThreadedProgressDlg(object):
pass
if __name__ == "__main__":
# GUI Frame class that spins off the worker thread
class MainFrame(wx.Frame):
"""Class MainFrame."""
def __init__(self, parent, aid):
"""Create the MainFrame."""
wx.Frame.__init__(self, parent, aid, 'Thread Test')
......@@ -219,13 +219,13 @@ if __name__ == "__main__":
# Dumb sample frame with two buttons
but = wx.Button(self, wx.ID_ANY, 'Start Progress', pos=(0, 0))
self.Bind(wx.EVT_BUTTON, self.OnStart, but)
def OnStart(self, event):
"""Start Computation."""
# Trigger the worker thread unless it's already busy
arguments = [test_class(a) for a in range(10)]
def method(x):
x.arg *= 1.1
time.sleep(1)
......@@ -233,9 +233,9 @@ if __name__ == "__main__":
print(tp.index_aborted)
print([a.arg for a in arguments])
class MainApp(wx.App):
"""Class Main App."""
def OnInit(self):
"""Init Main App."""
self.frame = MainFrame(None, -1)
......@@ -247,6 +247,5 @@ if __name__ == "__main__":
def __init__(self, arg):
self.arg = arg
app = MainApp(0)
app.MainLoop()