Skip to content

Commit

Permalink
- Added TestPickerModel(default picker model) and TestPickFilModel(fi…
Browse files Browse the repository at this point in the history
…lament model) for test

- Tested default picking and filament pincking
- Fixed errors from datavis picker model refactoring
  • Loading branch information
pedrohv committed Apr 3, 2020
1 parent c94bb84 commit bae1268
Show file tree
Hide file tree
Showing 10 changed files with 272 additions and 158 deletions.
1 change: 1 addition & 0 deletions emvis/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@
from . import utils
from . import models
from . import views
from . import tests
16 changes: 10 additions & 6 deletions emvis/models/_empicker.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,15 +188,19 @@ def getParams(self):
[scoreThreshold, useColor]
])

def changeParam(self, micId, paramName, paramValue, getValuesFunc):
def onParamChanged(self, micId, paramName, paramValues):
# Most cases here will modify the current coordinates
r = self.Result(currentCoordsChanged=True, tableModelChanged=True)
d = {'micId': micId,
'currentCoordsChanged': True,
'tableModelChanged': True}
n = True

if paramName == 'scoreThreshold':
self._scoreThreshold = getValuesFunc()['scoreThreshold']
self._scoreThreshold = paramValues['scoreThreshold']
elif paramName == 'useColor':
self._useColor = getValuesFunc()['useColor']
self._useColor = paramValues['useColor']
else:
r = self.Result() # No modification
n = False # No modification

return r
if n:
self.notifyEvent(type=dv.models.PICK_EVT_DATA_CHANGED, info=d)
3 changes: 2 additions & 1 deletion emvis/models/_emtable_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ def __init__(self, tableSource, **kwargs):
* string: This should be the path from where to read
the table(s). The first table will be loaded by default.
* tuple (string, string): Here you can specify the path and
the name of the table that you want to be loaded by default.
the name of the table that you want to be loaded by
default.
Keyword Arguments:
imageManager=value Provide an ImageManager that can be used
Expand Down
2 changes: 2 additions & 0 deletions emvis/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

from .test_common import TestPickerModel, TestPickFilModel
208 changes: 208 additions & 0 deletions emvis/tests/test_common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@

import os
from random import randint

import datavis as dv
import emvis.models as em_models

class TestPickerModel(em_models.EmPickerModel):
""" Em picker data model with direct access to ImageManager """

def __init__(self, inputDir, coordDir, imageManager=None):
"""
Create a new instance of :class:`~TestPickerModel`.
Args:
inputDir: Directory with the resulting picking dir
imageManager: optional :class:`~emvis.utils.ImageManager` class to
read micrographs from disk.
"""
em_models.EmPickerModel.__init__(self, imageManager=imageManager)
self._inputDir = inputDir
self._coordDir = coordDir
self._scoreThreshold = 0.0
self._useColor = False

self._loadData()

def _parseEmPickCoordinates(self, path):
""" Parse (x, y) coordinates from a text file assuming
that the first two columns on each line are x and y.
Other specifications can be:
- x y label
- x1 y1 width height
- x1 y1 width height label
"""
with open(path) as f:
Coord = dv.models.Coordinate
index = 0
for line in f:
li = line.strip()
index += 1
t = randint(0, 10) # FIXME[hv] use random threshold
if li:
parts = li.strip().split()
size = len(parts)
if size == 2 or size == 4: # (x, y) or (x1,y1,width,height)
yield Coord(int(parts[0]), int(parts[1]), "",
threshold=t)
elif size == 3: # (x, y, label)
yield Coord(int(parts[0]), int(parts[1]), str(parts[2]),
threshold=t)
elif size == 5: # (x1, y1, width, height, label):
yield Coord(int(parts[0]), int(parts[1]), str(parts[4]),
threshold=t)
else:
raise Exception(
"Unsupported coordinate specification:\n"
"path: %s" % path % "line: %d" % index)

