Skip to content

Commit

Permalink
BoundingBoxes.to_ascii_file + bugfix in NonTrackingTracker.track for …
Browse files Browse the repository at this point in the history
…raw dataframes + source argument in Tracker.track + roi.utils.{epanechnikov_density,density_based_roi}
  • Loading branch information
francoislaurent committed Dec 14, 2020
1 parent 8b107b3 commit 3686701
Show file tree
Hide file tree
Showing 19 changed files with 328 additions and 55 deletions.
19 changes: 0 additions & 19 deletions doc/tramway.analyzer.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ tramway.analyzer package

.. automodule:: tramway.analyzer
:members:
:undoc-members:
:show-inheritance:
:member-order: bysource

Expand All @@ -14,7 +13,6 @@ tramway.analyzer.artefact package

.. automodule:: tramway.analyzer.artefact
:members:
:undoc-members:
:show-inheritance:


Expand All @@ -23,7 +21,6 @@ tramway.analyzer.attribute package

.. automodule:: tramway.analyzer.attribute
:members:
:undoc-members:
:show-inheritance:


Expand All @@ -32,7 +29,6 @@ tramway.analyzer.images package

.. automodule:: tramway.analyzer.images
:members:
:undoc-members:
:show-inheritance:
:private-members: _RawImage

Expand All @@ -59,7 +55,6 @@ tramway.analyzer.tracker package

.. automodule:: tramway.analyzer.tracker
:members:
:undoc-members:
:show-inheritance:
:member-order: bysource

Expand All @@ -69,7 +64,6 @@ tramway.analyzer.spt_data package

.. automodule:: tramway.analyzer.spt_data
:members:
:undoc-members:
:show-inheritance:
:private-members: _SPTDataFrame

Expand All @@ -87,7 +81,6 @@ tramway.analyzer.roi package

.. automodule:: tramway.analyzer.roi
:members:
:undoc-members:
:show-inheritance:
:member-order: bysource

Expand All @@ -97,7 +90,6 @@ tramway.analyzer.tesseller package

.. automodule:: tramway.analyzer.tesseller
:members:
:undoc-members:
:show-inheritance:
:member-order: bysource

Expand All @@ -107,7 +99,6 @@ tramway.analyzer.tesseller.proxy module

.. automodule:: tramway.analyzer.tesseller.proxy
:members:
:undoc-members:
:show-inheritance:


Expand All @@ -119,7 +110,6 @@ as *tessellers*.

.. automodule:: tramway.analyzer.tesseller.proxied
:members:
:undoc-members:
:show-inheritance:


Expand All @@ -128,7 +118,6 @@ tramway.analyzer.tesseller.plugin module

.. automodule:: tramway.analyzer.tesseller.plugin
:members:
:undoc-members:
:show-inheritance:


Expand All @@ -148,7 +137,6 @@ as *cell_mergers*.

.. automodule:: tramway.analyzer.tesseller.post.merger
:members:
:undoc-members:
:show-inheritance:


Expand All @@ -165,7 +153,6 @@ tramway.analyzer.time package

.. automodule:: tramway.analyzer.time
:members:
:undoc-members:
:show-inheritance:
:member-order: bysource

Expand All @@ -175,7 +162,6 @@ tramway.analyzer.sampler package

.. automodule:: tramway.analyzer.sampler
:members:
:undoc-members:
:show-inheritance:
:member-order: bysource

Expand All @@ -185,7 +171,6 @@ tramway.analyzer.mapper package

.. automodule:: tramway.analyzer.mapper
:members:
:undoc-members:
:show-inheritance:
:member-order: bysource

Expand All @@ -203,7 +188,6 @@ tramway.analyzer.pipeline package

.. automodule:: tramway.analyzer.pipeline
:members:
:undoc-members:
:show-inheritance:


Expand All @@ -212,7 +196,6 @@ tramway.analyzer.env package

.. automodule:: tramway.analyzer.env
:members:
:undoc-members:
:show-inheritance:
:member-order: bysource

Expand All @@ -225,7 +208,6 @@ as *environments*.

.. automodule:: tramway.analyzer.env.environments
:members:
:undoc-members:
:show-inheritance:


Expand All @@ -234,6 +216,5 @@ tramway.analyzer.browser package

.. automodule:: tramway.analyzer.browser
:members:
:undoc-members:
:show-inheritance:

