...
 
Commits (75)
before_script:
- eval $(ssh-agent -s)
- echo "$ssh_key" | tr -d '\r' | ssh-add - > /dev/null
- mkdir -p ~/.ssh
- chmod 700 ~/.ssh
- ssh-keyscan -H 'vcs.ynic.york.ac.uk' >> ~/.ssh/known_hosts
- chmod 644 ~/.ssh/known_hosts
- apt -y build-dep .
stages:
- build_test
- deploy
build_test:
stage: build_test
script:
- git clone https://vcs.ynic.york.ac.uk/naf/naf-testdata.git
- git clone https://vcs.ynic.york.ac.uk/naf/python-megdata.git
- make -C python-megdata -f Makefile.dev
- PYTHONPATH=python-megdata/build/lib.linux-x86_64-2.7 make
- ls
- cd build
- ls
- PYTHONPATH=../python-megdata/build/lib.linux-x86_64-2.7:lib.linux-x86_64-2.7 NAFTEST=../naf-testdata xvfb-run -a nosetests -c ../nose.cfg -v lib.linux-x86_64-2.7/naf
artifacts:
paths:
- build
deploy:
stage: deploy
script:
- echo "deploy"
......@@ -8,12 +8,12 @@ BINS=$(shell python setup.py --list-scripts)
USAGES=$(addsuffix .txt,$(addprefix doc/gen/usage_,$(BINS)))
SCRIPT_SRC=$(addsuffix .rst,$(addprefix doc/gen/source_,$(BINS)))
PY4UICFILES=$(subst .ui,.py,$(wildcard naf/gui/qt4/ui/*.ui))
PYUICFILES=$(subst .ui,.py,$(wildcard naf/gui/qt/ui/*.ui))
DEVELVERSION ?= 0.DEVEL.$(shell date +%Y%m%d%H%M)
RELEASEVERSION ?= $(DEVELVERSION)
all: $(PY4UICFILES)
all: $(PYUICFILES)
python setup.py build
doc: doc-html
......@@ -28,8 +28,8 @@ doc/gen/source_%.rst: bin/%
@mkdir -p doc/gen
sed "s@PROGNAME@$*@" doc/source_template > $@
naf/gui/qt4/ui/%.py: naf/gui/qt4/ui/%.ui
pyuic4 -o $@ $<
naf/gui/qt/ui/%.py: naf/gui/qt/ui/%.ui
pyuic5 -o $@ $<
doc/bibliography/paperindex.inc: doc/bibliography/references.bib doc/bibliography/parse_references.py
cd doc/bibliography && python parse_references.py
......@@ -47,7 +47,7 @@ clean:
rm -fr doc/bibliography/papers
rm -f doc/bibliography/paperindex.inc
rm -f $(USAGES) $(SCRIPT_SRC)
rm -f $(PY4UICFILES)
rm -f $(PY5UICFILES)
test: all
cd build && PYTHONPATH=lib.$(PYTHONARCH)/:$${PYTHONPATH} NAFTEST=../../naf-testdata nosetests -c ../nose.cfg lib.$(PYTHONARCH)/naf
......
......@@ -22,9 +22,9 @@ release onwards). Package names are Debian binary package names.
python-wxgtk3.0 >= 3.0.1
python-yaml >= 3.11
python-mpi4py >= 1.3.1
python-qt4 >= 4.11.2
pyqt4-dev-tools: >= 4.11.2
qt4-dev-tools >= 4.8.6
python-pyqt5 >= 5.3.2
python-pyqt5.qtopengl >= 5.3.2
pyqt5-dev-tools: >= 5.3.2
python-vtk >= 5.8
python-bibtex >= 1.2.7
libgsl0-dev >= 1.16
......@@ -32,6 +32,12 @@ release onwards). Package names are Debian binary package names.
python-statsmodels >= 0.8
python-sphinx >= 1.2.3 (for building documentation and reports)
python-nose >= 1.3.4 (for running the test suite)
python-vtk >= 5.6
python-bibtex >= 1.2.4
libgsl0-dev >= 1.14
fftw-dev >= 2.1.3
python-sphinx >= 1.0.7
python-nose >= 0.11 (for running the test suite)
python-coverage (for getting test coverage)
xvfb (if building on a machine without an X display set)
......@@ -56,8 +62,8 @@ The following apt-get command should get all of the required dependencies:
apt-get install python-numpy python-scipy python-matplotlib python-h5py \
python-imaging python-dicom python-nifti python-mdp \
python-wxgtk3.0 python-yaml python-mpi4py python-qt4 \
qt4-dev-tools pyqt4-dev-tools python-vtk python-bibtex \
python-wxgtk3.0 python-yaml python-mpi4py python-pyqt5 \
python-pyqt5.qtopengl pyqt5-dev-tools python-vtk python-bibtex \
python-sphinx libgsl0-dev fftw-dev python-nose python-coverage \
python-statsmodels
......
......@@ -32,6 +32,12 @@ class OptionImportParameters(OptionHandlerBase):
outputgroup.add_option("-i","--subject-id", dest="subjectid", default="",
help="Subject identifier to put in file - defaults to empty string")
outputgroup.add_option("--apply-upb", dest="applyupb", default=False, action="store_true",
help="Apply UPB and convert to float")
outputgroup.add_option("--compress", dest="compress", default=False, action="store_true",
help="Compress datasets")
optparser.add_option_group(outputgroup)
return optparser
......@@ -93,7 +99,7 @@ else:
if isfile(e1):
inputs.append(BTIPDF.from_file(e1))
input_filenames.append(e1)
input_types.append('PREACQ')
input_types.append('COH')
# Add the main run
inputs.append(BTIPDF.from_file(inputfile))
......@@ -107,7 +113,7 @@ else:
# Add the pre-run file
inputs.append(BTIPDF.from_file(e2))
input_filenames.append(e2)
input_types.append('POSTACQ')
input_types.append('COH')
print "Run list:"
for r in range(len(inputs)):
......@@ -127,10 +133,10 @@ else:
bti_hs = BTIHSFile.from_file(hsfile)
h5 = from_bti_data(config, inputs, input_types, default_idx, bti_hs, op.subjectid)
h5 = from_bti_data(config, inputs, input_types, default_idx, bti_hs, op.subjectid, op.applyupb)
hfile = h5py.File(outputfile, 'w')
h5.to_hdf5(hfile)
h5.to_hdf5(hfile, op.compress)
hfile.close()
sys.exit(0)
......
This diff is collapsed.
This diff is collapsed.
......@@ -905,8 +905,8 @@ Optional arguments:
-j, --join-op Logical operation on code types to pre-reject, one of 'or' or 'and'
-E, --EEG Display EOG/ECG channels
-m --meg-threshold Magnitude threshold to apply before the first pass. Units are picotesla, i.e. -m 1.5 will reject epochs with values above 1.5e-12.
-l --low-freq Apply a low pass filter at the specified frequency (in Hz)
-u --high-freq Apply a high pass filter at the specified frequency (in Hz)
-l --low-freq Apply a high pass filter at the specified frequency (in Hz)
-u --high-freq Apply a low pass filter at the specified frequency (in Hz)
""" % os.path.basename(sys.argv[0])
sys.exit(exit_code)
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
#!/usr/bin/python
# vim: set expandtab ts=4 sw=4:
# This file is part of the NeuroImaging Analysis Framework
# For copyright and redistribution details, please see the COPYING file
import sys
import yaml
from naf.ynic.xmlparse import OldXMLParser
def convert_epoch_rejection(study):
from naf.meg.readers import EpochRejection
from naf.meg.rejection import SliceRejection
for runname in study.runs:
r = study.get_run(runname)
if not r.extra_data.has_key('epoch_rejection_file'):
continue
efilename = r.extra_data['epoch_rejection_file']
sfilename = efilename
if efilename.endswith('.txt'):
sfilename = sfilename[:-4]
sfilename += '_slicerej.txt'
# Find the epoch definer for this run
try:
reader = r.get_data(study)
ed = reader.epochdefiner
except Exception, e:
print "ERROR: Could not load data information for %s (%s) when converting epoch rejection files." % (runname, str(e))
sys.exit(1)
# Load epoch rejection filename
try:
er = EpochRejection.from_file(efilename)
except Exception, e:
print "ERROR: Could not load epoch rejection file %s when converting epoch rejection files." % (efilename)
sys.exit(1)
# Create the Slice Rejection file and write it out
try:
sr = SliceRejection.from_epoch_rejection(er, ed)
f = open(sfilename, 'w')
f.write(sr.to_string())
f.close()
except Exception, e:
print "ERROR: Could not write Slice Rejection File %s (%s)." % (sfilename, str(e))
sys.exit(1)
# Update the run object
del r.extra_data['epoch_rejection_file']
r.extra_data['slice_rejection_file'] = sfilename
return study
if len(sys.argv) < 2 or sys.argv[1] == '--help':
print """Usage: nafXMLToYAML filename.xml [outputname.yaml]
If no output filename is specified, stdout will be used.
Please note that as part of this process, any epoch rejection files
will be converted into slice rejection files with the suffix
_slicerej.txt.
"""
sys.exit(0)
y = OldXMLParser.load_study(sys.argv[1])
# Convert epoch rejection files to slice rejection files
y = convert_epoch_rejection(y)
if len(sys.argv) > 2:
out = open(sys.argv[2], 'w')
else:
out = sys.stdout
yaml.dump(y.to_yaml_dict(), out)
out.close()
......@@ -6,8 +6,8 @@ Build-Depends: debhelper (>= 7), fftw-dev, openmpi-bin, libopenmpi-dev, libgsl0-
python-coverage, python-nose, python-sphinx, python-bibtex,
python-h5py, python-numpy, python-scipy, python-matplotlib,
python-nifti, python-yaml, python-mpi4py, python-mdp, python-imaging,
pyqt4-dev-tools, python-qt4, python-vtk, python-wxgtk3.0, python-tk,
python-surfer, python-statsmodels
pyqt5-dev-tools, python-pyqt5, python-pyqt5.qtopengl, python-vtk6,
python-wxgtk3.0, python-tk, python-surfer, python-statsmodels
Standards-Version: 3.7.3
Homepage: https://vcs.ynic.york.ac.uk/naf
......@@ -16,7 +16,8 @@ Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, ${python:Depends},
openmpi-bin, python-h5py, python-numpy, python-scipy, python-matplotlib,
python-nifti, python-yaml, python-mpi4py, python-mdp, python-imaging,
python-qt4, python-vtk, python-wxgtk3.0, python-tk, python-statsmodels
python-pyqt5, python-pyqt5.qtopengl, python-vtk6, python-wxgtk3.0, python-tk,
python-statsmodels
Description: NeuroImaging Analysis Framework
YNiC NAF Code
......
......@@ -62,17 +62,17 @@ Statistics
However, we envisage the default way of generating results will become to make
statistic files and save the output of these rather than saving the
intermediate files (i.e. the NAI). :doc:`/userref/scripts/nafBFStats` will do this. The help
shows the options, but essentially you must specify an xml and a grid spacing.
shows the options, but essentially you must specify an YAML and a grid spacing.
You can then optionally specify as many runs, windows, conditions, filter etc
as you wish. Leaving a field blank i.e. filters, will ensure that all the
comparison is applied to all the filtered versions of the data. The key
argument is -C, which tells the script what you want to compare. ::
nafBFStats my/file.xml 5 -w act -w pass -c leftHand -c rightHand -C windows
nafBFStats my/file.yaml 5 -w act -w pass -c leftHand -c rightHand -C windows
This will perform an anlysis that compares the active and passive windows. The
analysis will be performed on the left and right hand separately. It will do
this for all the people in the xml file and all the filters, as no specific
this for all the people in the YAML file and all the filters, as no specific
ones were flagged.
The extra options are –write-nifti and –write-lower-level. Write nifti will
......@@ -152,7 +152,7 @@ Virtual Electrodes
:doc:`/userref/scripts/nafBFTS` replaces **ynicVirtualElectrodes**. It no longer needs
a '.ext' file in order to be run. So the first step in your analysis stream
could be to seed virtual electrodes. As arguments it takes an xml file, the
could be to seed virtual electrodes. As arguments it takes an YAML file, the
location of interest (comma separated list in nifti pixels). There are also -c,
-r and -w options in the same style as the original beamformer script. Extra
options include showing figures, applying pca, and also saving the figures out.
......@@ -161,7 +161,7 @@ and 'ALLMEGCOILS:rightHand:all:unfiltered_pca_ST.png'. The 3*time-points*epochs
array is saved in a /VE/filename.hdf' file and the reconstruction is always in
x,y,z. ::
nafBFTS /scratch/home/garreth/CodeTest.xml 51,93,185 -c rightHand -w all --show-figs --apply-pca
nafBFTS /scratch/home/garreth/CodeTest.yaml 51,93,185 -c rightHand -w all --show-figs --apply-pca
:doc:`/userref/scripts/nafTSPlot` can be used to plot and save figures from a '.hdf'
file created by :doc:`/userref/scripts/nafBFTS`.
......
......@@ -24,8 +24,6 @@ Channel Handling
.. automodule:: naf.meg.channels
:members:
.. autoclass:: naf.meg.btireaders.BTIChannelName
Epoch Definers
==============
......
......@@ -38,12 +38,3 @@ TODO: Make more generic and move out of YNiC module.
.. automodule:: naf.ynic.cluster
:members:
XML Parser
----------
This code is used for converting old-style YNiC XML analysis files and will
eventually be removed.
.. automodule:: naf.ynic.xmlparse
:members:
......@@ -35,7 +35,6 @@ Utilities
nafShowEpochs
nafStudyFindRunResults
nafTestFilterChain
nafXMLToYAML
nafYamlParse
Analysis Utilities
......
......@@ -7,7 +7,7 @@ nafBFCompMetric
Outline
--------
At the command line, you must specify an xml file and a grid spacing. You can
At the command line, you must specify an YAML file and a grid spacing. You can
then optionally specify as many runs, windows, conditions, filters etc as you
wish. Leaving a field blank i.e. filters, will ensure that all the comparison
is applied to all the filtered versions of the data. The key argument is -C,
......@@ -16,14 +16,14 @@ which tells the script what you want to compare. ::
nafBFCompMetric my/file.yaml 5 -w active -c conditionA -c conditionB -C conditions
This will perform an anlysis that compares conditionA with conditionB. It will
do this for all the people in the xml file and all the filters, as no specific
do this for all the people in the YAML file and all the filters, as no specific
ones were flagged.
The script will generate comparison metric files which are saved in the
participant results directory in METRICNAME/gridspacing/filename.hdf5. The
structure of the filename is to concatenate the coilSelector, condition, window
and filter of the two contrasting conditions into a colon separated filename.
Therefore you should not use colons in your xml file to describe windows,
Therefore you should not use colons in your YAML file to describe windows,
conditions, filters etc. ::
e.g. ALLMEGCOILS:conditionA:active:unfiltered:::::conditionB.hdf5
......
......@@ -10,7 +10,7 @@ Outline
This script will generate metric files which are saved in the participant results directory
in METRICNAME/gridspacing/filename.hdf5. The structure of the filename is to concatenate the coilSelector,
condition, window and filter into a colon separated filename. Therefore you should not use colons
in your xml file to describe windows, conditions, filters etc. ::
in your YAML file to describe windows, conditions, filters etc. ::
e.g. ALLMEGCOILS:leftHand:act:unfiltered.hdf5
......
......@@ -8,11 +8,11 @@ nafBFStats
Outline
-------
At the command line, you must specify an xml file and a grid spacing. You can then optionally specify as many runs, windows, conditions, filters etc as you wish. Leaving a field blank i.e. filters, will ensure that all the comparison is applied to all the filtered versions of the data. The key argument is -C, which tells the script what you want to compare. ::
At the command line, you must specify an YAML file and a grid spacing. You can then optionally specify as many runs, windows, conditions, filters etc as you wish. Leaving a field blank i.e. filters, will ensure that all the comparison is applied to all the filtered versions of the data. The key argument is -C, which tells the script what you want to compare. ::
nafBFStats my/file.yaml 5 -w active -w passive -c conditionA -c conditionB -C windows
This will perform an anlysis that compares the active and passive windows. The analysis will be performed on the left and right hand separately. It will do this for all the people in the xml file and all the filters, as no specific ones were flagged. ::
This will perform an anlysis that compares the active and passive windows. The analysis will be performed on the left and right hand separately. It will do this for all the people in the YAML file and all the filters, as no specific ones were flagged. ::
nafBFStats my/file.yaml 5 -w active -w passive -c conditionA -c conditionB -f filterA -C conditions
......
......@@ -10,9 +10,9 @@ Outline
This function will reconstruct the time series at a specified location in
an individual using the default YNiC beamformer implementation.
As arguments it takes an xml file, the location of interest (comma separated list in nifti pixels). There are also -c, -r and -w options in the same style as the original beamformer script. Extra options include showing figures, applying pca, and also saving the figures out. The figures are saved out as 'ALLMEGCOILS:rightHand:all:unfiltered_pca_TS.png' and 'ALLMEGCOILS:rightHand:all:unfiltered_pca_ST.png'. The 3*time-points*epochs array is saved in /filename.hdf' file and the reconstruction is always in x,y,z. ::
As arguments it takes an YAML file, the location of interest (comma separated list in nifti pixels). There are also -c, -r and -w options in the same style as the original beamformer script. Extra options include showing figures, applying pca, and also saving the figures out. The figures are saved out as 'ALLMEGCOILS:rightHand:all:unfiltered_pca_TS.png' and 'ALLMEGCOILS:rightHand:all:unfiltered_pca_ST.png'. The 3*time-points*epochs array is saved in /filename.hdf' file and the reconstruction is always in x,y,z. ::
nafBFTS /scratch/home/garreth/CodeTest.xml 51,93,185 -c rightHand -w all --show-figs --apply-pca
nafBFTS /scratch/home/garreth/CodeTest.yaml 51,93,185 -c rightHand -w all --show-figs --apply-pca
Usage
-----
......
......@@ -7,11 +7,11 @@ nafCombinations
Outline
-------
tool which allows the user to view the possible comparisons that are present within a specified xml file.
tool which allows the user to view the possible comparisons that are present within a specified YAML file.
As with a number of other scripts, the -c, -r, -w, -f flags can be used to restrict the output to specific
cominations of parameters. ::
nafCombinations /scratch/home/garreth/SaveParams.xml
nafCombinations /scratch/home/garreth/SaveParams.yaml
Returns:
......
......@@ -10,7 +10,7 @@ Outline
This script will save out the leadfields for each point in a grid at the resolution specific by ther user.
The leadfield is stored in a file called 'leadfield.hdf5' which can be found in the meg-run directory. Opening :doc:`nafLeadfield` and comparing it to :doc:`nafBFMetric` may give the user an idea of how the top level scripts work as their differences are very clear, yet the function they perform remain very similar. It is a good place to look when wanting to write out your own .hdf5 file.
Only one leadfield file can be save per MEG datafile, as the leadfields will be the same regardless of which conditions/windows are specified. The -p, -r and -s options are still valid though. The function does not incorporate any rejected channels from the xml file, and also uses the default chanset of ALLMEG channels. Therefore regardless of what the xml file contains, the output will always be gridpoints*248*3, as the function uses the default YNiC beamformer which is a vectorised spatial filter.
Only one leadfield file can be save per MEG datafile, as the leadfields will be the same regardless of which conditions/windows are specified. The -p, -r and -s options are still valid though. The function does not incorporate any rejected channels from the YAML file, and also uses the default chanset of ALLMEG channels. Therefore regardless of what the YAML file contains, the output will always be gridpoints*248*3, as the function uses the default YNiC beamformer which is a vectorised spatial filter.
Usage
......
#################################
nafXMLToYAML
#################################
:doc:`/gen/source_nafXMLToYAML`
Usage
-----
.. include:: ../../gen/usage_nafXMLToYAML.txt
:literal:
......@@ -2,7 +2,12 @@
from numpy import round
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
# Force the user of Qt5 backend in Matplotlib to avoid trying to load both Qt4
# and Qt5 by accident
from matplotlib import rcParams
rcParams['backend'] = 'Qt5Agg'
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
from matplotlib.cm import gray
......
#!/usr/bin/python
from PyQt4 import QtGui, QtCore
from PyQt5 import QtWidgets
from naf.gui.qt4.ui.dipoleResultsDialog_ui import Ui_dipoleResultsDialog
from naf.gui.qt.ui.dipoleResultsDialog_ui import Ui_dipoleResultsDialog
__all__ = []
class DipoleResults(QtGui.QDialog, Ui_dipoleResultsDialog):
class DipoleResults(QtWidgets.QDialog, Ui_dipoleResultsDialog):
def __init__(self, parent=None, fit=None, dat=None, config=None):
super(DipoleResults, self).__init__(parent)
self.setupUi(self)
......@@ -15,9 +15,9 @@ class DipoleResults(QtGui.QDialog, Ui_dipoleResultsDialog):
self.dat = dat
self.config = config
self.connect(self.closeButton, QtCore.SIGNAL("clicked()"), self.close)
self.connect(self.exportResultsButton, QtCore.SIGNAL("clicked()"), self.exportResults)
self.connect(self.spaceComboBox, QtCore.SIGNAL("currentIndexChanged(int)"), self.changeSpace)
self.closeButton.clicked.connect(self.close)
self.exportResultsButton.clicked.connect(self.exportResults)
self.spaceComboBox.currentIndexChanged.connect(self.changeSpace)
self.resTextEdit.setReadOnly(True)
self.update_space()
......@@ -26,7 +26,7 @@ class DipoleResults(QtGui.QDialog, Ui_dipoleResultsDialog):
self.show()
def exportResults(self):
QtGui.QMessageBox.critical(self,
QtWidgets.QMessageBox.critical(self,
"Warning",
"Exporting not yet implemented, please copy and paste.")
......
......@@ -5,10 +5,14 @@
from numpy import mod, arctan2, sin, cos, rad2deg, deg2rad, zeros, array, sqrt
from PyQt4 import QtGui
from PyQt5 import QtWidgets
# Force the user of Qt5 backend in Matplotlib to avoid trying to load both Qt4
# and Qt5 by accident
from matplotlib import rcParams
rcParams['backend'] = 'Qt5Agg'
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
from matplotlib.lines import Line2D
from matplotlib.widgets import Cursor
......@@ -32,8 +36,8 @@ class TimeSeriesCanvas(FigureCanvas):
self.mpl_connect('button_press_event', self.button_pressed)
self.setSizePolicy(QtGui.QSizePolicy.Expanding,
QtGui.QSizePolicy.Expanding)
self.setSizePolicy(QtWidgets.QSizePolicy.Expanding,
QtWidgets.QSizePolicy.Expanding)
self.updateGeometry()
......@@ -280,8 +284,8 @@ class ContourCanvas(FigureCanvas):
self.mpl_connect('pick_event', self.onpick1)
FigureCanvas.setSizePolicy(self,
QtGui.QSizePolicy.Expanding,
QtGui.QSizePolicy.Expanding)
QtWidgets.QSizePolicy.Expanding,
QtWidgets.QSizePolicy.Expanding)
FigureCanvas.updateGeometry(self)
self.selection = False
......
This diff is collapsed.
......@@ -4,19 +4,18 @@
# This file is part of the NeuroImaging Analysis Framework
# For copyright and redistribution details, please see the COPYING file
from PyQt4 import QtGui
from PyQt4.QtCore import SIGNAL
from PyQt5 import QtWidgets
import vtk
from vtk.qt4.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor
from QVTKRenderWindowInteractor import QVTKRenderWindowInteractor
from naf.maths.coords import get_merged_lines
from naf.meg.coords import COORD_INTERNAL_MM, COORD_ALIGNED_MM
from naf.meg.readers import OffReader
from naf.gui.vtkutils import ActorSpheresVTK, ActorLinesVTK, ActorVertTriVTK, ActorStructuredPointsVTK
from naf.gui.qt4.ui.coregOptions_ui import Ui_coregOptions
from naf.gui.qt4.ui.sfmOptions_ui import Ui_sfmOptions
from naf.gui.qt.ui.coregOptions_ui import Ui_coregOptions
from naf.gui.qt.ui.sfmOptions_ui import Ui_sfmOptions
class SpheresForwardModelVTK(object):
def __init__(self, transforms, forwardmodel, update_callback=None):
......@@ -145,13 +144,14 @@ class CoregVTKWindow(QVTKRenderWindowInteractor):
self.coreg = CoregVTK(transforms, update_callback=self.update_vtk)
self.sfm = SpheresForwardModelVTK(transforms, forwardmodel, update_callback=self.update_vtk)
# Note that this will fail with Qt < 5.6
style = vtk.vtkInteractorStyleTrackballCamera()
self.SetInteractorStyle(style)
self.coreg.add_all_actors(self.vrenderer)
self.sfm.add_all_actors(self.vrenderer)
class CoregOptions(QtGui.QGroupBox, Ui_coregOptions):
class CoregOptions(QtWidgets.QGroupBox, Ui_coregOptions):
def __init__(self, parent=None):
super(CoregOptions, self).__init__(parent)
......@@ -169,11 +169,11 @@ class CoregOptions(QtGui.QGroupBox, Ui_coregOptions):
self.hsdigToggle.setChecked( self.vtk.coreg.dig_pts.global_visible )
self.hsidxToggle.setChecked( self.vtk.coreg.dig_pts.global_visible )
self.connect( self.scalpToggle, SIGNAL("toggled(bool)"), self.vtk.coreg.scalp.SetVisibility )
self.connect( self.scalpSlider, SIGNAL("valueChanged(int)"), self.scalp_trans )
self.connect( self.hsdigToggle, SIGNAL("toggled(bool)"), self.vtk.coreg.dig_pts.SetVisibility )
self.connect( self.hsidxToggle, SIGNAL("toggled(bool)"), self.vtk.coreg.idx_pts.SetVisibility )
self.connect( self, SIGNAL("toggled(bool)"), self.coreg_toggle )
self.scalpToggle.toggled.connect(self.vtk.coreg.scalp.SetVisibility)
self.scalpSlider.valueChanged.connect(self.scalp_trans)
self.hsdigToggle.toggled.connect(self.vtk.coreg.dig_pts.SetVisibility)
self.hsidxToggle.toggled.connect(self.vtk.coreg.idx_pts.SetVisibility)
self.toggled.connect(self.coreg_toggle)
def scalp_trans(self, value):
value = value / 100.0
......@@ -186,7 +186,7 @@ class CoregOptions(QtGui.QGroupBox, Ui_coregOptions):
self.vtk.coreg.scalp.SetVisibility(value & self.scalpToggle.isChecked())
self.vtk.update()
class SfmOptions(QtGui.QGroupBox, Ui_sfmOptions):
class SfmOptions(QtWidgets.QGroupBox, Ui_sfmOptions):
def __init__(self, parent=None):
super(SfmOptions, self).__init__(parent)
......@@ -208,12 +208,12 @@ class SfmOptions(QtGui.QGroupBox, Ui_sfmOptions):
self.set_current_active(1)
self.connect( self.skullToggle, SIGNAL("toggled(bool)"), self.vtk.sfm.inskull_surface.SetVisibility )
self.connect( self.skullSlider, SIGNAL("sliderMoved(int)"), self.skull_trans )
self.connect( self.sphereToggle, SIGNAL("toggled(bool)"), self.vtk.sfm.spheres.SetVisibility )
self.connect( self.chansToggle, SIGNAL("toggled(bool)"), self.vtk.sfm.coils.SetVisibility )
self.connect( self.sphereSpinbox, SIGNAL("valueChanged(int)"), self.set_current_active )
self.connect( self, SIGNAL("toggled(bool)"), self.fm_toggle )
self.skullToggle.toggled.connect(self.vtk.sfm.inskull_surface.SetVisibility)
self.skullSlider.sliderMoved.connect(self.skull_trans)
self.sphereToggle.toggled.connect(self.vtk.sfm.spheres.SetVisibility)
self.chansToggle.toggled.connect(self.vtk.sfm.coils.SetVisibility)
self.sphereSpinbox.valueChanged.connect(self.set_current_active)
self.toggled.connect(self.fm_toggle)
def fm_toggle(self, value):
self.vtk.sfm.inskull_surface.SetVisibility(value & self.skullToggle.isChecked())
......
......@@ -3,13 +3,13 @@
# This file is part of the NeuroImaging Analysis Framework
# For copyright and redistribution details, please see the COPYING file
from PyQt4 import QtCore
from PyQt5 import QtCore
from subprocess import Popen, PIPE
from naf.gui.qt4.timedthread import TimedThread
from naf.gui.qt4.tablemodel import ListModel
from naf.gui.qt4.jobhandlers import *
from naf.gui.qt.timedthread import TimedThread
from naf.gui.qt.tablemodel import ListModel
from naf.gui.qt.jobhandlers import *
__all__ = []
......@@ -79,10 +79,10 @@ class ExecutionModel(ListModel):
self.update_thread = ExecutionThread(model=self)
self.connect(self.update_thread, QtCore.SIGNAL("lastUpdated(QDateTime, bool)"), self.last_updated)
self.update_thread.lastUpdated.connect(self.last_updated)
def last_updated(self, datetime, changed):
self.emit(QtCore.SIGNAL("lastUpdated(QDateTime, bool)"), datetime, changed)
self.lastUpdated.emit(datetime, changed)
def clear_ended_jobs(self):
# Take a copy as we're going to stomp all over our jobs list
......@@ -101,9 +101,9 @@ class ExecutionModel(ListModel):
jidx = len(self.items) - 1
idx = self.index(jidx, 0)
idx_end = self.index(jidx, self.columnCount()-1)
self.emit(QtCore.SIGNAL("countChanged()"))
self.emit(QtCore.SIGNAL("dataChanged(QModelIndex,QModelIndex)"), idx, idx_end)
self.emit(QtCore.SIGNAL("modelChanged()"))
self.countChanged.emit()
self.dataChanged.emit(idx, idx_end)
self.modelChanged.emit()
finally:
self.lock.unlock()
......@@ -119,7 +119,7 @@ class ExecutionModel(ListModel):
idx = self.index(jidx, 0)
idx_end = self.index(jidx, self.columnCount())
self.emit(QtCore.SIGNAL("dataChanged(QModelIndex,QModelIndex)"), idx, idx_end)
self.dataChanged.emit(idx, idx_end)
retjob = j
break
......@@ -142,7 +142,7 @@ class ExecutionModel(ListModel):
idx = self.index(jidx, 0)
idx_end = self.index(jidx, self.columnCount())
self.emit(QtCore.SIGNAL("dataChanged(QModelIndex,QModelIndex)"), idx, idx_end)
self.dataChanged.emit(idx, idx_end)
except ValueError:
pass
......
......@@ -7,7 +7,7 @@ from os import stat, unlink
from os.path import join, abspath, dirname
from PyQt4 import QtCore
from PyQt5 import QtCore
from naf.meg.coords import COORD_MEG, COORD_INTERNAL_MM, COORD_ALIGNED_MM, COORD_NIFTI_PIX, COORD_NIFTI_MM
......
......@@ -3,13 +3,18 @@
# This file is part of the NeuroImaging Analysis Framework
# For copyright and redistribution details, please see the COPYING file
from PyQt4 import QtCore
from PyQt5 import QtCore
from naf.gui.qt4.timedthread import TimedThread
from naf.gui.qt.timedthread import TimedThread
__all__ = []
class ListModel(QtCore.QAbstractTableModel):
countChanged = QtCore.pyqtSignal()
lastUpdated = QtCore.pyqtSignal(QtCore.QDateTime, int)
forceRefresh = QtCore.pyqtSignal()
modelChanged = QtCore.pyqtSignal()
def __init__(self):
super(ListModel, self).__init__()
......@@ -51,7 +56,7 @@ class ListModel(QtCore.QAbstractTableModel):
self.lock.unlock()
self.emit(QtCore.SIGNAL("countChanged()"))
self.countChanged.emit()
def remove_item(self, item):
self.lock.lockForWrite()
......@@ -69,7 +74,7 @@ class ListModel(QtCore.QAbstractTableModel):
self.lock.unlock()
self.emit(QtCore.SIGNAL("countChanged()"))
self.countChanged.emit()
def clear(self):
self.lock.lockForWrite()
......@@ -80,7 +85,7 @@ class ListModel(QtCore.QAbstractTableModel):
self.lock.unlock()
self.emit(QtCore.SIGNAL("countChanged()"))
self.countChanged.emit()
def rowCount(self, index=QtCore.QModelIndex()):
return len(self.items)
......@@ -153,14 +158,14 @@ class ListModelWithThread(ListModel):
# Create a thread
self.update_thread = ListModelThread(model=self)
self.connect(self.update_thread, QtCore.SIGNAL("finished()"), self.update_thread, QtCore.SLOT("deleteLater()"))
self.connect(self.update_thread, QtCore.SIGNAL("lastUpdated(QDateTime, bool)"), self.last_updated)
self.update_thread.finished.connect(self.update_thread.deleteLater)
self.update_thread.lastUpdated.connect(self.last_updated)
# Note that we don't start the thread, subclasses must do that themselves
# once all initialisation is taken care of
def refresh(self):
self.emit(QtCore.SIGNAL("forceRefresh()"))
self.forceRefresh.emit()
def timer_update(self):
"""Function called by thread to perform updates"""
......@@ -168,7 +173,7 @@ class ListModelWithThread(ListModel):
def last_updated(self, datetime, changed):
"""Function called by thread when an updated has been performed"""
self.emit(QtCore.SIGNAL("lastUpdated(QDateTime, bool)"), datetime, changed)
self.lastUpdated.emit(datetime, changed)
__all__.append('ListModelWithThread')
......@@ -184,7 +189,7 @@ class RemoteJobListModel(ListModelWithThread):
def timer_update(self):
from naf.utils.sgeutils import qstat_jobs
from naf.gui.qt4.jobhandlers import JOB_STATUS_QUEUED, JOB_STATUS_RUNNING, JOB_STATUS_UNKNOWN, JOB_STATUS_ENDED
from naf.gui.qt.jobhandlers import JOB_STATUS_QUEUED, JOB_STATUS_RUNNING, JOB_STATUS_UNKNOWN, JOB_STATUS_ENDED
self.lock.lockForWrite()
......@@ -219,25 +224,25 @@ class RemoteJobListModel(ListModelWithThread):
if j.jobstatus != JOB_STATUS_QUEUED:
j.jobstatus = JOB_STATUS_QUEUED
if idx:
self.emit(QtCore.SIGNAL("dataChanged(QModelIndex,QModelIndex)"), idx, idx)
self.dataChanged.emit(idx, idx)
ret = True
elif ji.state == 'running':
if j.jobstatus != JOB_STATUS_RUNNING:
j.jobstatus = JOB_STATUS_RUNNING
if idx:
self.emit(QtCore.SIGNAL("dataChanged(QModelIndex,QModelIndex)"), idx, idx)
self.dataChanged.emit(idx, idx)
ret = True
else:
if j.jobstatus != JOB_STATUS_UNKNOWN:
j.jobstatus = JOB_STATUS_UNKNOWN
if idx:
self.emit(QtCore.SIGNAL("dataChanged(QModelIndex,QModelIndex)"), idx, idx)
self.dataChanged.emit(idx, idx)
ret = True
else:
if j.jobstatus != JOB_STATUS_ENDED:
j.jobstatus = JOB_STATUS_ENDED
if idx:
self.emit(QtCore.SIGNAL("dataChanged(QModelIndex,QModelIndex)"), idx, idx)
self.dataChanged.emit(idx, idx)
ret = True
finally:
......@@ -252,7 +257,7 @@ class StudyCoregRunModel(ListModelWithThread):
"""Specialised model for watching the state of coregistration files"""
def __init__(self, study=None):
from naf.gui.qt4.jobhandlers import COREG_RUN_ID, COREG_RUN_NAME, COREG_RUN_INDIVIDUAL, COREG_RUN_MNI, COREG_COL_NAMES
from naf.gui.qt.jobhandlers import COREG_RUN_ID, COREG_RUN_NAME, COREG_RUN_INDIVIDUAL, COREG_RUN_MNI, COREG_COL_NAMES
ListModelWithThread.__init__(self)
......@@ -270,14 +275,14 @@ class StudyCoregRunModel(ListModelWithThread):
idx = self.index(ridx, 0)
idx_end = self.index(ridx, self.columnCount()-1)
run.erase_coreg()
self.emit(QtCore.SIGNAL("dataChanged(QModelIndex,QModelIndex)"), idx, idx_end)
self.dataChanged.emit(idx, idx_end)
break
finally:
self.lock.unlock()
def timer_update(self):
from naf.gui.qt4.jobhandlers import COREG_RUN_INDIVIDUAL, COREG_RUN_MNI
from naf.gui.qt.jobhandlers import COREG_RUN_INDIVIDUAL, COREG_RUN_MNI
self.lock.lockForWrite()
if len(self.items) < 1:
......@@ -300,7 +305,7 @@ class StudyCoregRunModel(ListModelWithThread):
idxend = self.index(ridx, colend)
ret = True
self.emit(QtCore.SIGNAL("dataChanged(QModelIndex,QModelIndex)"), idxstart, idxend)
self.dataChanged.emit(idxstart, idxend)
finally:
self.lock.unlock()
......
......@@ -3,11 +3,11 @@
# This file is part of the NeuroImaging Analysis Framework
# For copyright and redistribution details, please see the COPYING file
from PyQt4 import QtCore, QtGui
from PyQt5 import QtCore, QtGui, QtWidgets
from naf.gui.qt4.timedthread import TimedThread
from naf.gui.qt.timedthread import TimedThread
from naf.gui.qt4.ui.tailFile_ui import Ui_TailFile
from naf.gui.qt.ui.tailFile_ui import Ui_TailFile
class TailFileThread(TimedThread):
def __init__(self, parent=None, model=None):
......@@ -65,7 +65,7 @@ class TailFileThread(TimedThread):
self.datamutex.unlock()
class TailFileDialog(QtGui.QDialog, Ui_TailFile):
class TailFileDialog(QtWidgets.QDialog, Ui_TailFile):
def __init__(self, parent=None, controller=None, filename=None):
super(TailFileDialog, self).__init__(parent)
......@@ -83,14 +83,14 @@ class TailFileDialog(QtGui.QDialog, Ui_TailFile):
font.setPointSize(8)
self.textBrowser.setCurrentFont( font )
self.connect(self.refreshFileButton, QtCore.SIGNAL("clicked()"), self.force_refresh)
self.connect(self.thread, QtCore.SIGNAL("lastUpdated(QDateTime, bool)"), self.update_tailtime)
self.connect(self.closeTabButton, QtCore.SIGNAL("clicked()"), self.close)
self.refreshFileButton.clicked.connect(self.force_refresh)
self.thread.lastUpdated.connect(self.update_tailtime)
self.closeTabButton.clicked.connect(self.close)
self.thread.start()
def force_refresh(self):
self.emit(QtCore.SIGNAL("forceRefresh()"))
self.forceRefresh.emit()
def update_tailtime(self, datetime, changed):
self.lastUpdatedLabel.setText("File last refreshed: %s" % datetime.toString("yyyy-MM-dd hh:mm:ss"))
......
......@@ -3,9 +3,12 @@
# This file is part of the NeuroImaging Analysis Framework
# For copyright and redistribution details, please see the COPYING file
from PyQt4 import QtCore
from PyQt5 import QtCore
class TimedThread(QtCore.QThread):
lastUpdated = QtCore.pyqtSignal(QtCore.QDateTime, int)
def __init__(self, parent=None, model=None):
super(TimedThread, self).__init__(parent)
......@@ -38,11 +41,8 @@ class TimedThread(QtCore.QThread):
self.datamutex.lock()
self.timer = QtCore.QTimer()
self.connect( self.model, QtCore.SIGNAL("forceRefresh()"), run_refresh )
self.connect( self.model, QtCore.SIGNAL("go()"), run_go )
self.connect( self.model, QtCore.SIGNAL("stop()"), run_stop )
self.connect( self.model, QtCore.SIGNAL("kill()"), run_kill )
self.connect( self.timer, QtCore.SIGNAL("timeout()"), run_update )
self.model.forceRefresh.connect(run_refresh)
self.timer.timeout.connect(run_update)
self.timer.start(50)
finally:
......@@ -63,7 +63,7 @@ class TimedThread(QtCore.QThread):
try:
now = QtCore.QDateTime.currentDateTime()
changed = self.perform_update()
self.emit(QtCore.SIGNAL("lastUpdated(QDateTime, bool)"), now, changed)
self.lastUpdated.emit(now, changed)
finally:
try:
self.datamutex.lock()
......
......@@ -95,19 +95,19 @@
<customwidget>
<class>CoregVTKWindow</class>
<extends>QWidget</extends>
<header>naf/gui/qt4/coreg.h</header>
<header>naf.gui.qt/coreg.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>CoregOptions</class>
<extends>QGroupBox</extends>
<header>naf/gui/qt4/coreg.h</header>
<header>naf.gui.qt/coreg.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>SfmOptions</class>
<extends>QGroupBox</extends>
<header>naf/gui/qt4/coreg.h</header>
<header>naf.gui.qt/coreg.h</header>
<container>1</container>
</customwidget>
</customwidgets>
......
......@@ -108,7 +108,6 @@
</property>
<addaction name="action_New"/>
<addaction name="action_Open"/>
<addaction name="action_Import_XML"/>
<addaction name="action_Save"/>
<addaction name="actionSave_As"/>
<addaction name="separator"/>
......@@ -142,47 +141,42 @@
<string>&amp;New</string>
</property>
</action>
<action name="action_Import_XML">
<property name="text">
<string>&amp;Import XML</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>
<class>StudyParams</class>
<extends>QGroupBox</extends>
<header>naf/gui/qt4/studydefiner.h</header>
<header>naf.gui.qt/studydefiner.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>DataSets</class>
<extends>QGroupBox</extends>
<header>naf/gui/qt4/studydefiner.h</header>
<header>naf.gui.qt/studydefiner.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>ConditionParams</class>
<extends>QGroupBox</extends>
<header>naf/gui/qt4/studydefiner.h</header>
<header>naf.gui.qt/studydefiner.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>WindowParams</class>
<extends>QGroupBox</extends>
<header>naf/gui/qt4/studydefiner.h</header>
<header>naf.gui.qt/studydefiner.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>FCParams</class>
<extends>QGroupBox</extends>
<header>naf/gui/qt4/studydefiner.h</header>
<header>naf.gui.qt/studydefiner.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>ChannelSetParams</class>
<extends>QGroupBox</extends>
<header>naf/gui/qt4/studydefiner.h</header>
<header>naf.gui.qt/studydefiner.h</header>
<container>1</container>
</customwidget>
</customwidgets>
......
......@@ -31,7 +31,6 @@ class ActorStructuredPointsVTK(vtk.vtkActor):
self.v.SetDimensions(n.extent[0], n.extent[1], n.extent[2])
self.v.SetSpacing(numpy.diag(n.qform)[0:3])
self.v.SetOrigin(n.extent[0]*n.voxdim[0], 0, 0)
self.v.Update()
maxval = 255
else:
......@@ -43,17 +42,17 @@ class ActorStructuredPointsVTK(vtk.vtkActor):
maxval = 32767
self.extractor = vtk.vtkContourFilter()
self.extractor.SetInput(self.v)
self.extractor.SetInputData(self.v)
self.extractor.SetValue(0, maxval)
self.extractor.ComputeGradientsOn()
self.extractor.Update()
self.normals = vtk.vtkPolyDataNormals()
self.normals.SetInput(self.extractor.GetOutput())
self.normals.SetInputConnection(self.extractor.GetOutputPort())
self.normals.SetFeatureAngle(60.0)
self.mapper = vtk.vtkPolyDataMapper()
self.mapper.SetInput(self.normals.GetOutput())
self.mapper.SetInputConnection(self.normals.GetOutputPort())