Skip to content

Commit 107bc72

Browse files
author
Malte
committed
Established compatibility with the last pythonxy (matplotlib 1.4.3)
plus minor bug fixes and improved performance of marker drawing
1 parent a4cebfe commit 107bc72

File tree

7 files changed

+123
-44
lines changed

7 files changed

+123
-44
lines changed

ebttools/core.py

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,23 @@
4343

4444
import codecs
4545
from collections import OrderedDict
46-
from configparser import ConfigParser
46+
4747
import logging
4848
import numpy as np
4949
import os
5050
import scipy.ndimage
5151
from math import floor, ceil
5252

53+
try:
54+
from configparser import ConfigParser
55+
except ImportError as e:
56+
#a compatibility hack for python2 if it does not have conifgparser
57+
import sys
58+
if sys.version_info[0] == 2:
59+
from ConfigParser import ConfigParser
60+
else:
61+
raise e
62+
5363
#define which array index corresponds to which color
5464
rgbMap = {"red":0,"green":1,"blue":2}
5565

@@ -276,9 +286,9 @@ def rectangle_mask(self,x0, y0, width, height, angle=0.0):
276286
y0 : scalar
277287
y-value of rectangle center (in cm)
278288
width : scalar
279-
width (x-dimension) of the rectangle
289+
half-width (x-dimension) of the rectangle
280290
height : scalar
281-
height (y-dimension) of the rectangle
291+
half-height (y-dimension) of the rectangle
282292
angle : scalar, optional
283293
counter clockwise rotation angle of the rectangle
284294
test : bool, optional
@@ -287,7 +297,7 @@ def rectangle_mask(self,x0, y0, width, height, angle=0.0):
287297
Returns
288298
-------
289299
mask : ndarray
290-
a mask to index the array an return a rectangular area
300+
a mask to index the array and return a rectangular area
291301
"""
292302

293303
angle_rad = angle*np.pi/180.
@@ -298,7 +308,8 @@ def rectangle_mask(self,x0, y0, width, height, angle=0.0):
298308
#must be shifted by 0.5 pixels width.
299309
y, x = np.mgrid[-y0+0.5/self.DPC:(self.shape[0]+.5)/self.DPC-y0:1.0/self.DPC,
300310
-x0+0.5/self.DPC:(self.shape[1]+.5)/self.DPC-x0:1.0/self.DPC]
301-
311+
312+
302313
#condition for a rectangle
303314
mask = np.logical_and(np.abs(x*np.cos(angle_rad)-y*np.sin(angle_rad)) <= width,
304315
np.abs(x*np.sin(angle_rad)+y*np.cos(angle_rad)) <= height)
@@ -318,9 +329,9 @@ def rectangle_stats(self,x0, y0, width, height, angle=0.0, test=False):
318329
y0 : scalar
319330
y-value of rectangle center (in cm)
320331
width : scalar
321-
width (x-dimension) of the rectangle
332+
half-width (x-dimension) of the rectangle
322333
height : scalar
323-
height (y-dimension) of the rectangle
334+
half-height (y-dimension) of the rectangle
324335
angle : scalar, optional
325336
counter clockwise rotation angle of the rectangle
326337
test : bool, optional
@@ -459,7 +470,7 @@ def profile(self, x0, y0, x1, y1, interpolation="nearest",test=False):
459470
# for testing
460471
if __name__ == '__main__':
461472
#load some calibrations
462-
calibs = load_calibrations(os.path.join(os.path.curdir,"Calibration"))
473+
calibs = load_calibrations(os.path.join(os.path.abspath(os.path.curdir),"calibrations"))
463474
#create a simple scan (~4x4 cm)
464475
scan = np.zeros((470,470,3),dtype="uint8")
465476

@@ -471,6 +482,8 @@ def profile(self, x0, y0, x1, y1, interpolation="nearest",test=False):
471482

472483
doseDistribution = DoseArray(300.,calibs["example"],scan,255)
473484

485+
doseDistribution.rectangle_stats(1.0,1.0,0.5,0.5,0.,True)
486+
474487
mask = doseDistribution.rectangle_mask(0.4,0.5,0.2,0.1,0.0)
475488
print (doseDistribution[mask].shape)
476489

ebttools/gui/dosewidget.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,12 @@ def __call__(self, x, pos=None):
8282
def gauss(x, A, x0, sigma, offset):
8383
return A*np.exp(-np.square(x-x0)/(2*sigma**2))+offset
8484

85-
#define possibilities for color maps and check their availability on
86-
#the current installation
85+
#define possibilities for color maps and filter for their availability
86+
#on the current installation
8787
colorMapChoices = ["inferno","viridis","hot","gnuplot","spectral","jet",
8888
"rainbow","gray","seismic"]
8989

90-
for cmap in colorMapChoices:
91-
if cmap not in colormaps():
92-
colorMapChoices.remove(cmap)
90+
colorMapChoices = [cmap for cmap in colorMapChoices if cmap in colormaps()]
9391

9492
_advSettings = EasyEditSettings([("area stat linecolor","red"),
9593
("area stat linewidth",2.0),
@@ -732,7 +730,6 @@ def click_to_pos1(self, event):
732730
#catch if the focus leaves or enters a certain widget and connect matplotlib
733731
#button press callbacks accordingly
734732
def focus_change(self, old, new):
735-
736733
if (old == self.ui.xCenter or old == self.ui.yCenter or
737734
old == self.ui.x0 or old == self.ui.y0 or
738735
old == self.ui.x1 or old == self.ui.y1):

ebttools/gui/main.py

Lines changed: 64 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ def create_mplframe(self):
186186
def load_settings(self):
187187
"""load the setting of the GUI (called on startup)
188188
"""
189-
#create a QSettings object from ini file
189+
#create a QSettings object to store the settings
190190
self.QtSettings=QtCore.QSettings("OncoRay","EBT Evaluation")
191191
#self.QtSettings=QtCore.QSettings("settings.ini",QtCore.QSettings.IniFormat)
192192

@@ -397,7 +397,6 @@ def image_path_changed(self):
397397
except (IOError, OSError) as e:
398398
logging.error("failed to open file: "+str(e))
399399
return ()
400-
401400

402401
#check the format of the loaded image and adjust the input field accordingly
403402
logging.debug("image mode: "+img.mode)
@@ -448,9 +447,52 @@ def image_path_changed(self):
448447

449448

450449

450+
451+
452+
#check for dpi info
453+
try:
454+
dpi = img.info['dpi']
455+
456+
#try string conversion and tuple first and then deal with type of number
457+
if type(dpi) == str:
458+
try:
459+
dpi = float(dpi)
460+
except ValueError:
461+
logging.warning("Can not parse dpi info: "+dpi)
462+
dpi = 0
463+
elif type(dpi) == tuple:
464+
if len(dpi) == 1:
465+
dpi = dpi[0]
466+
elif len(dpi) == 2:
467+
if dpi[0] == dpi[1]:
468+
dpi = dpi[0]
469+
else:
470+
logging.warning("different DPI for the two dimensions found " +
471+
repr(dpi)+ " THIS IS NOT SUPPORTED")
472+
dpi = 0
473+
else:
474+
logging.warning("dpi has more than 2 dimensions" +
475+
repr(dpi)+ " DONT KNOW WHAT TO DO")
476+
dpi=0
477+
478+
try:
479+
dpi = float(dpi)
480+
if not dpi.is_integer():
481+
logging.warning("non integer DPI of {:.4f} is not supported".format(dpi))
482+
except TypeError: #unkown type of dpi
483+
logging.warning("Can not parse dpi info: "+repr(dpi))
484+
dpi = 0
485+
except KeyError:
486+
logging.debug("no dpi info")
487+
dpi=0
488+
451489
logging.debug("loaded image of dimensions: "+str(self.npImg.shape)+
452-
" and type: "+str(self.npImg.dtype))
453-
490+
" and type: "+str(self.npImg.dtype)+
491+
", with DPI: "+str(dpi))
492+
493+
if dpi > 0:
494+
self.ui.DPI.setValue(int(dpi))
495+
454496
#adjust UI elements to image properties
455497
self.ui.x0.setMaximum(self.npImg.shape[1])
456498
self.ui.x0.setValue(0)
@@ -522,20 +564,26 @@ def save_table_path_changed(self):
522564
self.saveTablePath = self.check_save_table_path(self.ui.saveTablePath.text())
523565

524566
def selection_changed(self):
525-
#try to remove old marker
567+
#the point here is to redraw the marker as efficiently as possible, i.e.
568+
#change as little of the existing plot as possible
569+
570+
#try to update the old marker
526571
try:
527-
self.selectionMarker.remove()
572+
self.selectionMarker.set_bounds(self.ui.x0.value(),self.ui.y0.value(),
573+
self.ui.x1.value()-self.ui.x0.value(),
574+
self.ui.y1.value()-self.ui.y0.value())
575+
self.subplot.draw_artist(self.selectionMarker)
528576
except AttributeError:
529-
pass
530-
531-
#create a rectangle marker and draw it
532-
rect = Rectangle((self.ui.x0.value(),self.ui.y0.value()),
533-
self.ui.x1.value()-self.ui.x0.value(),
534-
self.ui.y1.value()-self.ui.y0.value(),
535-
fill=False,color=self.settings["selection rectangle"],
536-
linewidth=2.0)
537-
self.selectionMarker = self.subplot.add_artist(rect)
538-
self.canvas.draw()
577+
#marker does not exist, create a new rectangle marker and draw it
578+
rect = Rectangle((self.ui.x0.value(),self.ui.y0.value()),
579+
self.ui.x1.value()-self.ui.x0.value(),
580+
self.ui.y1.value()-self.ui.y0.value(),
581+
fill=False,color=self.settings["selection rectangle"],
582+
linewidth=2.0)
583+
self.selectionMarker = self.subplot.add_artist(rect)
584+
585+
self.canvas.draw()
586+
self.canvas.flush_events()
539587

540588
def show_dose(self):
541589
logging.debug("calculating dose")

ebttools/gui/navtoolbar.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,16 @@
2727

2828

2929
from matplotlib import rcParams as mplParams
30-
from matplotlib.backend_tools import Cursors
30+
from matplotlib import __version__ as mplVersion
31+
32+
mplAbove1_5 = not ((int(mplVersion.split(".")[0]) < 2) and
33+
(int(mplVersion.split(".")[1]) < 5))
34+
35+
#in older matplotlib (<2 I believe) Cursors is in backend_bases, not it is in backend tools
36+
try:
37+
from matplotlib.backend_tools import Cursors
38+
except:
39+
from matplotlib.backend_bases import Cursors
3140
cursors = Cursors()
3241

3342
class MyNavigationToolbar(NavigationToolbar2QT):
@@ -210,10 +219,14 @@ def selection_released(self, event):
210219
for selection_id in self._ids_selection:
211220
self.canvas.mpl_disconnect(selection_id)
212221
self.release(event)
213-
self.draw()
222+
if mplAbove1_5:
223+
self.remove_rubberband()
224+
214225
self._selectionStart = None
215226
self._button_pressed = None
216227
self._ids_selection = []
217228

229+
230+
218231
#fire event
219232
self.canvas.callbacks.process("selection_changed")

run.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
#! /bin/python
22
# -*- coding: utf-8 -*-
33
"""
4-
Created on Sat Aug 12 21:02:24 2017
5-
6-
@author: Malte
4+
Use this script to execute the EBT evaluation GUI
75
"""
86

97
import os
108
import sys
119

12-
sys.path.append(os.path.dirname(__file__))
10+
sys.path.insert(0,(os.path.dirname(__file__)))
1311

1412
from ebttools.gui.main import run
1513

setup.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,23 @@
44
setup script for ebttools
55
"""
66
import os
7-
from setuptools import setup, find_packages
7+
from setuptools import setup, find_packages, __version__
8+
9+
#check to have setuptools > v36.2
10+
version = __version__.split(".")
11+
if len(version) < 2:
12+
raise ImportError("unkown version of setuptools, please update")
13+
if int(version[0]) < 36 or (int(version[0]) == 36 and int(version[1]) < 2):
14+
raise ImportError("setuptools version "+ __version__ +" too low, needs at least 36.2")
15+
816