34 changes: 26 additions & 8 deletions tests/test_analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import os
from math import *
import numpy
import pandas
import random
import subprocess
import pytest
Expand Down Expand Up @@ -249,17 +250,17 @@ def test_3roi_hexagons(self, one_sptdatafile, tmpdir):
self.tmpdir = tmpdir
self.label = '3roi_hexagons'
#
roi = [([-.4,-.5],[0.,-.1]),([-.1,0.],[.3,.4]),([.1,-.3],[.5,.1])]
roi = [ (numpy.array(lb), numpy.array(ub)) for lb, ub in roi ]
roi_bounds = [([-.4,-.5],[0.,-.1]),([-.1,0.],[.3,.4]),([.1,-.3],[.5,.1])]
roi_bounds = [ (numpy.array(lb), numpy.array(ub)) for lb, ub in roi_bounds ]
#
a=RWAnalyzer()
a.spt_data.from_ascii_file(one_sptdatafile)
a.tesseller.from_callable(tessellers.Hexagons)
a.tesseller.ref_distance = .01
a.tesseller.avg_location_count = 5
a.roi.from_bounding_boxes(roi, label='3-roi hexagons', group_overlapping_roi=True)
a.roi.from_bounding_boxes(roi_bounds, label='3-roi hexagons', group_overlapping_roi=True)
b = RoiHelper(one_sptdatafile, verbose=False)
b.set_bounding_boxes(roi, collection_label='3-roi hexagons')
b.set_bounding_boxes(roi_bounds, collection_label='3-roi hexagons')
b.tessellate('hexagon', ref_distance=.01, avg_location_count=5)
for i, r in enumerate(a.roi.as_support_regions()):
df = r.crop()
Expand Down Expand Up @@ -416,8 +417,8 @@ def test_nooverlap_roi(self, dynamicmesh):
a=RWAnalyzer()
a.spt_data.from_ascii_file(dynamicmesh)
a.spt_data.localization_precision = 1e-4
roi = [[.2,-.1],[-.3,.3],[0.,.1],[-.2,-0.]]
a.roi.from_squares(np.array(roi), .2, group_overlapping_roi=False)
roi_centers = [[.2,-.1],[-.3,.3],[0.,.1],[-.2,-0.]]
a.roi.from_squares(np.array(roi_centers), .2, group_overlapping_roi=False)
#
for i, r in a.roi.as_individual_roi(index=1, return_index=True):
assert i == 1
Expand Down Expand Up @@ -454,8 +455,8 @@ def test_overlapping_roi(self, dynamicmesh):
a=RWAnalyzer()
a.spt_data.from_ascii_file(dynamicmesh)
a.spt_data.localization_precision = 1e-4
roi = [[.2,-.1],[-.3,.3],[0.,.1],[-.2,-0.]]
a.roi.from_squares(np.array(roi), .2, group_overlapping_roi=True)
roi_centers = [[.2,-.1],[-.3,.3],[0.,.1],[-.2,-0.]]
a.roi.from_squares(np.array(roi_centers), .2, group_overlapping_roi=True)
#
j = 0
for i,r in a.roi.as_individual_roi(return_index=True):
Expand Down Expand Up @@ -567,3 +568,20 @@ def test_init_for_misplaced_attributes(self):
else:
assert attr is not attr # could set the attribute before initializing its parent


class TestSideEffects(object):
def test_attribute_overwrite(self):
warnings.simplefilter('ignore', SideEffectWarning)
a = RWAnalyzer()
a.spt_data.from_dataframe(pandas.DataFrame([], columns=list('xyt')))
a.spt_data.localization_precision = .03
a.spt_data.frame_interval = .05
a.time.frame_interval = .04
old_spt_data = a.spt_data
a.spt_data = spt_data.from_dataframe(pandas.DataFrame([], columns=list('xyt')))
a.spt_data.localization_error = old_spt_data.localization_error
a.spt_data.dt = old_spt_data.dt
assert a.spt_data.localization_precision == .03
assert a.spt_data.dt == .04
warnings.simplefilter('error', SideEffectWarning)

46 changes: 37 additions & 9 deletions tramway/analyzer/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@
# knowledge of the CeCILL license and that you accept its terms.


from tramway.core.exceptions import MisplacedAttributeWarning
from warnings import warn
from tramway.core.exceptions import MisplacedAttributeWarning, SideEffectWarning
import warnings
import logging

def report_misplaced_attribute(attr_name, proper_parent_name):
warn('`{}` is an attribute of the initialized `{}` attribute; this warning message can safely be silenced'.format(attr_name, proper_parent_name), MisplacedAttributeWarning)
warnings.warn('`{}` is an attribute of the initialized `{}` attribute; this warning message can safely be silenced'.format(attr_name, proper_parent_name), MisplacedAttributeWarning)
def proper_parent_name(attr_name):
parent_name = None
get_conditions, set_conditions = {}, {}
Expand All @@ -29,6 +29,9 @@ def proper_parent_name(attr_name):
parent_name = 'tesseller'
return parent_name, get_conditions, set_conditions

warnings.filterwarnings('error', category=SideEffectWarning)


