From c06f96134bfe7d58f21e564d3093004cc4dfd170 Mon Sep 17 00:00:00 2001 From: Thorsten Kranz Date: Thu, 19 Apr 2012 17:51:06 +0200 Subject: [PATCH 01/22] Added debian branch with configuration for debian package. Taken from nibabel. Thanks, Yarik --- debian/changelog | 25 ++++++++++++ debian/compat | 1 + debian/control | 43 ++++++++++++++++++++ debian/copyright | 65 +++++++++++++++++++++++++++++++ debian/gbp.conf | 8 ++++ debian/patches/no_doc_sources | 16 ++++++++ debian/patches/series | 1 + debian/pycompat | 1 + debian/python-pylocator-doc.docs | 1 + debian/python-pylocator-doc.links | 1 + debian/python-pylocator.install | 1 + debian/rules | 41 +++++++++++++++++++ debian/source/format | 1 + debian/source/options | 3 ++ debian/watch | 4 ++ 15 files changed, 212 insertions(+) create mode 100644 debian/changelog create mode 100644 debian/compat create mode 100644 debian/control create mode 100644 debian/copyright create mode 100644 debian/gbp.conf create mode 100644 debian/patches/no_doc_sources create mode 100644 debian/patches/series create mode 100644 debian/pycompat create mode 100644 debian/python-pylocator-doc.docs create mode 100644 debian/python-pylocator-doc.links create mode 100644 debian/python-pylocator.install create mode 100755 debian/rules create mode 100644 debian/source/format create mode 100644 debian/source/options create mode 100644 debian/watch diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..38e1c70 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,25 @@ +pylocator (1.1.0-1) unstable; urgency=low + + * New upstream release: better gifti and trackvis support, bugfixes. + + -- Yaroslav Halchenko Wed, 04 May 2011 16:44:55 -0400 + +pylocator (1.0.2-1) unstable; urgency=low + + * Fresh bugfix upstream release + * debian/copyright: + - changes to confirm to DEP5 rev 174 + - added myself + - updated years + * debian/control: + - boosted policy compliance to 3.9.2 (no changes) + - purged DM-Upload-Allowed (no need any more) + - slight tune up of the long description + + -- Yaroslav Halchenko Thu, 28 Apr 2011 10:27:22 -0400 + +pylocator (1.0.0-1) unstable; urgency=low + + * Initial release (Closes: #600275). + + -- Michael Hanke Fri, 15 Oct 2010 08:20:14 -0400 diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..7f8f011 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +7 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..96c4dfb --- /dev/null +++ b/debian/control @@ -0,0 +1,43 @@ +Source: pylocator +Section: python +Priority: extra +Maintainer: Thorsten Kranz +Uploaders: Thorsten Kranz +Build-Depends: debhelper (>= 7.2.18), python-all (>= 2.5), python-support (>= 0.6), python-numpy (>= 1.2), python-nibabel, python-vtk, python-gtk2, python-gtkglext1 +Standards-Version: 3.9.2 +Homepage: http://pylocator.thorstenkranz.de +Vcs-Browser: http://github.com/nipy/PyLocator +Vcs-Git: git://github.com/nipy/PyLocator.git +XS-Python-Version: >= 2.5 + +Package: python-pylocator +Architecture: all +Depends: ${misc:Depends}, ${python:Depends}, python-numpy, python-scipy, python-nibabel, python-vtk, python-gtk2, python-gtkglext1 +Recommends: python-dicom +Suggests: python-pylocator-doc +Provides: ${python:Provides} +XB-Python-Version: ${python:Versions} +Description: Localization of EEG-electrodes from MRI-volumes + + PyLocator is a little program for localizing EEG electrodes from MR-images. It uses VTK to show a neat GUI for marking electrode locations in 3d-space. It is based on previous work by John D. Hunter and Michael Castell as part of pbrain, now maintained by Eli Albert. PyLocator works as a stand-alone program without any dependencies from pbrain. + + This package provides the documentation in HTML format. + NiBabel provides read and write access to some common medical and + neuroimaging file formats, including: ANALYZE (plain, SPM99, SPM2), GIFTI, + NIfTI1, MINC, as well as PAR/REC. The various image format classes give full + or selective access to header (meta) information and access to the image data + is made available via NumPy arrays. NiBabel is the successor of PyNIfTI. + . + This package also provides a commandline tool for conversion of PAR/REC to + NIfTI images. + +Package: python-pylocator-doc +Section: doc +Architecture: all +Depends: ${misc:Depends}, libjs-jquery +Description: documentation for PyLocator + Localization of EEG-electrodes from MRI-volumes + + PyLocator is a little program for localizing EEG electrodes from MR-images. It uses VTK to show a neat GUI for marking electrode locations in 3d-space. It is based on previous work by John D. Hunter and Michael Castell as part of pbrain, now maintained by Eli Albert. PyLocator works as a stand-alone program without any dependencies from pbrain. + + This package provides the documentation in HTML format. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..ce49314 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,65 @@ +Format-Specification: http://svn.debian.org/wsvn/dep/web/deps/dep5.mdwn?op=file&rev=174 +Upstream-Name: pylocator +Upstream-Contact: thorstenkranz@gmail.com +Source: http://github.com/nipy/PyLocator + + +Files: * +Copyright 2011-2012, Thorsten Kranz. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are +permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of + conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list + of conditions and the following disclaimer in the documentation and/or other materials + provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THORSTEN KRANZ ''AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THORSTEN KRANZ OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those of the +authors and should not be interpreted as representing official policies, either expressed +or implied, of Thorsten Kranz. + +Files: doc/sphinxext/autosummary/* +Copyright: 2007-2009, Stefan van der Walt and Sphinx team +License: BSD + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + . + a. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + c. Neither the name of the Enthought nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + . + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + DAMAGE. + + +Files: debian/* +Copyright: 2006-2010, Michael Hanke + 2011, Yaroslav Halchenko +License: Expat diff --git a/debian/gbp.conf b/debian/gbp.conf new file mode 100644 index 0000000..92efb7d --- /dev/null +++ b/debian/gbp.conf @@ -0,0 +1,8 @@ +[DEFAULT] +# the default branch for upstream sources: +upstream-branch = master +# the default branch for the debian patch: +debian-branch = debian +# the default tag formats used: +upstream-tag = %(version)s +debian-tag = debian/%(version)s diff --git a/debian/patches/no_doc_sources b/debian/patches/no_doc_sources new file mode 100644 index 0000000..5d2e473 --- /dev/null +++ b/debian/patches/no_doc_sources @@ -0,0 +1,16 @@ +Description: Do not put links to source documention source in HTML files + Documentation source files are not shipped in the binary package, because + the are not very useful and occupy space, hence these links would be broken. +Forwarded: not-needed +Author: Michael Hanke +--- a/doc/source/conf.py ++++ b/doc/source/conf.py +@@ -201,7 +201,7 @@ + #html_split_index = False + + # If true, links to the reST sources are added to the pages. +-html_show_sourcelink = True ++html_show_sourcelink = False + + # If true, an OpenSearch description file will be output, and all pages will + # contain a tag referring to it. The value of this option must be the diff --git a/debian/patches/series b/debian/patches/series new file mode 100644 index 0000000..4c93208 --- /dev/null +++ b/debian/patches/series @@ -0,0 +1 @@ +no_doc_sources diff --git a/debian/pycompat b/debian/pycompat new file mode 100644 index 0000000..0cfbf08 --- /dev/null +++ b/debian/pycompat @@ -0,0 +1 @@ +2 diff --git a/debian/python-pylocator-doc.docs b/debian/python-pylocator-doc.docs new file mode 100644 index 0000000..6d28621 --- /dev/null +++ b/debian/python-pylocator-doc.docs @@ -0,0 +1 @@ +build/html diff --git a/debian/python-pylocator-doc.links b/debian/python-pylocator-doc.links new file mode 100644 index 0000000..5912988 --- /dev/null +++ b/debian/python-pylocator-doc.links @@ -0,0 +1 @@ +usr/share/javascript/jquery/jquery.js usr/share/doc/python-pylocator-doc/html/_static/jquery.js diff --git a/debian/python-pylocator.install b/debian/python-pylocator.install new file mode 100644 index 0000000..326a444 --- /dev/null +++ b/debian/python-pylocator.install @@ -0,0 +1 @@ +debian/tmp/usr/* usr/ diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..e930b26 --- /dev/null +++ b/debian/rules @@ -0,0 +1,41 @@ +#!/usr/bin/make -f +# -*- mode: makefile; coding: utf-8 -*- + +# one ring to rule them all ... +%: +# need to enforce distutils, since we also have a makefile + dh $@ --buildsystem=python_distutils --builddirectory=build + +override_dh_auto_build: + dh_auto_build + # and docs + $(MAKE) htmldoc + # but remove jquery copy (later on link to Debian's version) + -rm build/html/_static/jquery.js + # objects inventory is of no use for the package + -rm build/html/objects.inv + # also doc source files only consume space + -rm -r build/html/_sources + +# enable when we believe that the tests should pass +override_dh_auto_test: +ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS))) + for buildver in $(shell pyversions -vr); do \ + echo "I: Running NiBabel unittests using python$$buildver"; \ + $(MAKE) unittest PYTHON=python$$buildver || exit 1 ;\ + done +endif + +## immediately useable documentation +## and exemplar data (they are small excerpts anyway) +override_dh_compress: + dh_compress -X.py -X.html -X.css -X.jpg -X.txt -X.js -X.json -X.rtc -X.par -X.bin + +override_dh_installman: + PYTHONPATH=build/lib:$(PYTHONPATH) help2man -N \ + -n 'convert PARREC image to NIfTI' bin/parrec2nii > build/parrec2nii.1 + dh_installman build/parrec2nii.1 + +override_dh_clean: + $(MAKE) clean + dh_clean diff --git a/debian/source/format b/debian/source/format new file mode 100644 index 0000000..163aaf8 --- /dev/null +++ b/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/debian/source/options b/debian/source/options new file mode 100644 index 0000000..9874f1d --- /dev/null +++ b/debian/source/options @@ -0,0 +1,3 @@ +# ignore changes to the commit info file, since it will always have the +# shasum of the release tag and the repository version does not. +# extend-diff-ignore = nibabel/COMMIT_INFO.txt diff --git a/debian/watch b/debian/watch new file mode 100644 index 0000000..69185e7 --- /dev/null +++ b/debian/watch @@ -0,0 +1,4 @@ +# Compulsory line, this is a version 3 file +version=3 +opts="filenamemangle=s/.*\/(.*)/pylocator-$1\.tar\.gz/" \ + http://github.com/nipy/pylocator/downloads .*tarball/([\d\.a-z]+) From 473ebcfdd35d05f31f9a78fc52f037ce829c51f8 Mon Sep 17 00:00:00 2001 From: Thorsten Kranz Date: Thu, 19 Apr 2012 17:59:03 +0200 Subject: [PATCH 02/22] Minor changes --- debian/rules | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/debian/rules b/debian/rules index e930b26..2131fb6 100755 --- a/debian/rules +++ b/debian/rules @@ -11,21 +11,12 @@ override_dh_auto_build: # and docs $(MAKE) htmldoc # but remove jquery copy (later on link to Debian's version) - -rm build/html/_static/jquery.js + -rm doc/build/html/_static/jquery.js # objects inventory is of no use for the package - -rm build/html/objects.inv + -rm doc/build/html/objects.inv # also doc source files only consume space -rm -r build/html/_sources -# enable when we believe that the tests should pass -override_dh_auto_test: -ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS))) - for buildver in $(shell pyversions -vr); do \ - echo "I: Running NiBabel unittests using python$$buildver"; \ - $(MAKE) unittest PYTHON=python$$buildver || exit 1 ;\ - done -endif - ## immediately useable documentation ## and exemplar data (they are small excerpts anyway) override_dh_compress: From 31ccd30b08fec939ed7c1fb84844fba8eff59a80 Mon Sep 17 00:00:00 2001 From: Thorsten Kranz Date: Thu, 19 Apr 2012 17:51:06 +0200 Subject: [PATCH 03/22] Added debian branch with configuration for debian package. Taken from nibabel. Thanks, Yarik --- debian/rules | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/rules b/debian/rules index 2131fb6..7895f0d 100755 --- a/debian/rules +++ b/debian/rules @@ -11,9 +11,9 @@ override_dh_auto_build: # and docs $(MAKE) htmldoc # but remove jquery copy (later on link to Debian's version) - -rm doc/build/html/_static/jquery.js + -rm build/html/_static/jquery.js # objects inventory is of no use for the package - -rm doc/build/html/objects.inv + -rm build/html/objects.inv # also doc source files only consume space -rm -r build/html/_sources From 319dd96e0b73cfc2c450b59849aeefd005fc1aa3 Mon Sep 17 00:00:00 2001 From: Thorsten Kranz Date: Thu, 19 Apr 2012 17:59:03 +0200 Subject: [PATCH 04/22] Minor changes --- debian/rules | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/rules b/debian/rules index 7895f0d..2131fb6 100755 --- a/debian/rules +++ b/debian/rules @@ -11,9 +11,9 @@ override_dh_auto_build: # and docs $(MAKE) htmldoc # but remove jquery copy (later on link to Debian's version) - -rm build/html/_static/jquery.js + -rm doc/build/html/_static/jquery.js # objects inventory is of no use for the package - -rm build/html/objects.inv + -rm doc/build/html/objects.inv # also doc source files only consume space -rm -r build/html/_sources From 473fbc28f794f52790bf9406fc8d302b01bc0d3b Mon Sep 17 00:00:00 2001 From: Thorsten Kranz Date: Thu, 19 Apr 2012 23:16:47 +0200 Subject: [PATCH 05/22] making deb-build work; first shot --- debian/control | 27 +++++---------------------- debian/rules | 28 ++++++++++++++-------------- 2 files changed, 19 insertions(+), 36 deletions(-) diff --git a/debian/control b/debian/control index 96c4dfb..26d14e3 100644 --- a/debian/control +++ b/debian/control @@ -18,26 +18,9 @@ Suggests: python-pylocator-doc Provides: ${python:Provides} XB-Python-Version: ${python:Versions} Description: Localization of EEG-electrodes from MRI-volumes + PyLocator is a little program for localizing EEG electrodes from MR-images. + It uses VTK to show a neat GUI for marking electrode locations in 3d-space. + It is based on previous work by John D. Hunter and Michael Castell as part + of pbrain, now maintained by Eli Albert. + PyLocator works as a stand-alone program without any dependencies from pbrain. - PyLocator is a little program for localizing EEG electrodes from MR-images. It uses VTK to show a neat GUI for marking electrode locations in 3d-space. It is based on previous work by John D. Hunter and Michael Castell as part of pbrain, now maintained by Eli Albert. PyLocator works as a stand-alone program without any dependencies from pbrain. - - This package provides the documentation in HTML format. - NiBabel provides read and write access to some common medical and - neuroimaging file formats, including: ANALYZE (plain, SPM99, SPM2), GIFTI, - NIfTI1, MINC, as well as PAR/REC. The various image format classes give full - or selective access to header (meta) information and access to the image data - is made available via NumPy arrays. NiBabel is the successor of PyNIfTI. - . - This package also provides a commandline tool for conversion of PAR/REC to - NIfTI images. - -Package: python-pylocator-doc -Section: doc -Architecture: all -Depends: ${misc:Depends}, libjs-jquery -Description: documentation for PyLocator - Localization of EEG-electrodes from MRI-volumes - - PyLocator is a little program for localizing EEG electrodes from MR-images. It uses VTK to show a neat GUI for marking electrode locations in 3d-space. It is based on previous work by John D. Hunter and Michael Castell as part of pbrain, now maintained by Eli Albert. PyLocator works as a stand-alone program without any dependencies from pbrain. - - This package provides the documentation in HTML format. diff --git a/debian/rules b/debian/rules index 2131fb6..ec9c0f2 100755 --- a/debian/rules +++ b/debian/rules @@ -9,24 +9,24 @@ override_dh_auto_build: dh_auto_build # and docs - $(MAKE) htmldoc - # but remove jquery copy (later on link to Debian's version) - -rm doc/build/html/_static/jquery.js - # objects inventory is of no use for the package - -rm doc/build/html/objects.inv - # also doc source files only consume space - -rm -r build/html/_sources +# $(MAKE) htmldoc +# # but remove jquery copy (later on link to Debian's version) +# -rm doc/build/html/_static/jquery.js +# # objects inventory is of no use for the package +# -rm doc/build/html/objects.inv +# # also doc source files only consume space +# -rm -r build/html/_sources ## immediately useable documentation ## and exemplar data (they are small excerpts anyway) override_dh_compress: dh_compress -X.py -X.html -X.css -X.jpg -X.txt -X.js -X.json -X.rtc -X.par -X.bin -override_dh_installman: - PYTHONPATH=build/lib:$(PYTHONPATH) help2man -N \ - -n 'convert PARREC image to NIfTI' bin/parrec2nii > build/parrec2nii.1 - dh_installman build/parrec2nii.1 +#override_dh_installman: +# PYTHONPATH=build/lib:$(PYTHONPATH) help2man -N \ +# -n 'convert PARREC image to NIfTI' bin/parrec2nii > build/parrec2nii.1 +# dh_installman build/parrec2nii.1 -override_dh_clean: - $(MAKE) clean - dh_clean +#override_dh_clean: +# $(MAKE) clean +# dh_clean From 50791e485381195525eba4b5ad566d749f1bff0c Mon Sep 17 00:00:00 2001 From: Thorsten Kranz Date: Fri, 20 Apr 2012 07:10:53 +0200 Subject: [PATCH 06/22] Changes to make building .deb work - finally --- debian/changelog | 25 +++---------------------- debian/patches/no_doc_sources | 16 ---------------- debian/patches/series | 1 - debian/python-pylocator.install | 1 - 4 files changed, 3 insertions(+), 40 deletions(-) delete mode 100644 debian/patches/no_doc_sources delete mode 100644 debian/patches/series diff --git a/debian/changelog b/debian/changelog index 38e1c70..b15ca25 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,25 +1,6 @@ -pylocator (1.1.0-1) unstable; urgency=low +pylocator (1.0-1) unstable; urgency=low - * New upstream release: better gifti and trackvis support, bugfixes. + * First debian package for PyLocator - -- Yaroslav Halchenko Wed, 04 May 2011 16:44:55 -0400 + -- Thorsten Kranz Fri, 20 April 2012 15:00:00 +0100 -pylocator (1.0.2-1) unstable; urgency=low - - * Fresh bugfix upstream release - * debian/copyright: - - changes to confirm to DEP5 rev 174 - - added myself - - updated years - * debian/control: - - boosted policy compliance to 3.9.2 (no changes) - - purged DM-Upload-Allowed (no need any more) - - slight tune up of the long description - - -- Yaroslav Halchenko Thu, 28 Apr 2011 10:27:22 -0400 - -pylocator (1.0.0-1) unstable; urgency=low - - * Initial release (Closes: #600275). - - -- Michael Hanke Fri, 15 Oct 2010 08:20:14 -0400 diff --git a/debian/patches/no_doc_sources b/debian/patches/no_doc_sources deleted file mode 100644 index 5d2e473..0000000 --- a/debian/patches/no_doc_sources +++ /dev/null @@ -1,16 +0,0 @@ -Description: Do not put links to source documention source in HTML files - Documentation source files are not shipped in the binary package, because - the are not very useful and occupy space, hence these links would be broken. -Forwarded: not-needed -Author: Michael Hanke ---- a/doc/source/conf.py -+++ b/doc/source/conf.py -@@ -201,7 +201,7 @@ - #html_split_index = False - - # If true, links to the reST sources are added to the pages. --html_show_sourcelink = True -+html_show_sourcelink = False - - # If true, an OpenSearch description file will be output, and all pages will - # contain a tag referring to it. The value of this option must be the diff --git a/debian/patches/series b/debian/patches/series deleted file mode 100644 index 4c93208..0000000 --- a/debian/patches/series +++ /dev/null @@ -1 +0,0 @@ -no_doc_sources diff --git a/debian/python-pylocator.install b/debian/python-pylocator.install index 326a444..e69de29 100644 --- a/debian/python-pylocator.install +++ b/debian/python-pylocator.install @@ -1 +0,0 @@ -debian/tmp/usr/* usr/ From 2360deea7f1aa149c5c1b242623517efe5c9e7d2 Mon Sep 17 00:00:00 2001 From: Thorsten Kranz Date: Fri, 20 Apr 2012 07:18:50 +0200 Subject: [PATCH 07/22] Added .desktop file --- debian/python-pylocator.desktop | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 debian/python-pylocator.desktop diff --git a/debian/python-pylocator.desktop b/debian/python-pylocator.desktop new file mode 100644 index 0000000..50dae48 --- /dev/null +++ b/debian/python-pylocator.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Version=1.0b1 +Type=Application +Name=PyLocator +Comment=Marking electrode locations in MRI recordings +TryExec=pylocator +Exec=pylocator %F +Icon=pylocator +MimeType=image/x-foo; From bfd407aa2f936b80515358b30013f32513ca38f3 Mon Sep 17 00:00:00 2001 From: Thorsten Kranz Date: Fri, 20 Apr 2012 11:39:03 +0200 Subject: [PATCH 08/22] new build --- debian/changelog | 2 +- debian/source/format | 2 +- debian/watch | 4 ---- 3 files changed, 2 insertions(+), 6 deletions(-) delete mode 100644 debian/watch diff --git a/debian/changelog b/debian/changelog index b15ca25..98233f2 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -pylocator (1.0-1) unstable; urgency=low +pylocator (1.0b2) unstable; urgency=low * First debian package for PyLocator diff --git a/debian/source/format b/debian/source/format index 163aaf8..89ae9db 100644 --- a/debian/source/format +++ b/debian/source/format @@ -1 +1 @@ -3.0 (quilt) +3.0 (native) diff --git a/debian/watch b/debian/watch deleted file mode 100644 index 69185e7..0000000 --- a/debian/watch +++ /dev/null @@ -1,4 +0,0 @@ -# Compulsory line, this is a version 3 file -version=3 -opts="filenamemangle=s/.*\/(.*)/pylocator-$1\.tar\.gz/" \ - http://github.com/nipy/pylocator/downloads .*tarball/([\d\.a-z]+) From a622b832a89a8998f6664d1530209b7a2f81bd2c Mon Sep 17 00:00:00 2001 From: Thorsten Kranz Date: Fri, 20 Apr 2012 17:31:19 +0200 Subject: [PATCH 09/22] cleaned debian package build --- debian/changelog | 2 +- debian/control | 3 +-- debian/{python-pylocator.desktop => pylocator.desktop} | 0 debian/python-pylocator-doc.docs | 1 - debian/python-pylocator-doc.links | 1 - debian/python-pylocator.install | 0 6 files changed, 2 insertions(+), 5 deletions(-) rename debian/{python-pylocator.desktop => pylocator.desktop} (100%) delete mode 100644 debian/python-pylocator-doc.docs delete mode 100644 debian/python-pylocator-doc.links delete mode 100644 debian/python-pylocator.install diff --git a/debian/changelog b/debian/changelog index 98233f2..6c05d4b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -pylocator (1.0b2) unstable; urgency=low +pylocator (1.0b3) unstable; urgency=low * First debian package for PyLocator diff --git a/debian/control b/debian/control index 26d14e3..f8a59d1 100644 --- a/debian/control +++ b/debian/control @@ -10,11 +10,10 @@ Vcs-Browser: http://github.com/nipy/PyLocator Vcs-Git: git://github.com/nipy/PyLocator.git XS-Python-Version: >= 2.5 -Package: python-pylocator +Package: pylocator Architecture: all Depends: ${misc:Depends}, ${python:Depends}, python-numpy, python-scipy, python-nibabel, python-vtk, python-gtk2, python-gtkglext1 Recommends: python-dicom -Suggests: python-pylocator-doc Provides: ${python:Provides} XB-Python-Version: ${python:Versions} Description: Localization of EEG-electrodes from MRI-volumes diff --git a/debian/python-pylocator.desktop b/debian/pylocator.desktop similarity index 100% rename from debian/python-pylocator.desktop rename to debian/pylocator.desktop diff --git a/debian/python-pylocator-doc.docs b/debian/python-pylocator-doc.docs deleted file mode 100644 index 6d28621..0000000 --- a/debian/python-pylocator-doc.docs +++ /dev/null @@ -1 +0,0 @@ -build/html diff --git a/debian/python-pylocator-doc.links b/debian/python-pylocator-doc.links deleted file mode 100644 index 5912988..0000000 --- a/debian/python-pylocator-doc.links +++ /dev/null @@ -1 +0,0 @@ -usr/share/javascript/jquery/jquery.js usr/share/doc/python-pylocator-doc/html/_static/jquery.js diff --git a/debian/python-pylocator.install b/debian/python-pylocator.install deleted file mode 100644 index e69de29..0000000 From 2cdce78956c702e28eda66e9077fe95794d7c320 Mon Sep 17 00:00:00 2001 From: Thorsten Kranz Date: Sat, 21 Apr 2012 04:15:35 +0200 Subject: [PATCH 10/22] Added desktop file to pylocator.install --- debian/pylocator.install | 1 + 1 file changed, 1 insertion(+) create mode 100644 debian/pylocator.install diff --git a/debian/pylocator.install b/debian/pylocator.install new file mode 100644 index 0000000..ac9142e --- /dev/null +++ b/debian/pylocator.install @@ -0,0 +1 @@ +debian/pylocator.desktop usr/share/applications/ From bc36e6a7fcdf49456834c7f4c3b1251a53b9d23f Mon Sep 17 00:00:00 2001 From: Thorsten Kranz Date: Mon, 23 Apr 2012 00:54:09 +0200 Subject: [PATCH 11/22] Next try for desktop & icon installation --- debian/pylocator.desktop | 3 ++- debian/pylocator.install | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/debian/pylocator.desktop b/debian/pylocator.desktop index 50dae48..f37ca13 100644 --- a/debian/pylocator.desktop +++ b/debian/pylocator.desktop @@ -1,9 +1,10 @@ [Desktop Entry] Version=1.0b1 Type=Application +Categories=Science; Name=PyLocator Comment=Marking electrode locations in MRI recordings TryExec=pylocator Exec=pylocator %F Icon=pylocator -MimeType=image/x-foo; +MimeType=application/x-gzip; data/octet-stream diff --git a/debian/pylocator.install b/debian/pylocator.install index ac9142e..ed661e8 100644 --- a/debian/pylocator.install +++ b/debian/pylocator.install @@ -1 +1,2 @@ debian/pylocator.desktop usr/share/applications/ +pylocator/resources/pylocator.ico usr/share/icons/ From e15443da29dfbb135d933497c568f51e8ff2be02 Mon Sep 17 00:00:00 2001 From: Thorsten Kranz Date: Wed, 25 Apr 2012 23:07:45 +0200 Subject: [PATCH 12/22] Trying multithreading for rendering --- pylocator/events.py | 4 ++-- pylocator/marker_list.py | 2 ++ pylocator/render_window.py | 19 +++++++++++++++++++ pylocator/surf_renderer_props.py | 2 ++ 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/pylocator/events.py b/pylocator/events.py index bfe7744..eb97c75 100644 --- a/pylocator/events.py +++ b/pylocator/events.py @@ -172,9 +172,9 @@ def detach(self, observer): def notify(self, event, *args): for observer in self.observers.keys(): if shared.debug: - print "EventHandler.notify(", event, "): calling update_viewer for ", observer + print "EventHandler.notify(", event, "): calling enqueue_update for ", observer try: - observer.update_viewer(event, *args) + observer.enqueue_update(event, *args) except Exception, e: print "Error while updating observer", observer, type(e), e diff --git a/pylocator/marker_list.py b/pylocator/marker_list.py index bc8432f..151c097 100644 --- a/pylocator/marker_list.py +++ b/pylocator/marker_list.py @@ -131,6 +131,8 @@ def update_viewer(self, event, *args): marker = args[0] self.__set_marker_selected(marker,False) + enqueue_update = update_viewer + def cb_add(self,*args): parent_window = self.get_parent_window() #print parent_window diff --git a/pylocator/render_window.py b/pylocator/render_window.py index b9ba9f7..001c118 100644 --- a/pylocator/render_window.py +++ b/pylocator/render_window.py @@ -1,3 +1,5 @@ +from Queue import Queue, Empty +from threading import Thread import gtk import vtk from GtkGLExtVTKRenderWindowInteractor import GtkGLExtVTKRenderWindowInteractor @@ -17,6 +19,10 @@ def __init__(self,*args): GtkGLExtVTKRenderWindowInteractor.__init__(self,*args) self.screenshot_button_label = "_render window_" self.roi_actors = {} + self.event_queue = Queue(10) + self.stop_rendering = False + self.updating_thread = Thread(target=self.start_event_loop) + self.updating_thread.start() EventHandler().attach(self) self.interactButtons = (1,2,3) @@ -131,6 +137,9 @@ def _get_roi_actor(self, uuid): return return self.roi_actors[uuid] + def enqueue_update(self, event, *args): + self.event_queue.put((event, args), timeout=10) + def update_viewer(self, event, *args): if event=='render off': self.renderOn = 0 @@ -185,6 +194,16 @@ def update_viewer(self, event, *args): self.change_roi_opacity(uuid, opacity) self.Render() + def start_event_loop(self): + while not self.stop_rendering: + try: + event, args = self.event_queue.get(timeout=1) + self.update_viewer(event,*args) + except Empty: + pass + except Exception, e: + print type(e), e + class ThreeDimRenderWindow(object): textActors = {} diff --git a/pylocator/surf_renderer_props.py b/pylocator/surf_renderer_props.py index 569973f..afaea59 100644 --- a/pylocator/surf_renderer_props.py +++ b/pylocator/surf_renderer_props.py @@ -476,3 +476,5 @@ def set_image_data(self, data): def update_viewer(self, event, *args): if event=='set image data': self.set_image_data(args[0]) + + enqueue_update = update_viewer From 8d49faeb4f1b0c9bc4c594041c6c7f73b5cdf3d6 Mon Sep 17 00:00:00 2001 From: Thorsten Kranz Date: Wed, 25 Apr 2012 23:43:47 +0200 Subject: [PATCH 13/22] Updating windows with idle_add Instead of using multiple threads (producing random crashed without sync) we now use the idle_add-possibility of gobject to integrate the updated into the event loop of gtk. --- pylocator/render_window.py | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/pylocator/render_window.py b/pylocator/render_window.py index 001c118..d8dce20 100644 --- a/pylocator/render_window.py +++ b/pylocator/render_window.py @@ -1,6 +1,6 @@ from Queue import Queue, Empty -from threading import Thread import gtk +import gobject import vtk from GtkGLExtVTKRenderWindowInteractor import GtkGLExtVTKRenderWindowInteractor from events import EventHandler @@ -20,9 +20,6 @@ def __init__(self,*args): self.screenshot_button_label = "_render window_" self.roi_actors = {} self.event_queue = Queue(10) - self.stop_rendering = False - self.updating_thread = Thread(target=self.start_event_loop) - self.updating_thread.start() EventHandler().attach(self) self.interactButtons = (1,2,3) @@ -139,6 +136,7 @@ def _get_roi_actor(self, uuid): def enqueue_update(self, event, *args): self.event_queue.put((event, args), timeout=10) + gobject.idle_add(self.do_update) def update_viewer(self, event, *args): if event=='render off': @@ -194,15 +192,12 @@ def update_viewer(self, event, *args): self.change_roi_opacity(uuid, opacity) self.Render() - def start_event_loop(self): - while not self.stop_rendering: - try: - event, args = self.event_queue.get(timeout=1) - self.update_viewer(event,*args) - except Empty: - pass - except Exception, e: - print type(e), e + def do_update(self): + try: + event, args = self.event_queue.get(timeout=1) + self.update_viewer(event,*args) + except Empty: + pass class ThreeDimRenderWindow(object): textActors = {} From 9ce77d9813990da54221d2a4f09529d587d1167e Mon Sep 17 00:00:00 2001 From: Thorsten Kranz Date: Thu, 26 Apr 2012 03:35:21 +0200 Subject: [PATCH 14/22] Version number --- pylocator/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pylocator/__init__.py b/pylocator/__init__.py index b214e35..73aaa0e 100644 --- a/pylocator/__init__.py +++ b/pylocator/__init__.py @@ -12,5 +12,5 @@ pygtk, gtkglext """ -__version__ = "1.0 beta 1" +__version__ = "1.0.90" From 1bf595250f0909afe0f295595ca8f5c97a02f5de Mon Sep 17 00:00:00 2001 From: Thorsten Kranz Date: Thu, 3 May 2012 00:00:50 +0200 Subject: [PATCH 15/22] Multiple selection; first shot --- pylocator/marker_list.py | 49 +++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/pylocator/marker_list.py b/pylocator/marker_list.py index f773e78..d0b9466 100644 --- a/pylocator/marker_list.py +++ b/pylocator/marker_list.py @@ -1,4 +1,5 @@ from __future__ import division +from sets import Set import gobject import gtk @@ -22,6 +23,7 @@ def __init__(self): self._marker_ids = {} self.nmrk=0 self.__ignore_sel_changed = False + self.old_selection=Set([]) #Toolbar toolbar = self.__create_toolbar() @@ -39,7 +41,7 @@ def __init__(self): self.treev_mrk = gtk.TreeView(self.tree_mrk) self._treev_sel = self.treev_mrk.get_selection() self._treev_sel.connect("changed",self.treev_sel_changed) - self._treev_sel.set_mode(gtk.SELECTION_SINGLE) + self._treev_sel.set_mode(gtk.SELECTION_MULTIPLE) renderer = gtk.CellRendererText() renderer.set_property("xalign",1.0) #renderer.set_xalign(0.0) @@ -147,10 +149,11 @@ def cb_add(self,*args): EventHandler().add_marker(marker) def cb_remove(self,*args): - marker = self.__get_selected_marker() - if marker==None: + markers = self.__get_selected_markers() + if markers==None: return - EventHandler().remove_marker(marker) + for marker in markers: + EventHandler().remove_marker(marker) def cb_choose_color(self,*args): marker = self.__get_selected_marker() @@ -248,17 +251,30 @@ def remove_marker(self,marker): def treev_sel_changed(self,selection): if self.__ignore_sel_changed: return - EventHandler().clear_selection() - try: - treeiter = selection.get_selected()[1] - if treeiter: + model, rows = selection.get_selected_rows() + if rows!=None: + new_selection = Set(rows) + newly_selected = new_selection - self.old_selection + newly_deselected = self.old_selection - new_selection + #print self.old_selection + #print new_selection + #print newly_selected + #print newly_deselected + for row in newly_selected: + treeiter = model.get_iter(row) mrk_id = self.tree_mrk.get(treeiter,0)[0] if mrk_id==None: return marker = self._markers[mrk_id] - EventHandler().select_new(marker) - except: - pass + EventHandler().add_selection(marker) + for row in newly_deselected: + treeiter = model.get_iter(row) + mrk_id = self.tree_mrk.get(treeiter,0)[0] + if mrk_id==None: + return + marker = self._markers[mrk_id] + EventHandler().remove_selection(marker) + self.old_selection = Set(rows) def __update_treeview_visibility(self): if self.tree_mrk.get_iter_first()==None: @@ -269,12 +285,13 @@ def __update_treeview_visibility(self): self.emptyIndicator.hide() self.scrolledwindow.show() - def __get_selected_marker(self): - treeiter = self._treev_sel.get_selected()[1] - if not treeiter: + def __get_selected_markers(self): + model, rows = self._treev_sel.get_selected_rows() + if rows==None: return - mrk_id = self.tree_mrk.get(treeiter,0)[0] - return self._markers[mrk_id] + treeiters = [model.get_iter(row) for row in rows] + mrk_ids = [model.get(treeiter,0)[0] for treeiter in treeiters] + return [self._markers[mrk_id] for mrk_id in mrk_ids] def __format_coord_string(self,x,y,z): def fmt(f): From b1171e4fd62e15bc446883a8470df30d73c3b445 Mon Sep 17 00:00:00 2001 From: Thorsten Kranz Date: Tue, 8 May 2012 23:27:40 +0200 Subject: [PATCH 16/22] Generated changelog with gdch --- debian/changelog | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/debian/changelog b/debian/changelog index 6c05d4b..4573578 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,16 @@ -pylocator (1.0b3) unstable; urgency=low +pylocator (1.0) unstable; urgency=low + [ Thorsten Kranz ] * First debian package for PyLocator + * Added desktop file to pylocator.install + * Next try for desktop & icon installation + * DOC: updating tutorial, images. + * Updated tutorial + * New Logo for documentation + * BF: Changing color of marker is not immediatly visible in plan widgets observers + * Fixed minor problems, e.g., too verbose output + * Increased version number to final release 1.0, still in branch + * Added menu entry for toggling labels, again + * Adjusted calculation of slider values for surface thresholds - -- Thorsten Kranz Fri, 20 April 2012 15:00:00 +0100 - + -- Thorsten A. Kranz Tue, 08 May 2012 23:26:00 +0200 From 27f6915f47baef6b22ebbe831c064ce4c6e79f9f Mon Sep 17 00:00:00 2001 From: Thorsten Kranz Date: Wed, 9 May 2012 00:00:34 +0200 Subject: [PATCH 17/22] Cleaning from failed merge --- debian/changelog | 6 ---- debian/compat | 1 - debian/control | 25 ---------------- debian/copyright | 65 ---------------------------------------- debian/gbp.conf | 8 ----- debian/pycompat | 1 - debian/pylocator.desktop | 10 ------- debian/pylocator.install | 2 -- debian/rules | 32 -------------------- debian/source/format | 1 - debian/source/options | 3 -- 11 files changed, 154 deletions(-) delete mode 100644 debian/changelog delete mode 100644 debian/compat delete mode 100644 debian/control delete mode 100644 debian/copyright delete mode 100644 debian/gbp.conf delete mode 100644 debian/pycompat delete mode 100644 debian/pylocator.desktop delete mode 100644 debian/pylocator.install delete mode 100755 debian/rules delete mode 100644 debian/source/format delete mode 100644 debian/source/options diff --git a/debian/changelog b/debian/changelog deleted file mode 100644 index 6c05d4b..0000000 --- a/debian/changelog +++ /dev/null @@ -1,6 +0,0 @@ -pylocator (1.0b3) unstable; urgency=low - - * First debian package for PyLocator - - -- Thorsten Kranz Fri, 20 April 2012 15:00:00 +0100 - diff --git a/debian/compat b/debian/compat deleted file mode 100644 index 7f8f011..0000000 --- a/debian/compat +++ /dev/null @@ -1 +0,0 @@ -7 diff --git a/debian/control b/debian/control deleted file mode 100644 index f8a59d1..0000000 --- a/debian/control +++ /dev/null @@ -1,25 +0,0 @@ -Source: pylocator -Section: python -Priority: extra -Maintainer: Thorsten Kranz -Uploaders: Thorsten Kranz -Build-Depends: debhelper (>= 7.2.18), python-all (>= 2.5), python-support (>= 0.6), python-numpy (>= 1.2), python-nibabel, python-vtk, python-gtk2, python-gtkglext1 -Standards-Version: 3.9.2 -Homepage: http://pylocator.thorstenkranz.de -Vcs-Browser: http://github.com/nipy/PyLocator -Vcs-Git: git://github.com/nipy/PyLocator.git -XS-Python-Version: >= 2.5 - -Package: pylocator -Architecture: all -Depends: ${misc:Depends}, ${python:Depends}, python-numpy, python-scipy, python-nibabel, python-vtk, python-gtk2, python-gtkglext1 -Recommends: python-dicom -Provides: ${python:Provides} -XB-Python-Version: ${python:Versions} -Description: Localization of EEG-electrodes from MRI-volumes - PyLocator is a little program for localizing EEG electrodes from MR-images. - It uses VTK to show a neat GUI for marking electrode locations in 3d-space. - It is based on previous work by John D. Hunter and Michael Castell as part - of pbrain, now maintained by Eli Albert. - PyLocator works as a stand-alone program without any dependencies from pbrain. - diff --git a/debian/copyright b/debian/copyright deleted file mode 100644 index ce49314..0000000 --- a/debian/copyright +++ /dev/null @@ -1,65 +0,0 @@ -Format-Specification: http://svn.debian.org/wsvn/dep/web/deps/dep5.mdwn?op=file&rev=174 -Upstream-Name: pylocator -Upstream-Contact: thorstenkranz@gmail.com -Source: http://github.com/nipy/PyLocator - - -Files: * -Copyright 2011-2012, Thorsten Kranz. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are -permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of - conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list - of conditions and the following disclaimer in the documentation and/or other materials - provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THORSTEN KRANZ ''AS IS'' AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THORSTEN KRANZ OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -The views and conclusions contained in the software and documentation are those of the -authors and should not be interpreted as representing official policies, either expressed -or implied, of Thorsten Kranz. - -Files: doc/sphinxext/autosummary/* -Copyright: 2007-2009, Stefan van der Walt and Sphinx team -License: BSD - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - . - a. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - b. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - c. Neither the name of the Enthought nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - . - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR - ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - DAMAGE. - - -Files: debian/* -Copyright: 2006-2010, Michael Hanke - 2011, Yaroslav Halchenko -License: Expat diff --git a/debian/gbp.conf b/debian/gbp.conf deleted file mode 100644 index 92efb7d..0000000 --- a/debian/gbp.conf +++ /dev/null @@ -1,8 +0,0 @@ -[DEFAULT] -# the default branch for upstream sources: -upstream-branch = master -# the default branch for the debian patch: -debian-branch = debian -# the default tag formats used: -upstream-tag = %(version)s -debian-tag = debian/%(version)s diff --git a/debian/pycompat b/debian/pycompat deleted file mode 100644 index 0cfbf08..0000000 --- a/debian/pycompat +++ /dev/null @@ -1 +0,0 @@ -2 diff --git a/debian/pylocator.desktop b/debian/pylocator.desktop deleted file mode 100644 index f37ca13..0000000 --- a/debian/pylocator.desktop +++ /dev/null @@ -1,10 +0,0 @@ -[Desktop Entry] -Version=1.0b1 -Type=Application -Categories=Science; -Name=PyLocator -Comment=Marking electrode locations in MRI recordings -TryExec=pylocator -Exec=pylocator %F -Icon=pylocator -MimeType=application/x-gzip; data/octet-stream diff --git a/debian/pylocator.install b/debian/pylocator.install deleted file mode 100644 index ed661e8..0000000 --- a/debian/pylocator.install +++ /dev/null @@ -1,2 +0,0 @@ -debian/pylocator.desktop usr/share/applications/ -pylocator/resources/pylocator.ico usr/share/icons/ diff --git a/debian/rules b/debian/rules deleted file mode 100755 index ec9c0f2..0000000 --- a/debian/rules +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/make -f -# -*- mode: makefile; coding: utf-8 -*- - -# one ring to rule them all ... -%: -# need to enforce distutils, since we also have a makefile - dh $@ --buildsystem=python_distutils --builddirectory=build - -override_dh_auto_build: - dh_auto_build - # and docs -# $(MAKE) htmldoc -# # but remove jquery copy (later on link to Debian's version) -# -rm doc/build/html/_static/jquery.js -# # objects inventory is of no use for the package -# -rm doc/build/html/objects.inv -# # also doc source files only consume space -# -rm -r build/html/_sources - -## immediately useable documentation -## and exemplar data (they are small excerpts anyway) -override_dh_compress: - dh_compress -X.py -X.html -X.css -X.jpg -X.txt -X.js -X.json -X.rtc -X.par -X.bin - -#override_dh_installman: -# PYTHONPATH=build/lib:$(PYTHONPATH) help2man -N \ -# -n 'convert PARREC image to NIfTI' bin/parrec2nii > build/parrec2nii.1 -# dh_installman build/parrec2nii.1 - -#override_dh_clean: -# $(MAKE) clean -# dh_clean diff --git a/debian/source/format b/debian/source/format deleted file mode 100644 index 89ae9db..0000000 --- a/debian/source/format +++ /dev/null @@ -1 +0,0 @@ -3.0 (native) diff --git a/debian/source/options b/debian/source/options deleted file mode 100644 index 9874f1d..0000000 --- a/debian/source/options +++ /dev/null @@ -1,3 +0,0 @@ -# ignore changes to the commit info file, since it will always have the -# shasum of the release tag and the repository version does not. -# extend-diff-ignore = nibabel/COMMIT_INFO.txt From a351e1a29725b8a93d62af7e7bee80cc5be875eb Mon Sep 17 00:00:00 2001 From: Thorsten Kranz Date: Tue, 26 Mar 2013 00:42:56 +0100 Subject: [PATCH 18/22] FIX: No slider increment found for images with value range 0-1 --- pylocator/surf_renderer_props.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pylocator/surf_renderer_props.py b/pylocator/surf_renderer_props.py index 767d9f5..cc7d404 100644 --- a/pylocator/surf_renderer_props.py +++ b/pylocator/surf_renderer_props.py @@ -364,9 +364,9 @@ def interaction_event(self, observer, event): #self.entryIntensity.set_text('%1.1f' % (self.intensitySum/self.intensityCnt)) def __adjust_scrollbar_threshold_for_data(self): - valid_increments = sorted([1.*10**e for e in range(-2,3)] + - [2.*10**e for e in range(-2,3)] + - [5.*10**e for e in range(-2,3)] + valid_increments = sorted([1.*10**e for e in range(-4,3)] + + [2.*10**e for e in range(-4,3)] + + [5.*10**e for e in range(-4,3)] ) min_, median_, max_ = EventHandler().get_nifti_stats() upper_limit = min(max_ , median_+4*(median_-min_)) #if max is too high From 0c2d3c71effa915a5701d48c7e404054973e0b9a Mon Sep 17 00:00:00 2001 From: Thorsten Kranz Date: Fri, 8 Feb 2013 18:47:40 +0100 Subject: [PATCH 19/22] Change: replaced HScrollbar by HScale, due to new look in recent versions of PyGTK, Change: comments allowed in markers-files. --- pylocator/events.py | 8 ++- pylocator/misc/markers_io.py | 17 +++++-- pylocator/roi_renderer_props.py | 26 +++++----- pylocator/surf_renderer_props.py | 84 ++++++++++++++++---------------- 4 files changed, 73 insertions(+), 62 deletions(-) diff --git a/pylocator/events.py b/pylocator/events.py index eb97c75..1605d7f 100644 --- a/pylocator/events.py +++ b/pylocator/events.py @@ -3,6 +3,7 @@ import pickle from shared import shared from vtkutils import vtkmatrix4x4_to_array +from misc import markers_io class UndoRegistry: __sharedState = {} @@ -155,8 +156,11 @@ def save_registration_as(self, fname): def load_markers_from(self, fname): self.notify('render off') - for line in file(fname, 'r'): - marker = Marker.from_string(line) + for marker_values in markers_io.load_markers(open(fname, 'r')): + marker = Marker(xyz=(marker_values[1:4]), + radius=marker_values[4], + rgb = marker_values[5:8]) + marker.set_label(marker_values[0]) self.add_marker(marker) self.notify('render on') UndoRegistry().flush() diff --git a/pylocator/misc/markers_io.py b/pylocator/misc/markers_io.py index 6b42ac9..f66b15f 100644 --- a/pylocator/misc/markers_io.py +++ b/pylocator/misc/markers_io.py @@ -1,14 +1,21 @@ - def load_markers(fh): if type(fh)==str: fh = open(fh,"r") rv = [] for line in fh.readlines(): - rv.append([]) - parts = line[:-1].split(",") - rv[-1].append(parts[0]) + data_and_comment = line.split("#") + if len(data_and_comment) == 1: + data_part = data_and_comment[0][:-1] #strip newline at end + else: + data_part = data_and_comment[0] # ignore comment + if len(data_part.strip()) == 0: + continue + new_item = [] + parts = data_part.split(",") + new_item.append(parts[0]) for i in range(1,len(parts)): - rv[-1].append(float(parts[i])) + new_item.append(float(parts[i])) + rv.append(new_item) return rv def load_markers_to_dict(fh): diff --git a/pylocator/roi_renderer_props.py b/pylocator/roi_renderer_props.py index 0f1d666..e1a1437 100644 --- a/pylocator/roi_renderer_props.py +++ b/pylocator/roi_renderer_props.py @@ -15,7 +15,7 @@ from rois import RoiParams class RoiRendererProps(gtk.VBox): - SCROLLBARSIZE = 150,20 + SCALESIZE = 150,20 lastColor = SurfParams.color paramd = {} # a dict from names to SurfParam instances @@ -110,15 +110,15 @@ def _make_properties_frame(self): f1 = gtk.Frame("Opacity") f1.show() vboxProps.pack_start(f1, False) - self.scrollbar_opacity = gtk.HScrollbar() - self.scrollbar_opacity.set_update_policy(gtk.UPDATE_DELAYED) - self.scrollbar_opacity.show() - self.scrollbar_opacity.set_size_request(*self.SCROLLBARSIZE) - self.scrollbar_opacity.set_range(0, 1) - self.scrollbar_opacity.set_increments(.05, .2) - self.scrollbar_opacity.set_value(1.0) - self.scrollbar_opacity.connect('value_changed', self.change_opacity_of_roi) - f1.add(self.scrollbar_opacity) + self.scale_opacity = gtk.HScale() + self.scale_opacity.set_update_policy(gtk.UPDATE_DELAYED) + self.scale_opacity.show() + self.scale_opacity.set_size_request(*self.SCALESIZE) + self.scale_opacity.set_range(0, 1) + self.scale_opacity.set_increments(.05, .2) + self.scale_opacity.set_value(1.0) + self.scale_opacity.connect('value_changed', self.change_opacity_of_roi) + f1.add(self.scale_opacity) f2 = gtk.Frame("Color") f2.show() @@ -183,9 +183,9 @@ def treev_sel_changed(self,selection): except Exception, e: print "During setting color of color chooser:", type(e),e try: - self.scrollbar_opacity.set_value(self.paramd[roi_id].opacity) + self.scale_opacity.set_value(self.paramd[roi_id].opacity) except Exception, e: - print "During setting value of opacity scrollbar:", type(e),e + print "During setting value of opacity scale:", type(e),e else: self.props_frame.hide() @@ -200,7 +200,7 @@ def change_opacity_of_roi(self,*args): treeiter = self.treev_sel.get_selected()[1] if treeiter: roi_id = self.tree_roi.get(treeiter,0) - self.paramd[roi_id].set_opacity(self.scrollbar_opacity.get_value()) + self.paramd[roi_id].set_opacity(self.scale_opacity.get_value()) self.render() def __update_treeview_visibility(self): diff --git a/pylocator/surf_renderer_props.py b/pylocator/surf_renderer_props.py index cc7d404..5845f9c 100644 --- a/pylocator/surf_renderer_props.py +++ b/pylocator/surf_renderer_props.py @@ -17,7 +17,7 @@ from connect_filter import ConnectFilter class SurfRendererProps(gtk.VBox): - SCROLLBARSIZE = 150,20 + SCALESIZE = 150,20 lastColor = SurfParams.color_ lastColorName = SurfParams.colorName picker_surface_id = None @@ -131,31 +131,31 @@ def _make_general_properties_expander(self): frame = gtk.Frame("Threshold") frame.show() vbox.pack_start(frame) - scrollbar = gtk.HScrollbar() - scrollbar.set_update_policy(gtk.UPDATE_DELAYED) - #scrollbar.set_draw_value(True) - scrollbar.show() - scrollbar.set_size_request(*self.SCROLLBARSIZE) - scrollbar.set_range(0, 100) - scrollbar.set_increments(1, 5) - scrollbar.set_value(80) - scrollbar.connect('value-changed', self.change_threshold_of_surf) - self.scrollbar_threshold = scrollbar - frame.add(scrollbar) + scale = gtk.HScale() + scale.set_update_policy(gtk.UPDATE_DELAYED) + #scale.set_draw_value(True) + scale.show() + scale.set_size_request(*self.SCALESIZE) + scale.set_range(0, 100) + scale.set_increments(1, 5) + scale.set_value(80) + scale.connect('value-changed', self.change_threshold_of_surf) + self.scale_threshold = scale + frame.add(scale) frame = gtk.Frame("Opacity") frame.show() vbox.pack_start(frame) - scrollbar = gtk.HScrollbar() - scrollbar.set_update_policy(gtk.UPDATE_DELAYED) - scrollbar.show() - scrollbar.set_size_request(*self.SCROLLBARSIZE) - scrollbar.set_range(0, 1) - scrollbar.set_increments(.05, .2) - scrollbar.set_value(1.0) - scrollbar.connect('value-changed', self.change_opacity_of_surf) - self.scrollbar_opacity = scrollbar - frame.add(scrollbar) + scale = gtk.HScale() + scale.set_update_policy(gtk.UPDATE_DELAYED) + scale.show() + scale.set_size_request(*self.SCALESIZE) + scale.set_range(0, 1) + scale.set_increments(.05, .2) + scale.set_value(1.0) + scale.connect('value-changed', self.change_opacity_of_surf) + self.scale_opacity = scale + frame.add(scale) hbox = gtk.HBox() hbox.show() @@ -206,7 +206,7 @@ def set_connect_mode(id_): def set_decimate_params(id_): if self.paramd[id_].useDecimate: - self.paramd[id_].deci.targetReduction = self.scrollbar_target_reduction.get_value() + self.paramd[id_].deci.targetReduction = self.scale_target_reduction.get_value() def connect_method_changed(button): if button.get_active(): @@ -287,16 +287,16 @@ def apply_(*args): vboxFrame = gtk.VBox() vboxFrame.set_spacing(3) vboxFrame.pack_start(gtk.Label("Target Reduction")) - scrollbar = gtk.HScrollbar() - scrollbar.set_update_policy(gtk.UPDATE_DELAYED) - scrollbar.show() - scrollbar.set_size_request(*self.SCROLLBARSIZE) - scrollbar.set_range(0, 0.99) - scrollbar.set_increments(.05, .2) - scrollbar.set_value(0.8) - scrollbar.connect('value_changed', apply_) - self.scrollbar_target_reduction = scrollbar - vboxFrame.pack_start(scrollbar) + scale = gtk.HScale() + scale.set_update_policy(gtk.UPDATE_DELAYED) + scale.show() + scale.set_size_request(*self.SCALESIZE) + scale.set_range(0, 0.99) + scale.set_increments(.05, .2) + scale.set_value(0.8) + scale.connect('value_changed', apply_) + self.scale_target_reduction = scale + vboxFrame.pack_start(scale) frameDecimateFilter.add(vboxFrame) expander.show_all() @@ -322,7 +322,7 @@ def add_segment(self, button): error_msg("Cannot create surface. Image data of surface renderer is not set.") return if self.nsurf==0: - self.__adjust_scrollbar_threshold_for_data() + self.__adjust_scale_threshold_for_data() self.nsurf +=1 intensity = self.__calculate_intensity_threshold() @@ -363,7 +363,7 @@ def interaction_event(self, observer, event): #self.add_intensity(xyzv[3]) #self.entryIntensity.set_text('%1.1f' % (self.intensitySum/self.intensityCnt)) - def __adjust_scrollbar_threshold_for_data(self): + def __adjust_scale_threshold_for_data(self): valid_increments = sorted([1.*10**e for e in range(-4,3)] + [2.*10**e for e in range(-4,3)] + [5.*10**e for e in range(-4,3)] @@ -372,9 +372,9 @@ def __adjust_scrollbar_threshold_for_data(self): upper_limit = min(max_ , median_+4*(median_-min_)) #if max is too high incr1 = [i for i in valid_increments if i<(upper_limit-min_)/100][-1] incr2 = [i for i in valid_increments if i<(upper_limit-min_)/20][-1] - self.scrollbar_threshold.set_range(min_, upper_limit) - self.scrollbar_threshold.set_increments(incr1, incr2) - self.scrollbar_threshold.set_value(median_) + self.scale_threshold.set_range(min_, upper_limit) + self.scale_threshold.set_increments(incr1, incr2) + self.scale_threshold.set_value(median_) def __get_selected_id(self): treeiter = self.treev_sel.get_selected()[1] @@ -400,12 +400,12 @@ def treev_sel_changed(self, selection): self.props_frame.show() try: self.ignore_settings_updates = True - self.scrollbar_threshold.set_value(param.intensity) + self.scale_threshold.set_value(param.intensity) if param.colorName==self.color_chooser.custom_str: self.color_chooser._set_color(param.color) else: self.color_chooser._set_color(param.colorName) - self.scrollbar_opacity.set_value(param.opacity) + self.scale_opacity.set_value(param.opacity) self.update_pipeline_params() is_picker_surface = param.uuid==self.picker_surface_id self.pickerButton.set_active(is_picker_surface) @@ -419,13 +419,13 @@ def change_threshold_of_surf(self,*args): param = self.__get_selected_surface() if not param: return - param.intensity = self.scrollbar_threshold.get_value() + param.intensity = self.scale_threshold.get_value() param.update_pipeline() self.render() def change_opacity_of_surf(self,*args): param = self.__get_selected_surface() - param.set_opacity(self.scrollbar_opacity.get_value()) + param.set_opacity(self.scale_opacity.get_value()) self.render() def change_color_of_surf(self,*args): From aba79a9485097b632adc110fb8a5ba91704b460b Mon Sep 17 00:00:00 2001 From: Thorsten Kranz Date: Sat, 9 Feb 2013 11:51:14 +0100 Subject: [PATCH 20/22] Changed height of scales load_markers_to_dict now uses load_markers (less code repetition ) Tests for markers_io.load_markers --- pylocator/misc/markers_io.py | 42 ++++++++++---- pylocator/roi_renderer_props.py | 2 +- pylocator/surf_renderer_props.py | 4 +- pylocator/tests/misc/__init__.py | 0 pylocator/tests/misc/test_markers_io.py | 76 +++++++++++++++++++++++++ pylocator/tests/test_gui.py | 39 ++++++------- 6 files changed, 127 insertions(+), 36 deletions(-) create mode 100644 pylocator/tests/misc/__init__.py create mode 100644 pylocator/tests/misc/test_markers_io.py diff --git a/pylocator/misc/markers_io.py b/pylocator/misc/markers_io.py index f66b15f..5325842 100644 --- a/pylocator/misc/markers_io.py +++ b/pylocator/misc/markers_io.py @@ -1,8 +1,18 @@ def load_markers(fh): + """Reads all markers from a file to a list. Converts coordinates, radii and color + to float. + + :param fh: File handle open for reading or filename. If filename is given, + file will be opened in "r" mode. + :type fh: file or string + + :returns: List of lists. Each marker is represented as a list with eight + values: label, x,y,z, radius, red, green, blue + """ if type(fh)==str: fh = open(fh,"r") rv = [] - for line in fh.readlines(): + for idx, line in enumerate(fh.readlines()): data_and_comment = line.split("#") if len(data_and_comment) == 1: data_part = data_and_comment[0][:-1] #strip newline at end @@ -14,22 +24,32 @@ def load_markers(fh): parts = data_part.split(",") new_item.append(parts[0]) for i in range(1,len(parts)): - new_item.append(float(parts[i])) + try: + new_item.append(float(parts[i])) + except ValueError, ve: + raise FormatException(ve) + if not len(new_item)==8: + raise FormatException("Not enough values in line %i" % idx) rv.append(new_item) return rv def load_markers_to_dict(fh): - if type(fh)==str: - fh = open(fh,"r") - marker_list = [] - for line in fh.readlines(): - marker_list.append([]) - parts = line[:-1].split(",") - marker_list[-1].append(parts[0]) - for i in range(1,len(parts)): - marker_list[-1].append(float(parts[i])) + """Reads all markers from a file to a dictionary. Converts coordinates, radii and color + to float. Using the same label for two or more times will hide some markers. + + :param fh: File handle open for reading or filename. If filename is given, + file will be opened in "r" mode. + :type fh: file or string + + :returns: Dictionary of lists. Each marker is represented as a list with eight + values: label, x,y,z, radius, red, green, blue + """ + marker_list = load_markers(fh) return dict([(marker[0],marker[1:]) for marker in marker_list]) +class FormatException(Exception): + pass + if __name__=="__main__": fn = "/media/Extern/public/Experimente/AudioStroop/kombinierte_analyse/elec_pos/443.txt" print load_markers(fn) diff --git a/pylocator/roi_renderer_props.py b/pylocator/roi_renderer_props.py index e1a1437..66d2634 100644 --- a/pylocator/roi_renderer_props.py +++ b/pylocator/roi_renderer_props.py @@ -15,7 +15,7 @@ from rois import RoiParams class RoiRendererProps(gtk.VBox): - SCALESIZE = 150,20 + SCALESIZE = 150,40 lastColor = SurfParams.color paramd = {} # a dict from names to SurfParam instances diff --git a/pylocator/surf_renderer_props.py b/pylocator/surf_renderer_props.py index 5845f9c..f26a6ff 100644 --- a/pylocator/surf_renderer_props.py +++ b/pylocator/surf_renderer_props.py @@ -17,7 +17,7 @@ from connect_filter import ConnectFilter class SurfRendererProps(gtk.VBox): - SCALESIZE = 150,20 + SCALESIZE = 150,40 lastColor = SurfParams.color_ lastColorName = SurfParams.colorName picker_surface_id = None @@ -151,7 +151,7 @@ def _make_general_properties_expander(self): scale.show() scale.set_size_request(*self.SCALESIZE) scale.set_range(0, 1) - scale.set_increments(.05, .2) + scale.set_increments(.025, .1) scale.set_value(1.0) scale.connect('value-changed', self.change_opacity_of_surf) self.scale_opacity = scale diff --git a/pylocator/tests/misc/__init__.py b/pylocator/tests/misc/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pylocator/tests/misc/test_markers_io.py b/pylocator/tests/misc/test_markers_io.py new file mode 100644 index 0000000..3b46f77 --- /dev/null +++ b/pylocator/tests/misc/test_markers_io.py @@ -0,0 +1,76 @@ +from cStringIO import StringIO +from pylocator.misc import markers_io + +from nose.tools import assert_raises + +valid_test_cases = { +"simple without labels" : +""",25.5092096987,-18.0000156769,37.0115808132,5.0,0.0,0.0,1.0 +,46.686666807,-18.0000156769,-9.19378015049,5.0,0.0,0.0,1.0 +,8.18219933732,-18.0000156769,11.5023711145,5.0,0.0,0.0,1.0""", + +"simple with labels" : +"""Fz,25.5092096987,-18.0000156769,37.0115808132,5.0,0.0,0.0,1.0 +Cz,46.686666807,-18.0000156769,-9.19378015049,5.0,0.0,0.0,1.0 +Pz,8.18219933732,-18.0000156769,11.5023711145,5.0,0.0,0.0,1.0""", + +"exponential notation in coordinate" : +"""Fz,2.55E1,-18.0000156769,37.0115808132,5.0,0.0,0.0,1.0 +Cz,46.686666807,-18.0000156769,-9.19378015049,5.0,0.0,0.0,1.0 +Pz,8.18219933732,-18.0000156769,11.5023711145,5.0,0.0,0.0,1.0""", + +"exponential notation in radius" : +"""Fz,25.5092096987,-18.0000156769,37.0115808132,5.0E-1,0.0,0.0,1.0 +Cz,46.686666807,-18.0000156769,-9.19378015049,5.0,0.0,0.0,1.0 +Pz,8.18219933732,-18.0000156769,11.5023711145,5.0,0.0,0.0,1.0""", + +"exponential notation in color" : +"""Fz,25.5092096987,-18.0000156769,37.0115808132,5.0,0.0,0.0,2.0E-1 +Cz,46.686666807,-18.0000156769,-9.19378015049,5.0,0.0,0.0,1.0 +Pz,8.18219933732,-18.0000156769,11.5023711145,5.0,0.0,0.0,1.0""", + +"comment line in the beginning" : +"""# This is a comment +Fz,25.5092096987,-18.0000156769,37.0115808132,5.0,0.0,0.0,1.0 +Cz,46.686666807,-18.0000156769,-9.19378015049,5.0,0.0,0.0,1.0 +Pz,8.18219933732,-18.0000156769,11.5023711145,5.0,0.0,0.0,1.0""", + +"comment for one coordinate" : +"""Fz,25.5092096987,-18.0000156769,37.0115808132,5.0,0.0,0.0,1.0 # This is a comment +Cz,46.686666807,-18.0000156769,-9.19378015049,5.0,0.0,0.0,1.0 +Pz,8.18219933732,-18.0000156769,11.5023711145,5.0,0.0,0.0,1.0""", + +"empty line" : +"""Fz,25.5092096987,-18.0000156769,37.0115808132,5.0,0.0,0.0,1.0 + +Cz,46.686666807,-18.0000156769,-9.19378015049,5.0,0.0,0.0,1.0 +Pz,8.18219933732,-18.0000156769,11.5023711145,5.0,0.0,0.0,1.0""", +} + +invalid_test_cases = { +"coordinate is no float" : +""",ERROR,-18.0000156769,37.0115808132,5.0,0.0,0.0,1.0 +,46.686666807,-18.0000156769,-9.19378015049,5.0,0.0,0.0,1.0 +,8.18219933732,-18.0000156769,11.5023711145,5.0,0.0,0.0,1.0""", + +"not enough values" : +""",25.5092096987,-18.0000156769,37.0115808132,5.0,0.0,0.0 +,46.686666807,-18.0000156769,-9.19378015049,5.0,0.0,0.0,1.0 +,8.18219933732,-18.0000156769,11.5023711145,5.0,0.0,0.0,1.0""", +} + +def test_reading_markers_from_filehandle(): + for k in valid_test_cases: + yield read_markers_from_stringio, k, valid_test_cases[k] + +def read_markers_from_stringio(key, file_content): + sio = StringIO(file_content) + markers = markers_io.load_markers(sio) + assert len(markers)>0 + +def test_reading_invalid_markers_from_filehandle(): + for k in invalid_test_cases: + yield invalid_data_raise_exception, k, invalid_test_cases[k] + +def invalid_data_raise_exception(key, file_content): + assert_raises(markers_io.FormatException, read_markers_from_stringio, key, file_content) diff --git a/pylocator/tests/test_gui.py b/pylocator/tests/test_gui.py index 3705739..876cf40 100644 --- a/pylocator/tests/test_gui.py +++ b/pylocator/tests/test_gui.py @@ -1,31 +1,26 @@ import gobject, gtk import getopt,sys,os -from pylocator.pylocator_mainwindow import PyLocatorMainWindow +from pylocator.controller import PyLocatorController from pylocator.shared import shared from nose.tools import assert_raises -usage="""usage: %s [options] -options: ---help -h print this message ---filename -f filename""" % sys.argv[0] - def test_mainwindow_noargs(): - window = PyLocatorMainWindow() - window.show() - -def test_mainwindow(): - my_argv = ["-f", "somestrangeand_inexistent_file.nii.gz"] - options, args = getopt.getopt(my_argv[:], 'hf:s:', ['help','filename','surface']) - filename=None - surface=None - for option, value in options: - if option in ('-h', '--help'): - print usage; sys.exit(0) - if option in ('-f', '--file'): - filename=value - if option in ('-s', '--surface'): - surface=value + controller = PyLocatorController() + controller.window.show() - assert_raises(IOError,PyLocatorMainWindow,filename=filename,surface=surface) +#def test_mainwindow(): +# my_argv = ["-f", "somestrangeand_inexistent_file.nii.gz"] +# options, args = getopt.getopt(my_argv[:], 'hf:s:', ['help','filename','surface']) +# filename=None +# surface=None +# for option, value in options: +# if option in ('-h', '--help'): +# print usage; sys.exit(0) +# if option in ('-f', '--file'): +# filename=value +# if option in ('-s', '--surface'): +# surface=value +# +# assert_raises(IOError,PyLocatorMainWindow,filename=filename,surface=surface) From cae4c749970b1c2f0db75700a073fe8765c9580a Mon Sep 17 00:00:00 2001 From: Thorsten Kranz Date: Wed, 10 Apr 2013 00:07:55 +0200 Subject: [PATCH 21/22] UX-improvements NEW: Saving and loading of ROIs FIX: Loading and writing markers from "Tab" possible - towards unified UX --- pylocator/controller.py | 3 +- pylocator/dialogs.py | 14 +++ pylocator/marker_list.py | 60 ++++++++++- pylocator/marker_window_interactor.py | 2 +- pylocator/markers.py | 2 +- pylocator/misc/helpers.py | 12 +++ pylocator/misc/persistence.py | 51 +++++++++ pylocator/plane_widgets_observer.py | 27 +++-- pylocator/plane_widgets_xyz.py | 13 +-- pylocator/render_window.py | 25 ++--- pylocator/roi_renderer_props.py | 148 +++++++++++++++++++------- pylocator/rois.py | 14 ++- pylocator/shared.py | 3 - pylocator/surf_params.py | 17 +-- pylocator/surf_renderer.py | 18 ++-- pylocator/surf_renderer_props.py | 13 +-- pylocator/vtksurface.py | 2 +- 17 files changed, 327 insertions(+), 97 deletions(-) create mode 100644 pylocator/misc/helpers.py create mode 100644 pylocator/misc/persistence.py diff --git a/pylocator/controller.py b/pylocator/controller.py index aead074..8294181 100644 --- a/pylocator/controller.py +++ b/pylocator/controller.py @@ -189,8 +189,7 @@ def load_nifti(self, filename): if not reader: return False else: - imageData = reader.GetOutput() - EventHandler().notify('set image data', imageData) + EventHandler().notify('set image', reader) EventHandler().notify("set axes directions") EventHandler().set_nifti(reader) self.store_current_camera_fpus() diff --git a/pylocator/dialogs.py b/pylocator/dialogs.py index 5e0342b..30b90dd 100644 --- a/pylocator/dialogs.py +++ b/pylocator/dialogs.py @@ -157,3 +157,17 @@ def __get_plane_widgets(self): pwz = self.pwxyz.pwZ return pwx, pwy, pwz +def select_existing_file(title="Please choose a file"): + try: + dialog = gtk.FileSelection(title) + dialog.set_filename(shared.get_last_dir()) + response = dialog.run() + if response == gtk.RESPONSE_OK: + filename = dialog.get_filename() + dialog.destroy() + return filename + else: + dialog.destroy() + return None + except Exception: + return None \ No newline at end of file diff --git a/pylocator/marker_list.py b/pylocator/marker_list.py index d0b9466..3ef9b88 100644 --- a/pylocator/marker_list.py +++ b/pylocator/marker_list.py @@ -3,7 +3,9 @@ import gobject import gtk -from dialogs import edit_coordinates, edit_label_of_marker +from dialogs import (edit_coordinates, edit_label_of_marker, + select_existing_file) +from gtkutils import error_msg from events import EventHandler from colors import choose_one_color, tuple2gdkColor, gdkColor2tuple @@ -99,7 +101,23 @@ def __create_toolbar(self): 'Color', 'Select color for marker', self.cb_choose_color - ] + ], + "-", + [gtk.STOCK_OPEN, + 'Load', + 'Load markers from file', + self.cb_load + ], + [gtk.STOCK_SAVE, + 'Save', + 'Save markers to file', + self.cb_save + ], + [gtk.STOCK_SAVE_AS, + 'Save as', + 'Choose a file and save markers', + self.cb_save_as + ], ] return ListToolbar(conf) @@ -192,6 +210,44 @@ def cb_edit_position(self,*args): EventHandler().notify("move marker",marker, (x,y,z)) self.treev_sel_changed(self._treev_sel) + def cb_load(self, *args): + fname = select_existing_file("Choose file containing marker information") + if fname is not None: + try: + EventHandler().load_markers_from(fname) + except IOError: + error_msg( + 'Could not load markers from %s' % fname, + ) + else: + shared.set_file_selection(fname) + self.markersFileName = fname + + def cb_save(self, *args): + try: self.markersFileName + except AttributeError: + self.save_as(*args) + else: EventHandler().save_markers_as(self.markersFileName) + + def cb_save_as(self, *args): + def ok_clicked(w): + fname = dialog.get_filename() + shared.set_file_selection(fname) + try: EventHandler().save_markers_as(fname) + except IOError: + error_msg('Could not save data to %s' % fname, + ) + else: + self.markersFileName = fname + dialog.destroy() + + dialog = gtk.FileSelection('Choose filename for marker') + dialog.set_filename(shared.get_last_dir()) + dialog.ok_button.connect("clicked", ok_clicked) + dialog.cancel_button.connect("clicked", lambda w: dialog.destroy()) + dialog.show() + pass + def _move_in_list(self,up=True): if self._treev_sel.count_selected_rows == 0: return diff --git a/pylocator/marker_window_interactor.py b/pylocator/marker_window_interactor.py index 37fef62..4e8c820 100644 --- a/pylocator/marker_window_interactor.py +++ b/pylocator/marker_window_interactor.py @@ -66,7 +66,7 @@ def update_viewer(self, event, *args): def get_marker_at_point(self): raise NotImplementedError - def set_image_data(self, imageData): + def set_image(self, image): pass def set_select_mode(self): diff --git a/pylocator/markers.py b/pylocator/markers.py index 9de6baa..58b55a8 100644 --- a/pylocator/markers.py +++ b/pylocator/markers.py @@ -38,7 +38,7 @@ def __init__(self, xyz, radius, rgb = None, uuid_=None): #create ID if not uuid_: - self.uuid = uuid.uuid1() + self.uuid = uuid.uuid4() else: self.uuid = uuid_ diff --git a/pylocator/misc/helpers.py b/pylocator/misc/helpers.py new file mode 100644 index 0000000..7198b99 --- /dev/null +++ b/pylocator/misc/helpers.py @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- +""" +Small helper methods. +""" + +import os + +def relative_and_absolute_path(path): + """Takes a relative or absolute path and returns both the relative and the + absolute path, with respect to the current""" + return os.path.relpath(path), os.path.abspath(path) + diff --git a/pylocator/misc/persistence.py b/pylocator/misc/persistence.py new file mode 100644 index 0000000..f5f4928 --- /dev/null +++ b/pylocator/misc/persistence.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +""" +General saving / loading utilities +""" +import json +import datetime + +DATE_FORMAT = "%Y%m%d %H:%M:%S" + +def save_rois(rois, fh): + output_dict = {} + output_dict["Content"] = "ROI-Definitions for PyLocator" + _add_current_date(output_dict) + output_dict["Data"] = rois + _save_structure_as_json(output_dict, fh) + +def load_rois(fh): + def check_sanity(rois): + assert rois["Content"] == "ROI-Definitions for PyLocator" + _assert_date_is_valid(rois) + for roi in rois["Data"]: + assert len(roi["color"]) == 3 + assert all([0 <= color_part <= 1 for color_part in roi["color"]]) + assert 0 <= roi["opacity"] <= 1 + + rois = _load_json(fh) + check_sanity(rois) + return rois + + +# Helper methods ############################ + +def _save_structure_as_json(rois, fh): + fh = _make_open_file(fh, "w") + json.dump(rois, fh, indent=4) + +def _load_json(fh): + fh = _make_open_file(fh,"r") + return json.load(fh) + +def _make_open_file(fh, mode): + if type(fh)==str: + fh = open(fh,mode) + return fh + +def _add_current_date(dict_): + dict_["Date"] = datetime.datetime.now().strftime(DATE_FORMAT) + +def _assert_date_is_valid(rois): + datetime_saved = datetime.datetime.strptime(rois["Date"], DATE_FORMAT) + assert datetime_saved is not None \ No newline at end of file diff --git a/pylocator/plane_widgets_observer.py b/pylocator/plane_widgets_observer.py index b6491b2..4a16b53 100644 --- a/pylocator/plane_widgets_observer.py +++ b/pylocator/plane_widgets_observer.py @@ -20,7 +20,7 @@ class PlaneWidgetObserver(MarkerWindowInteractor): """ axes_labels_color = (0.,0.82,1.) - def __init__(self, planeWidget, owner, orientation, imageData=None): + def __init__(self, planeWidget, owner, orientation, image=None): if shared.debug: print "PlaneWidgetObserver.__init__(): orientation=",orientation MarkerWindowInteractor.__init__(self) self.interactButtons = (1,2,3) @@ -36,17 +36,18 @@ def __init__(self, planeWidget, owner, orientation, imageData=None): self.textActors = {} self.hasData = 0 - self.set_image_data(imageData) + self.set_image(image) self.lastTime = 0 self.set_mouse1_to_move() - def set_image_data(self, imageData): - if imageData is None: return - self.imageData = imageData + def set_image(self, image): + if image is None: return + self.image = image + self.imageData = image.GetOutput() if not self.hasData: if shared.debug: print "PlaneWidgetObserver(", self.orientation,").. AddObserver(self.interaction_event)" foo = self.pw.AddObserver('InteractionEvent', self.interaction_event) - if shared.debug: print "PlaneWidgetObserver.set_image_data(): AddObserver call returns ", foo + if shared.debug: print "PlaneWidgetObserver.set_image(): AddObserver call returns ", foo self.connect("scroll_event", self.scroll_widget_slice) self.hasData = 1 @@ -63,7 +64,7 @@ def set_image_data(self, imageData): self.observer.SetLookupTable(self.pw.GetLookupTable()) self.observer.DisplayTextOn() #self.observer.GetMarginProperty().EdgeVisibilityOff() # turn off edges?? - self.observer.SetInput(imageData) + self.observer.SetInput(self.imageData) self.observer.SetInteractor(self.interactor) self.observer.On() self.observer.InteractionOff() @@ -527,7 +528,7 @@ def obs_to_world(self, pnt): transform.Scale(spacing) return transform.TransformPoint(pnt) - def add_roi(self, uuid, pipe, color): + def add_roi(self, uuid, pipe, color, opacity): actor = RoiEdgeActor(pipe, color, self.pw) self.renderer.AddActor(actor) actor.color = color @@ -541,7 +542,17 @@ def remove_roi(self, uuid): def color_roi(self, uuid, color): actor = self._get_roi_actor(uuid) + if shared.debug: + print "pwo.color_roi:" + print self.roi_actors.keys() + print uuid + #from pprint import pprint + #pprint(self.roi_actors) + print color if actor: + if shared.debug: + print color actor.set_color(color) + self.update_rois() diff --git a/pylocator/plane_widgets_xyz.py b/pylocator/plane_widgets_xyz.py index 2718764..87a847a 100644 --- a/pylocator/plane_widgets_xyz.py +++ b/pylocator/plane_widgets_xyz.py @@ -34,7 +34,7 @@ class PlaneWidgetsXYZ(ThreeDimRenderWindow, MarkerWindowInteractor): """ axes_labels_color = (0.,0.82,1.) - def __init__(self, imageData=None): + def __init__(self, image=None): MarkerWindowInteractor.__init__(self) ThreeDimRenderWindow.__init__(self) @@ -54,7 +54,7 @@ def __init__(self, imageData=None): self.axes_labels = [] - self.set_image_data(imageData) + self.set_image(image) self.Render() self.vtk_translation = np.zeros(3, 'd') @@ -85,10 +85,11 @@ def rotate_vtk(self, axis, value): self.scaleTransform.Translate(self.vtk_translation[0],self.vtk_translation[1],self.vtk_translation[2]) self.Render() - def set_image_data(self, imageData): - if shared.debug: print "PlaneWidgetsXYZ.set_image_data()!!" - if imageData is None: return - self.imageData = imageData + def set_image(self, image): + if shared.debug: print "PlaneWidgetsXYZ.set_image()!!" + if image is None: return + self.image = image + self.imageData = image.GetOutput() extent = self.imageData.GetBounds()#Extent() if shared.debug: print "***Extent:", extent frac = 0.3 diff --git a/pylocator/render_window.py b/pylocator/render_window.py index d8dce20..76634be 100644 --- a/pylocator/render_window.py +++ b/pylocator/render_window.py @@ -19,7 +19,7 @@ def __init__(self,*args): GtkGLExtVTKRenderWindowInteractor.__init__(self,*args) self.screenshot_button_label = "_render window_" self.roi_actors = {} - self.event_queue = Queue(10) + self.event_queue = Queue(1000) EventHandler().attach(self) self.interactButtons = (1,2,3) @@ -90,7 +90,7 @@ def take_screenshot(self, fn_pattern, magnification=1): def set_screenshot_props(self, label): self.screenshot_button_label = label - def set_image_data(self, image_data): + def set_image(self, image): pass def add_marker(self, marker): @@ -105,7 +105,7 @@ def set_labels_visibility(self, visible=True): def set_marker_selection(self, marker, select=True): pass - def add_surface(self, uuid, pipe, color): + def add_surface(self, uuid, pipe, color, opacity): pass def remove_surface(self, uuid): @@ -146,9 +146,9 @@ def update_viewer(self, event, *args): self.Render() elif event=='render now': self.Render() - elif event=='set image data': - imageData = args[0] - self.set_image_data(imageData) + elif event=='set image': + image = args[0] + self.set_image(image) self.Render() elif event=='add marker': marker = args[0] @@ -167,8 +167,8 @@ def update_viewer(self, event, *args): marker = args[0] self.set_marker_selection(marker, False) elif event=='add surface': - uuid, pipe, color = args - self.add_surface(uuid, pipe, color) + uuid, pipe, color, opacity = args + self.add_surface(uuid, pipe, color, opacity) elif event=='remove surface': uuid = args[0] self.remove_surface(uuid) @@ -176,8 +176,8 @@ def update_viewer(self, event, *args): uuid, color = args self.color_surface(uuid, color) elif event=='add roi': - uuid, pipe, color = args - self.add_roi(uuid, pipe, color) + uuid, pipe, color, opacity = args + self.add_roi(uuid, pipe, color, opacity) elif event=='remove roi': uuid = args[0] self.remove_roi(uuid) @@ -248,9 +248,10 @@ def set_marker_selection(self, marker, select=True): actor = self.boxes[marker] self.renderer.RemoveActor(actor) - def add_roi(self, uuid, pipe, color): + def add_roi(self, uuid, pipe, color, opacity): isoActor = self._create_actor(pipe) isoActor.GetProperty().SetColor(color) + isoActor.GetProperty().SetOpacity(opacity) self._set_roi_lighting(isoActor) self.roi_actors[uuid] = isoActor @@ -270,7 +271,7 @@ def change_roi_opacity(self, uuid, opacity): actor = self._get_roi_actor(uuid) if actor: actor.GetProperty().SetOpacity(opacity) - return self.roi_actors[uuid] + return self.roi_actors[uuid] def _create_actor(self,pipe): isoMapper = vtk.vtkPolyDataMapper() diff --git a/pylocator/roi_renderer_props.py b/pylocator/roi_renderer_props.py index 66d2634..1ae2980 100644 --- a/pylocator/roi_renderer_props.py +++ b/pylocator/roi_renderer_props.py @@ -13,6 +13,9 @@ from colors import ColorChooser from vtkNifti import vtkNiftiImageReader from rois import RoiParams +from dialogs import select_existing_file + +from misc import persistence class RoiRendererProps(gtk.VBox): SCALESIZE = 150,40 @@ -51,19 +54,24 @@ def __create_toolbar(self): [gtk.STOCK_ADD, 'Add', 'Load ROI from file and render it', - self.add_roi + self.cb_add_roi ], [gtk.STOCK_REMOVE, 'Remove', 'Remove selected ROI', self.rm_roi ], - #"-", - #[gtk.STOCK_GO_UP, - # 'Move up', - # 'Move selected marker up in list', - # self.cb_move_up - #], + "-", + [gtk.STOCK_OPEN, + 'Load', + 'Load ROI settings from a file. Will discard all currently used ROIs', + self.load_rois + ], + [gtk.STOCK_SAVE_AS, + 'Save', + 'Save all ROI settings to a file.', + self.save_rois + ], #[gtk.STOCK_GO_DOWN, # 'Move down', # 'Move selected marker down in list', @@ -131,38 +139,35 @@ def _make_properties_frame(self): vboxProps.show_all() return frame - def add_roi(self,*args): - dialog = gtk.FileSelection('Choose filename for ROI mask') - dialog.set_filename(shared.get_last_dir()) - dialog.show() - response = dialog.run() - if response==gtk.RESPONSE_OK: - fname = dialog.get_filename() - dialog.destroy() - try: - #Actually add ROI - self.nroi+=1 - tree_iter = self.tree_roi.append(None) - self.tree_roi.set(tree_iter,0,self.nroi,1,os.path.split(fname)[1],2,fname,3,True) - self.__update_treeview_visibility() - - roi_image_reader = vtkNiftiImageReader() - roi_image_reader.SetFileName(fname) - roi_image_reader.Update() - roi_id = self.tree_roi.get(tree_iter,0) - self.paramd[roi_id] = RoiParams(roi_image_reader.GetOutput()) - #self.paramd[roi_id].update_pipeline() - #print self.paramd[roi_id].intensity - shared.set_file_selection(fname) - except IOError: - error_msg( - 'Could not load ROI mask from %s' % fname, - ) - finally: - self.__update_treeview_visibility() - else: dialog.destroy() + def cb_add_roi(self,*args): + fname = select_existing_file('Choose filename for ROI mask') + try: + if fname is not None: + self._do_add_roi(fname) + shared.set_file_selection(fname) + except IOError: + error_msg( + 'Could not load ROI mask from %s' % fname, + ) + finally: + self.__update_treeview_visibility() self.render() + def _do_add_roi(self, fname, *args): + self.nroi+=1 + tree_iter = self.tree_roi.append(None) + self.tree_roi.set(tree_iter,0,self.nroi,1,os.path.split(fname)[1],2,fname,3,True) + self.__update_treeview_visibility() + + roi_image_reader = vtkNiftiImageReader() + roi_image_reader.SetFileName(fname) + roi_image_reader.Update() + roi_id = self.tree_roi.get(tree_iter,0) + self.paramd[roi_id] = RoiParams(roi_image_reader, *args) + return roi_id + #self.paramd[roi_id].update_pipeline() + #print self.paramd[roi_id].intensity + def rm_roi(self,*args): treestore,treeiter = self.treev_sel.get_selected() roi_id = treestore.get(treeiter,0) @@ -171,6 +176,75 @@ def rm_roi(self,*args): del self.paramd[roi_id] self.__update_treeview_visibility() self.render() + + def save_rois(self,*args): + if len(self.paramd.keys())==0: + error_msg("Cannot save to file as no ROIs are defined yet.",self.get_toplevel(),title="Not possible" ) + return + + rois = [dict(absolute_path=os.path.abspath(roi.image.GetFilename()), + relative_path=os.path.relpath(roi.image.GetFilename()), + opacity=roi.opacity, color=roi.color) for roi in self.paramd.values()] + + def ok_clicked(w): + fname = dialog.get_filename() + shared.set_file_selection(fname) + try: + persistence.save_rois(rois, fname) + except IOError: + error_msg('Could not save data to %s' % fname, + ) + else: + dialog.destroy() + + dialog = gtk.FileSelection('Choose filename for ROIs') + dialog.set_filename(shared.get_last_dir()) + dialog.ok_button.connect("clicked", ok_clicked) + dialog.cancel_button.connect("clicked", lambda w: dialog.destroy()) + dialog.show() + + def load_rois(self, *args): + filename = select_existing_file("Please choose the file containing ROIs") + if filename is None: + return + rois = persistence.load_rois(filename) + self._precheck_rois_sanity() + self._clear_all_rois() + for roi in rois["Data"]: + if (self._relpath_exists(roi)): + self._do_add_roi(roi["relative_path"], roi["color"], roi["opacity"]) + elif (self._abspath_exists(roi)): + self._do_add_roi(roi["absolute_path"], roi["color"], roi["opacity"]) + else: + error_msg("Cannot load ROIs from file. Path to Nifti is not valid." + \ + "Searched at: \n%s and \n%s" % (roi["relative_path"], roi["absolut_path"]), + self.get_toplevel(),title="Loading failed") + return + self.render() + + def _relpath_exists(self, roi): + path = roi["relative_path"] + return os.path.isfile(path) + + def _abspath_exists(self, roi): + path = roi["absolute_path"] + return os.path.isfile(path) + + def _clear_all_rois(self): + self.tree_roi.clear() + for k in self.paramd.keys(): + self.paramd[k].destroy() + del self.paramd[k] + self.nroi = 0 + + def _precheck_rois_sanity(self): + pass + +# def _set_properties_for_roi(self, roi_id, roi_dict): +# roi = self.paramd[roi_id] +# print "_set_properties_for_roi:", roi.uuid +# roi.set_opacity(roi_dict["opacity"]) +# roi.set_color(roi_dict["color"]) def treev_sel_changed(self,selection): treeiter = selection.get_selected()[1] diff --git a/pylocator/rois.py b/pylocator/rois.py index cb2726f..8f41f95 100644 --- a/pylocator/rois.py +++ b/pylocator/rois.py @@ -3,14 +3,16 @@ from events import EventHandler from surf_params import SurfParams +from shared import shared + class RoiParams(SurfParams): intensity = 0.5 - def __init__(self, imageData, color=None): + def __init__(self, image, color=None, opacity=None): if color==None: color = (0.,0.,1.) - SurfParams.__init__(self, imageData, self.intensity, color) + SurfParams.__init__(self, image, self.intensity, color, opacity) def set_lighting(self): surf_prop = self.isoActor.GetProperty() @@ -19,7 +21,7 @@ def set_lighting(self): surf_prop.SetSpecular(.5) def notify_add_surface(self, pipe): - EventHandler().notify("add roi", self._uuid, pipe, self._color) + EventHandler().notify("add roi", self._uuid, pipe, self._color, self._opacity) def notify_remove_surface(self): EventHandler().notify("remove roi", self._uuid) @@ -108,7 +110,13 @@ def get_color(self): def set_color(self, color): self._color = color + old_color = self.GetProperty().GetColor() self.GetProperty().SetColor(color) + new_color = self.GetProperty().GetColor() + if shared.debug: + print "old_color, color_to_set, new_color:", old_color, color, new_color + + self.update() color = property(get_color, set_color) diff --git a/pylocator/shared.py b/pylocator/shared.py index 536f6ae..c3681f2 100644 --- a/pylocator/shared.py +++ b/pylocator/shared.py @@ -31,7 +31,4 @@ def get_last_dir(self): return os.path.dirname(self.lastSel) + os.sep - - - shared = Shared() diff --git a/pylocator/surf_params.py b/pylocator/surf_params.py index 6bc9bfa..585a5fb 100644 --- a/pylocator/surf_params.py +++ b/pylocator/surf_params.py @@ -17,18 +17,21 @@ class SurfParams(object): useConnect = True useDecimate = False - def __init__(self, imageData, intensity, color=None): - self._uuid = uuid.uuid1() + def __init__(self, image, intensity, color=None, opacity = None): + self.image = image + self._uuid = uuid.uuid4() if intensity!=None: self.intensity = intensity if color==None: color=self.color_ self.set_color(color) + + self.set_opacity(opacity) self.connect = ConnectFilter() self.deci = DecimateFilter() self.marchingCubes = vtk.vtkMarchingCubes() - self.marchingCubes.SetInput(imageData) + self.marchingCubes.SetInput(self.image.GetOutput()) self.output = vtk.vtkPassThrough() @@ -78,7 +81,7 @@ def update_pipeline(self): self.update_properties() def notify_add_surface(self, pipe): - EventHandler().notify("add surface", self._uuid, pipe, self._color) + EventHandler().notify("add surface", self._uuid, pipe, self._color, self._opacity) def notify_remove_surface(self): EventHandler().notify("remove surface", self._uuid) @@ -97,9 +100,9 @@ def update_properties(self): if self.useDecimate: self.deci.update() def update_viewer(self, event, *args): - if event=='set image data': - imageData = args[0] - self.set_image_data(imageData) + if event=='set image': + image = args[0] + self.set_image(image) def __del__(self): self.notify_remove_surface() diff --git a/pylocator/surf_renderer.py b/pylocator/surf_renderer.py index 16bb06b..5c50c99 100644 --- a/pylocator/surf_renderer.py +++ b/pylocator/surf_renderer.py @@ -11,18 +11,19 @@ class SurfRenderWindow(ThreeDimRenderWindow, PyLocatorRenderWindow): picker_id = None - def __init__(self, imageData=None): + def __init__(self, image=None): PyLocatorRenderWindow.__init__(self) ThreeDimRenderWindow.__init__(self) self.surface_actors = {} self.AddObserver('KeyPressEvent', self.key_press) - def set_image_data(self, imageData): - self.imageData = imageData - if imageData is None: return - center = imageData.GetCenter() - #spacing = imageData.GetSpacing() - bounds = imageData.GetBounds() + def set_image(self, image): + self.image = image + if image is None: return + self.imageData = image.GetOutput() + center = self.imageData.GetCenter() + #spacing = self.imageData.GetSpacing() + bounds = self.imageData.GetBounds() pos = center[0], center[1], center[2] - max(bounds)*2 fpu = center, pos, (0,-1,0) self.set_camera(fpu) @@ -41,9 +42,10 @@ def set_labels_visibility(self, visible=True): def set_picker_surface(self, uuid): self.picker_id = uuid - def add_surface(self, uuid, pipe, color): + def add_surface(self, uuid, pipe, color, opacity): isoActor = self._create_actor(pipe) isoActor.GetProperty().SetColor(color) + isoActor.GetProperty().SetOpacity(opacity) self._set_surface_lighting(isoActor) self.surface_actors[uuid] = isoActor if not self.picker_id: diff --git a/pylocator/surf_renderer_props.py b/pylocator/surf_renderer_props.py index f26a6ff..8597d60 100644 --- a/pylocator/surf_renderer_props.py +++ b/pylocator/surf_renderer_props.py @@ -22,7 +22,7 @@ class SurfRendererProps(gtk.VBox): lastColorName = SurfParams.colorName picker_surface_id = None pickerIdx = None - imageData = None + image = None ignore_settings_updates = False paramd = {} # a dict from ids (indices) to SurfParam instances @@ -337,7 +337,7 @@ def add_segment(self, button): self.__update_treeview_visibility() - self.paramd[self.nsurf] = SurfParams(self.imageData, intensity, self.lastColor) + self.paramd[self.nsurf] = SurfParams(self.image, intensity, self.lastColor, 1.0) params = self.paramd[self.nsurf] if self.nsurf==1: self.picker_surface_id = params.uuid @@ -471,11 +471,12 @@ def __update_treeview_visibility(self): self.emptyIndicator.hide() self.treev_surf.show() - def set_image_data(self, data): - self.imageData = data + def set_image(self, image): + self.image = image + self.imageData = self.image.GetOutput() def update_viewer(self, event, *args): - if event=='set image data': - self.set_image_data(args[0]) + if event=='set image': + self.set_image(args[0]) enqueue_update = update_viewer diff --git a/pylocator/vtksurface.py b/pylocator/vtksurface.py index 0019100..581d5a5 100644 --- a/pylocator/vtksurface.py +++ b/pylocator/vtksurface.py @@ -126,7 +126,7 @@ def __init__(self, filename, renderer): renderer.AddActor(self.contours) # XXX: mcc will this work?!? - print "PlaneWidgetsXYZ.set_image_data: setting EventHandler.set_vtkactor(self.contours)!" + print "PlaneWidgetsXYZ.set_image: setting EventHandler.set_vtkactor(self.contours)!" EventHandler().set_vtkactor(self.contours) #writer = vtk.vtkSTLWriter() From 724cefc847644fb59aaea41f26fe0b3dd8d0e858 Mon Sep 17 00:00:00 2001 From: Thorsten Kranz Date: Wed, 10 Apr 2013 01:33:38 +0200 Subject: [PATCH 22/22] Version number changed --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 4573578..d381c36 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -pylocator (1.0) unstable; urgency=low +pylocator (1.5) unstable; urgency=low [ Thorsten Kranz ] * First debian package for PyLocator