917
def read(fname):
1018
return open(os.path.join(os.path.dirname(__file__), fname)).read()
1119

1220

1321
setup(
1422
name='ebttools',
15-
version='1.0.0',
23+
version='1.1.0',
1624

1725
packages=find_packages(exclude=("tests")), #automagically include all subfolders as packages, but don't install the tests
1826
package_data = {"":["*.png"],
@@ -25,10 +33,10 @@ def read(fname):
2533
author_email='[email protected]',
2634
url='https://github.com/mgotz/EBT_evalution',
2735

28-
install_requires=['matplotlib',
29-
'scipy',
30-
'numpy',
31-
'pillow',
36+
install_requires=['matplotlib>=1.4.3',
37+
'scipy>=0.15.1',
38+
'numpy>=1.9.2',
39+
'pillow>=2.8.2',
3240
'configparser;python_version<"3.2"',
3341
'mg_dataprocessing>=1.0.0',
3442
'mg_pyguitools>=1.1.1'],

tests/dosewidget_test.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
import os
1414
import sys
1515

16+
os.environ["QT_API"] = "pyqt5"
17+
1618
#add base to path and load
1719
sys.path.append(os.path.join(sys.path[0],".."))
1820
from ebttools.gui.dosewidget import DoseWidget
@@ -45,8 +47,8 @@ def __init__(self):
4547
self.ui = Ui_MainWindow()
4648
self.ui.setupUi(self)
4749

48-
xDim = 4000
49-
yDim = 4000
50+
xDim = 470
51+
yDim = 470
5052

5153
#create a noise gaussian for test data
5254
x,y = np.meshgrid(np.linspace(0,xDim,yDim),np.linspace(0,xDim,yDim))

0 commit comments

Comments
 (0)