def _initLabels(self):
""" Initialize the labels for this PickerModel. """
colors = [
"#1EFF00",
"#DD0014"
]
for i, c in enumerate(colors):
name = str(i)
self._labels[name] = self.Label(name=name, color=c)
self._labels['D'] = self._labels['0']

def _input(self, filename):
return os.path.join(self._inputDir, filename)

def _coord(self, filename):
return os.path.join(self._coordDir, filename)

def _loadData(self):
self._loadedMics = set()

if not os.path.exists(self._inputDir):
raise Exception("Expecting directory '%s'" % self._inputDir)

if not os.path.exists(self._coordDir):
raise Exception("Expecting directory '%s'" % self._coordDir)

micId = 0
for micName in os.listdir(self._inputDir):
micId += 1
mic = dv.models.Micrograph(micId=micId, path=self._input(micName))
self.addMicrograph(mic)
self.beginReadCoordinates(micId)

def readCoordinates(self, micId):
if not micId in self._loadedMics:
self._loadedMics.add(micId)
mic = self.getMicrograph(micId)
micName = os.path.split(mic.getPath())[-1]
coordPath = self._coord(os.path.splitext(micName)[0] + '.box')

if os.path.exists(coordPath):
return self._parseEmPickCoordinates(coordPath)
return []

def createCoordinate(self, x, y, label, **kwargs):
"""
Return a Coordinate object. This is the preferred way to create
Coordinates objects, ensuring that the object contains all
the additional properties related to the model.
Subclasses should implement this method
"""
return dv.models.Coordinate(x, y, 'M', threshold=1, **kwargs)

def iterCoordinates(self, micId):
# Re-implement this to show only these above the threshold
# or with a different color (label)
for coord in self._getCoordsList(micId):
good = coord.threshold > self._scoreThreshold
coord.label = '0' if good else '1'
if good or self._useColor:
yield coord

def getColumns(self):
""" Return a Column list that will be used to display micrographs. """
return [
dv.models.ColumnConfig('Micrograph', dataType=dv.models.TYPE_STRING,
editable=False),
dv.models.ColumnConfig('Coordinates', dataType=dv.models.TYPE_INT,
editable=False),
dv.models.ColumnConfig('Id', dataType=dv.models.TYPE_INT,
editable=False, visible=False),
]

def getValue(self, row, col):
""" Return the value in this (row, column) from the micrographs table.
"""
mic = self.getMicrographByIndex(row)

if col == 0: # Name
return os.path.basename(mic.getPath())
elif col == 1: # Coordinates
# Use real coordinates number for already loaded micrographs
return len(mic)
elif col == 2: # Id
return mic.getId()
else:
raise Exception("Invalid column value '%s'" % col)

def getParams(self):
Param = dv.models.Param
scoreThreshold = Param('scoreThreshold', 'int', value=5,
display='slider', range=(0, 10),
label='Score threshold',
help='Display coordinates with score above '
'this value.')

useColor = Param('useColor', 'bool', value=self._useColor,
label='Color coordinates \nwith score above?')

return dv.models.Form([
[scoreThreshold, useColor]
])

def onParamChanged(self, micId, paramName, paramValues):
# Most cases here will modify the current coordinates
d = {'micId': micId,
'currentCoordsChanged': True,
'tableModelChanged': True}
n = True

if paramName == 'scoreThreshold':
self._scoreThreshold = paramValues['scoreThreshold']
elif paramName == 'useColor':
self._useColor = paramValues['useColor']
else:
n = False # No modification

if n:
self.notifyEvent(type=dv.models.PICK_EVT_DATA_CHANGED, info=d)


class TestPickFilModel(TestPickerModel):