from .attribute import *
from .artefact import *
from .spt_data import *
Expand All @@ -44,6 +47,15 @@ def proper_parent_name(attr_name):
from .localizer import *
from .tracker import *

import tramway.analyzer.spt_data.allsymbols as spt_data
import tramway.analyzer.roi.allsymbols as roi
import tramway.analyzer.time.allsymbols as time
import tramway.analyzer.tesseller.allsymbols as tesseller
import tramway.analyzer.sampler.allsymbols as sampler
import tramway.analyzer.mapper.allsymbols as mapper
import tramway.analyzer.images.allsymbols as images
import tramway.analyzer.tracker.allsymbols as tracker


class BasicLogger(object):
"""
Expand Down Expand Up @@ -434,11 +446,22 @@ def __setattr__(self, attrname, obj):
attrname in ('script',):
object.__setattr__(self, attrname, obj)
elif callable(obj):
attr = getattr(self, attrname)
try:
attr.from_callable(obj)
except AttributeError:
raise AttributeError('attribute is read-only')
if attrname[0] != '_' and isinstance(obj, InitializerMethod):
attr = getattr(self, attrname)
if isinstance(attr, Initializer):
obj.assign( self )
else:
warnings.warn(
"attribute '{}' is already initialized; side effects may occur".format(
attrname),
SideEffectWarning)
obj.reassign( self )
else:
attr = getattr(self, attrname)
try:
attr.from_callable(obj)
except AttributeError:
raise AttributeError('attribute is read-only')
else:
parent_name, _, set_conditions = proper_parent_name(attrname)
if parent_name is None:
Expand All @@ -461,8 +484,13 @@ def __getattr__(self, attrname):


__all__ = ['RWAnalyzer',
'spt_data', 'roi',
'time', 'tesseller', 'sampler',
'mapper',
'images', 'tracker',
'tessellers', 'cell_mergers',
'Analysis', 'commit_as_analysis',
'environments',
'first', 'single']
'first', 'single',
'SideEffectWarning']

38 changes: 38 additions & 0 deletions tramway/analyzer/attribute/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ def initializer(self, cls):
if cls is None:
setter(self, None)
elif callable(cls):
if isinstance(cls, InitializerMethod):
cls.assign( self )
return
if metacls:
def typechecked_setter(obj):
if not isinstance(obj, metacls):
Expand Down Expand Up @@ -235,3 +238,38 @@ def __setattr__(self, attrname, val):
setattr(self._proxied, attrname, val)


__all__.append('InitializerMethod')
class InitializerMethod(object):
"""
Useful for explicit typing.
"""
__slots__ = ('attrname', 'method', 'args', 'kwargs')
def __init__(self, method, attrname=None):
self.method = method
if attrname is None:
attrname = method.__module__.split('.')[-1]
self.attrname = attrname
self.args = self.kwargs = None
def __call__(self, *args, **kwargs):
self.args = args
self.kwargs = kwargs
return self
def assign(self, parent_analyzer):
if not (isinstance(self.args, tuple) and isinstance(self.kwargs, dict)):
raise RuntimeError('initializer method has not been called')
parent_attribute = getattr(parent_analyzer, self.attrname)
self.method(parent_attribute, *self.args, **self.kwargs)
def reassign(self, parent_analyzer):
import importlib
mod = importlib.import_module(self.method.__module__)
try:
clsname = str(self.method)[::-1].split('.', 1)[-1][::-1].split()[-1]
cls = getattr(mod, clsname)
assert isinstance(cls, type) and issubclass(cls, Initializer)
except:
raise AttributeError("cannot find a proper initializer for the '{}' attribute".format(self.attrname))
attr = getattr(type(parent_analyzer), self.attrname)
# TODO: add a freset method to the properties returned by selfinitializing_property
attr.fset(parent_analyzer, cls)
self.assign( parent_analyzer )

2 changes: 1 addition & 1 deletion tramway/analyzer/env/environments.py
Original file line number Diff line number Diff line change
Expand Up @@ -1347,7 +1347,7 @@ def wait_for_job_completion(self):
if _continue:
continue
if start is None:
total = pending = None
total, pending = None, 0
else:
total = stop
pending = stop - start
Expand Down
7 changes: 7 additions & 0 deletions tramway/analyzer/images/allsymbols.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

from . import *
from ..attribute import InitializerMethod

from_tiff_file = InitializerMethod( ImagesInitializer.from_tiff_file )
from_tiff_files = InitializerMethod( ImagesInitializer.from_tiff_files )

7 changes: 7 additions & 0 deletions tramway/analyzer/mapper/allsymbols.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

from . import *
from ..attribute import InitializerMethod

from_plugin = InitializerMethod( MapperInitializer.from_plugin )
from_callable = InitializerMethod( MapperInitializer.from_callable )

0 comments on commit 3686701

Please sign in to comment.