Skip to content

Commit

Permalink
LMT-analysis v1.0.3 implemented: fixes #10, closes #10
Browse files Browse the repository at this point in the history
- Event "approach contact" corrected
- Events "follow zone" and "side walk" updated: they no longer compute on a detection where the head and tail are not detected
- Fix a problem with the Nest3_ event. The stop condition necessary is now considered correctly
- Fix an head/tail problem condition in the followzone event
BootstrapVue3 updated to v0.3.11
  • Loading branch information
ntorquet committed Oct 5, 2022
1 parent 4f6afb9 commit 23705bd
Show file tree
Hide file tree
Showing 27 changed files with 1,805 additions and 1,691 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ django-admin startproject lmt_toolkit_analysis
## Javascript Requirements and installations
- vue-cli
- axios
- bootstrap-vue-3
- bootstrap-vue-3@0.3.11
- bootstrap-icons-vue
- vue3-popper
- chart.js (for plots)
Expand Down
2,375 changes: 1,187 additions & 1,188 deletions frontend/package-lock.json

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@
},
"dependencies": {
"@meforma/vue-toaster": "^1.3.0",
"@popperjs/core": "^2.11.6",
"axios": "^0.27.2",
"bootstrap": "^5.2.2",
"bootstrap-icons-vue": "^1.8.1",
"bootstrap-vue-3": "^0.1.14",
"bootstrap-vue-3": "^0.3.11",
"chart.js": "^3.8.0",
"core-js": "^3.8.3",
"stylus": "^0.58.1",
Expand Down
75 changes: 58 additions & 17 deletions frontend/src/views/VersionHistory.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,66 @@
Some important changes will impact the results. This page gives you an history of all changes so that you know if a new analysis is needed.
</b-card>

<table class="table table-striped table-hover">
<thead>
<tr>
<th style="width: 5%">Version</th>
<th style="width: 10%">Date</th>
<th>Changes / Notes</th>
<th>Release</th>
</tr>
</thead>
<tr>
<td>v0.1</td>
<td>2022 september</td>
<td>
<b-table-simple striped hover>
<b-thead>
<b-tr>
<b-th style="width: 5%">Version</b-th>
<b-th style="width: 10%">Date</b-th>
<b-th>LMT-toolkit Changes / Notes</b-th>
<b-th>LMT-analysis Changes / Notes</b-th>
<b-th>LMT-analysis release</b-th>
</b-tr>
</b-thead>
<b-tr>
<b-td><a href="https://github.com/ntorquet/lmt_toolkit_analysis/releases/tag/v0.1" target="_blank">
<b-badge variant="dark" pill><b-icon-github></b-icon-github> v0.1.1</b-badge></a>
</b-td>
<b-td>2022 october</b-td>
<b-td>
<strong>Pre release version</strong>:<br />
Wrong message color if temperature higher than 26°C corrected<br />
BootstrapVue3 updated to v0.3.11
</b-td>
<b-td>
LMT-analysis upgraded (v1.0.0 to v1.0.3):
<b-list-group>
<b-list-group-item class="d-flex justify-content-between align-items-center">
Event "approach contact" corrected
<a href="https://github.com/fdechaumont/lmt-analysis/releases/tag/v1.0.1" target="_blank"><b-badge variant="secondary" pill><b-icon-github></b-icon-github> v1.0.1</b-badge></a>
</b-list-group-item>
<b-list-group-item class="d-flex justify-content-between align-items-center">
Events "follow zone" and "side walk" updated: they no longer compute on a detection where the head and tail are not detected
<a href="https://github.com/fdechaumont/lmt-analysis/releases/tag/v1.0.1" target="_blank"><b-badge variant="secondary" pill><b-icon-github></b-icon-github> v1.0.1</b-badge></a>
</b-list-group-item>
<b-list-group-item class="d-flex justify-content-between align-items-center">
Fix a problem with the Nest3_ event. The stop condition necessary is now considered correctly
<a href="https://github.com/fdechaumont/lmt-analysis/releases/tag/v1.0.2" target="_blank"><b-badge variant="secondary" pill><b-icon-github></b-icon-github> v1.0.2</b-badge></a>
</b-list-group-item>
<b-list-group-item class="d-flex justify-content-between align-items-center">
Fix an head/tail problem condition in the followzone event
<a href="https://github.com/fdechaumont/lmt-analysis/releases/tag/v1.0.3" target="_blank"><b-badge variant="secondary" pill><b-icon-github></b-icon-github> v1.0.3</b-badge></a>
</b-list-group-item>
</b-list-group>
</b-td>
<b-td>
<a href="https://github.com/fdechaumont/lmt-analysis/releases/tag/v1.0.3" target="_blank"><b-badge variant="secondary" pill><b-icon-github></b-icon-github> v1.0.3</b-badge></a>
</b-td>
</b-tr>
<b-tr>
<b-td><a href="https://github.com/ntorquet/lmt_toolkit_analysis/releases/tag/v0.1" target="_blank">
<b-badge variant="dark" pill><b-icon-github></b-icon-github> v0.1</b-badge></a>
</b-td>
<b-td>2022 september</b-td>
<b-td>
<strong>Pre release version</strong><br />
</b-td>
<b-td>

Initial code for reliability. Analysis code is a fork of <a href="https://github.com/fdechaumont/lmt-analysis" target="_blank">lmt-analysis</a> on July 13, 2022.
</td>
<td><a href="https://github.com/ntorquet/lmt_toolkit_analysis/releases/tag/v0.1" target="_blank"><b-icon-github></b-icon-github> LMT-toolkit analysis v0.1</a></td>
</tr>
</table>
</b-td>
<b-td>Pre release corresponding to <a href="https://github.com/fdechaumont/lmt-analysis/releases/tag/v1.0.0" target="_blank"><b-badge variant="secondary" pill><b-icon-github></b-icon-github> v1.0.0</b-badge></a></b-td>
</b-tr>
</b-table-simple>
</template>

<script>
Expand Down
7 changes: 4 additions & 3 deletions lmt_toolkit_analysis/lmttoolkitanalysis/LMT/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""
Created 13 aout 2019
'''
Created on 13 aout 2018
@author: Fab
"""
'''
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
'''
Created on 7 sept 2017
Created on 7 sept. 2017
@author: Fab
'''

Expand Down Expand Up @@ -622,7 +622,9 @@ def getMeanBodyLength (self, tmin=0, tmax=None):
continue

a = self.detectionDictionnary.get( key )
bodySizeList.append(a.getBodySize())

if (a.isHeadAndTailDetected()):
bodySizeList.append(a.getBodySize())

mean = np.nanmean(bodySizeList)
print( "mean animal bodysize: " , mean )
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,63 +15,105 @@
from .Measure import *
from .EventTimeLineCache import EventTimeLineCached


def flush( connection ):
''' flush event in database '''
deleteEventTimeLineInBase(connection, "Approach contact" )

def reBuildEvent( connection, file, tmin=None, tmax=None , pool = None ):

'''
This event represents the approaches that is just before a contact (longer than 3 frames); if the speeds of the two animals
involved in the contact are not different enough, the animal approaching cannot be defined and therefore the event is not computed
for this contact.
This event is a reduction of distance between two animals, one going more quickly than the other, until they get in contact.
This event ends at the frame just before the contact and lasts the whole time of approach.
'''

#pool = AnimalPool( )
#pool.loadAnimals( connection )
#pool.loadDetection( start = tmin, end = tmax )
if ( pool == None ):
pool = AnimalPool( )
pool.loadAnimals( connection )
pool.loadDetection( start = tmin, end = tmax , lightLoad=True )

contactDicoDico = {}

eventName = "Approach contact"
print ( eventName )
print('Computing ', eventName)

#upload the timelines of interest
contactDico = {}
approachDico = {}
for animal in range( 1 , pool.getNbAnimals()+1 ):
for idAnimalB in range( 1 , pool.getNbAnimals()+1 ):
if ( animal == idAnimalB ):
continue
''' I take the dictionnary of event of the contact event, that's why I put DicoDico '''
contactDicoDico[animal, idAnimalB] = EventTimeLineCached( connection, file, "Contact", animal, idAnimalB, minFrame=tmin, maxFrame=tmax ).getDictionnary()
''' This one is the dico of event '''
approachDico[animal, idAnimalB] = EventTimeLineCached( connection, file, "Social approach", animal, idAnimalB, minFrame=tmin, maxFrame=tmax ) #fait une matrice de toutes les approches à deux possibles

#charge the contact timelines as a dictionary of timelines
contactDico[animal, idAnimalB] = EventTimeLineCached( connection, file, "Contact", animal, idAnimalB, minFrame=tmin, maxFrame=tmax )
#charge the approach timelines as a dictionary of timelines
approachDico[animal, idAnimalB] = EventTimeLineCached( connection, file, "Approach", animal, idAnimalB, minFrame=tmin, maxFrame=tmax ) #fait une matrice de toutes les approches à deux possibles

#initiate the timeline of approach before a contact
appContactTimeLineDico = {}
appContactTimeLineDicoDico = {}
for animal in range( 1 , pool.getNbAnimals()+1 ):
for idAnimalB in range( 1 , pool.getNbAnimals()+1 ):
if ( animal == idAnimalB ):
continue

appContactTimeLineDico[ animal, idAnimalB ] = EventTimeLine( None, eventName , animal , idAnimalB , None , None , loadEvent=False )
appContactTimeLineDicoDico[ animal, idAnimalB ] = {}

#upload the dictionary for each approach timeline
approachDicoDico = {}
for animal in range( 1 , pool.getNbAnimals()+1 ):

for idAnimalB in range( 1 , pool.getNbAnimals()+1 ):
if( animal == idAnimalB ):
continue

eventName = "Approach contact"
print ( eventName )
#upload the dictionary for each approach timeline:
approachDicoDico[animal, idAnimalB] = approachDico[animal, idAnimalB].getDictionary()

appContactTimeLine = EventTimeLine( None, eventName , animal , idAnimalB , None , None , loadEvent=False )

for eventApp in approachDico[animal, idAnimalB].eventList:

''' new code: '''
#check who approached who before the contact
for animal in range( 1 , pool.getNbAnimals()+1 ):
for idAnimalB in range( 1 , pool.getNbAnimals()+1 ):
if( animal == idAnimalB ):
continue

#clean the contact timeline to keep only events longer than 3 frames
contactDico[animal, idAnimalB].mergeCloseEvents(numberOfFrameBetweenEvent=1)
contactDico[animal, idAnimalB].removeEventsBelowLength(maxLen=3)


for contactEvent in contactDico[animal, idAnimalB].eventList:
frameBeforeContact = contactEvent.startFrame - 1
#if the frame before the contact is within the approach timeline of A to B, then add the corresponding approach event to the approach contact timeline
if frameBeforeContact in approachDicoDico[animal, idAnimalB]:
#print('A approaches B')
approachEvent = approachDico[animal, idAnimalB].getEventAt( frameBeforeContact )
for t in range (approachEvent.startFrame, frameBeforeContact + 1):
appContactTimeLineDicoDico[animal, idAnimalB][t] = True

for t in range( eventApp.endFrame - TIME_WINDOW_BEFORE_EVENT, eventApp.endFrame + TIME_WINDOW_BEFORE_EVENT + 1 ):

if ( t in contactDicoDico[animal, idAnimalB] ):
appContactTimeLine.eventList.append(eventApp)
break


''' old code(slow)
#if the frame before the contact is within the approach timeline of B to A, then add the corresponding approach event to the approach contact timeline
elif frameBeforeContact in approachDicoDico[idAnimalB, animal]:
#print('B approaches A')
approachEvent = approachDico[idAnimalB, animal].getEventAt( frameBeforeContact )
for t in range (approachEvent.startFrame, frameBeforeContact + 1):
appContactTimeLineDicoDico[idAnimalB, animal][t] = True

bug: est ce que ca n aurait pas du etre eventContact.startFrame ? ou eventApp.endFrame-TIME_WINDOW_BEFORE_EVENT, eventApp.endFrame+TIME_WINDOW_BEFORE_EVENT ?
#if the frame before the contact is not within any approach timeline, then go to the next contact event
else:
#print('Not possible to decide who is approaching who.')
continue

for eventContact in contactDicoDico[animal, idAnimalB].eventList:
if (eventApp.overlapInT(eventContact.endFrame-TIME_WINDOW_BEFORE_EVENT, eventContact.endFrame+TIME_WINDOW_BEFORE_EVENT) == True):
appContactTimeLine.eventList.append(eventApp)
'''

appContactTimeLine.endRebuildEventTimeLine(connection)

for animal in range( 1 , pool.getNbAnimals()+1 ):
for idAnimalB in range( 1 , pool.getNbAnimals()+1 ):
if( animal == idAnimalB ):
continue
appContactTimeLineDico[animal, idAnimalB].reBuildWithDictionnary( appContactTimeLineDicoDico[animal, idAnimalB] )
appContactTimeLineDico[animal, idAnimalB].endRebuildEventTimeLine( connection )

# log process
from .TaskLogger import TaskLogger
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@
'''
import sqlite3
from time import *
from lmtanalysis.Chronometer import Chronometer
from lmtanalysis.Animal import *
from lmtanalysis.Detection import *
from lmtanalysis.Measure import *
from .Chronometer import Chronometer
from .Animal import *
from .Detection import *
from .Measure import *
import matplotlib.pyplot as plt
import numpy as np
from lmtanalysis.Event import *
from lmtanalysis.Measure import *
from lmtanalysis.EventTimeLineCache import EventTimeLineCached
from lmtanalysis.BehaviouralSequencesUtil import exclusiveEventList, contactTypeList
from .Event import *
from .Measure import *
from .EventTimeLineCache import EventTimeLineCached
from .BehaviouralSequencesUtil import exclusiveEventList, contactTypeList

def flush( connection ):
''' flush event in database '''
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@
'''
import sqlite3
from time import *
from lmtanalysis.Chronometer import Chronometer
from lmtanalysis.Animal import *
from lmtanalysis.Detection import *
from lmtanalysis.Measure import *
from .Chronometer import Chronometer
from .Animal import *
from .Detection import *
from .Measure import *
import matplotlib.pyplot as plt
import numpy as np
from lmtanalysis.Event import *
from lmtanalysis.Measure import *
from lmtanalysis.EventTimeLineCache import EventTimeLineCached
from lmtanalysis.BehaviouralSequencesUtil import exclusiveEventList
from .Event import *
from .Measure import *
from .EventTimeLineCache import EventTimeLineCached
from .BehaviouralSequencesUtil import exclusiveEventList

def flush( connection ):
''' flush event in database '''
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@
'''
import sqlite3
from time import *
from lmtanalysis.Chronometer import Chronometer
from lmtanalysis.Animal import *
from lmtanalysis.Detection import *
from lmtanalysis.Measure import *
from .Chronometer import Chronometer
from .Animal import *
from .Detection import *
from .Measure import *
import matplotlib.pyplot as plt
import numpy as np
from lmtanalysis.Event import *
from lmtanalysis.Measure import *
from lmtanalysis.EventTimeLineCache import EventTimeLineCached
from lmtanalysis.BehaviouralSequencesUtil import exclusiveEventList
from .Event import *
from .Measure import *
from .EventTimeLineCache import EventTimeLineCached
from .BehaviouralSequencesUtil import exclusiveEventList

def flush( connection ):
''' flush event in database '''
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def reBuildEvent( connection, file, tmin=None, tmax=None, pool = None ):

for idAnimalB in pool.animalDictionnary.keys():
print(pool.animalDictionnary[idAnimalB])
meanSizeB = pool.animalDictionnary[idAnimalB].getMeanBodyLength( tmax = tmax )
#meanSizeB = pool.animalDictionnary[idAnimalB].getMeanBodyLength( tmax = tmax )

for animal in pool.animalDictionnary.keys():
if( idAnimalB == animal ):
Expand All @@ -94,6 +94,8 @@ def reBuildEvent( connection, file, tmin=None, tmax=None, pool = None ):

for idAnimalB in pool.animalDictionnary.keys():

meanSizeB = pool.animalDictionnary[idAnimalB].getMeanBodyLength( tmax = tmax )

for animal in pool.animalDictionnary.keys():
if( animal == idAnimalB ):
continue
Expand Down Expand Up @@ -149,6 +151,8 @@ def reBuildEvent( connection, file, tmin=None, tmax=None, pool = None ):
speedA = pool.animalDictionnary[animal].getSpeed(t)
speedB = pool.animalDictionnary[idAnimalB].getSpeed(t)
#angleB = pool.animalList[idAnimalB].getDirection(t)
if not pool.animalDictionnary[animal].getDetectionAt( t ).isHeadAndTailDetected():
continue
angleA = pool.animalDictionnary[animal].getDirection(t)

if (speedA == None or speedB == None):
Expand All @@ -171,11 +175,12 @@ def reBuildEvent( connection, file, tmin=None, tmax=None, pool = None ):
for time in range( t-15, t+1, 2):
#time = t
try:
angleB = pool.animalDictionnary[idAnimalB].getDirection(time)
if ( checkZone( dicA[t].massX, dicA[t].massY, angleA, meanSizeB, dicB[time].massX, dicB[time].massY, angleB ) == True):

resultIso[t] = True
break
if pool.animalDictionnary[idAnimalB].getDetectionAt( time ).isHeadAndTailDetected():
angleB = pool.animalDictionnary[idAnimalB].getDirection(time)
if ( checkZone( dicA[t].massX, dicA[t].massY, angleA, meanSizeB, dicB[time].massX, dicB[time].massY, angleB ) == True):

resultIso[t] = True
break
except:
pass

Expand Down
Loading

0 comments on commit 23705bd

Please sign in to comment.