def _parseEmPickCoordinates(self, path):
""" Parse (x1, y1, x2, y2) coordinates from a text file assuming
that the first four columns on each line are x1, y1, x2, y2.
Other specifications can be:
- x1 y1 x2 y2 label
"""
with open(path) as f:
Coord = dv.models.Coordinate
index = 0
for line in f:
li = line.strip()
index += 1
t = randint(0, 10) # FIXME[hv] use random threshold
if li:
parts = li.strip().split()
size = len(parts)
if size == 4: # (x1, y1, x2, y2)
yield Coord(int(parts[0]), int(parts[1]), "",
threshold=t, x2=parts[2], y2=parts[3])
elif size == 5: # (x1, y1, x2, y2, label):
yield Coord(int(parts[0]), int(parts[1]), str(parts[4]),
threshold=t, x2=parts[2], y2=parts[3])
else:
raise Exception(
"Unsupported coordinate specification:\n"
"path: %s" % path % "line: %d" % index)
113 changes: 32 additions & 81 deletions emvis/tests/test_dualimagelistview.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,92 +16,43 @@ def getDataPaths(self):
]

def createView(self):
tool_params1 = [
[
{
'name': 'threshold',
'type': 'float',
'value': 0.55,
'label': 'Quality threshold',
'help': 'If this is ... bla bla bla',
'display': 'default'
},
{
'name': 'thresholdBool',
'type': 'bool',
'value': True,
'label': 'Quality checked',
'help': 'If this is a boolean param'
}
],
[
{
'name': 'threshold543',
'type': 'float',
'value': 0.67,
'label': 'Quality',
'help': 'If this is ... bla bla bla',
'display': 'default'
},
{
'name': 'threshold',
'type': 'float',
'value': 14.55,
'label': 'Quality threshold2',
'help': 'If this is ... bla bla bla',
'display': 'default'
}
],
{
'name': 'threshold2',
'type': 'string',
'value': 'Explanation text',
'label': 'Threshold ex',
'help': 'If this is ... bla bla bla 2',
'display': 'default'
},
{
'name': 'text',
'type': 'string',
'value': 'Text example',
'label': 'Text',
'help': 'If this is ... bla bla bla for text'
},
{
'name': 'threshold4',
'type': 'float',
'value': 1.5,
'label': 'Quality',
'help': 'If this is ... bla bla bla for quality'
},
{
'name': 'picking-method',
'type': 'enum', # or 'int' or 'string' or 'enum',
'choices': ['LoG', 'Swarm', 'SVM'],
'value': 1, # values in enum are int, in this case it is 'LoG'
'label': 'Picking method',
'help': 'Select the picking strategy that you want to use. ',
# display should be optional, for most params, a textbox is the
# default
# for enum, a combobox is the default, other options could be
# sliders
'display': 'combo' # or 'combo' or 'vlist' or 'hlist' or
# 'slider'
},
{
'name': 'threshold3',
'type': 'bool',
'value': True,
'label': 'Checked',
'help': 'If this is a boolean param'
}
]
Param = dv.models.Param
brightness = Param('brightness', 'int', value=50, display='slider',
range=(1, 100), label='Brightness',
help='Adjust image brightness.')

threshold = Param('threshold', 'float', value=0.55,
label='Quality threshold',
help='If this is...bla bla bla')
thresholdBool = Param('threshold', 'bool', value=True,
label='Quality checked',
help='If this is a boolean param')

threshold5 = Param('threshold5', 'string', value='Another text',
label='Another text example',
help='Showing more text')

threshold6 = Param('threshold6', 'float', value=1.5,
label='Another float',
help='Just another float example')

apply = Param('apply', 'button', label='Operation1')

form = dv.models.Form([
brightness,
[threshold, thresholdBool],
threshold5,
threshold6,
[apply]
])

return dv.views.DualImageListView(
emv.models.ModelsFactory.createListModel(self.getDataPaths()),
options=tool_params1, method=printFunc)
form=form, method=printFunc)


def printFunc(*args):
print('Example function. Print the arguments:')
print(args)


Expand Down
Loading

0 comments on commit bae1268

Please sign in to comment.