comparison trafficintelligence/iframework.py @ 1162:efd52c55a72b

added indicator framework file
author Nicolas Saunier <nicolas.saunier@polymtl.ca>
date Sun, 07 Mar 2021 23:26:51 -0500
parents
children fa9c358789ac
comparison
equal deleted inserted replaced
1161:b968c33f8c2f 1162:efd52c55a72b
1 from enum import Enum
2 from pathlib import Path
3 from datetime import datetime
4
5 from sqlalchemy.ext.declarative import declarative_base, declared_attr
6 from sqlalchemy import Table, Column, Integer, Boolean, String, Float, DateTime, Enum as SQLEnum, ForeignKey, CheckConstraint, create_engine
7 from sqlalchemy.orm import relationship, backref, sessionmaker
8
9 """
10
11 """
12
13 Base = declarative_base()
14
15 GenderEnum = Enum('GenderEnum', 'male female unknown')
16 ModeEnum = Enum('ModeEnum', 'cardriver carpassenger transit bike walking scooter skating')
17 VehicleEnum = Enum('VehicleEnum', 'car SUV truck bus bike scooter skate rollers')
18
19 # should there be a survey object for site info, observer, etc?
20
21 class Mode(Base):
22 'personal, because in a group (family), some might have a scooter or rollers'
23 __tablename__ = 'modes'
24 idx = Column(Integer, primary_key=True)
25 personIdx = Column(Integer, ForeignKey('persons.idx'))
26 vehicleIdx = Column(Integer, ForeignKey('vehicles.idx'))
27 transport = Column(SQLEnum(ModeEnum), nullable=False)
28 startTime = Column(DateTime) # None first time if only one group
29 pointIdx = Column(Integer, ForeignKey('points.idx'))
30
31 person = relationship('Person', backref = backref('modes'))
32 vehicle = relationship('Vehicle')
33 point = relationship('Point')
34
35 def __init__(self, transport, person, vehicle = None, startTime = None, p = None):
36 self.person = person
37 self.transport = transport
38 self.vehicle = vehicle
39 self.startTime = startTime
40 self.point = p
41
42 @staticmethod
43 def initGroup(transport, group, vehicle = None, startTime = None):
44 return [Mode(transport, p, startTime) for p in group.getPersons()]
45
46 class Group(Base):
47 __tablename__ = 'groups'
48 idx = Column(Integer, primary_key=True)
49
50 def __init__(self, persons):
51 for p in persons:
52 GroupBelonging(p, self)
53
54 def getPersons(self):
55 return [gb.person for gb in self.groupBelongings]
56
57 class GroupBelonging(Base):
58 __tablename__ = 'groupbelongings'
59 groupIdx = Column(Integer, ForeignKey('groups.idx'), primary_key=True)
60 personIdx = Column(Integer, ForeignKey('persons.idx'), primary_key=True)
61 pointIdx = Column(Integer, ForeignKey('points.idx'))
62 startTime = Column(DateTime) # None first time if only one group
63
64 person = relationship('Person', backref = backref('groupBelongings'))
65 group = relationship('Group', backref = backref('groupBelongings'))
66 point = relationship('Point')
67
68 def __init__(self, person, group, startTime = None, p = None):
69 self.person = person
70 self.group = group
71 self.startTime = startTime
72 self.point = p
73
74 # in aggregated form, there is a total number of observations for a given time interval, a number for each binary variable and k-1 variables for a categorical variable with k categories
75 class Person(Base):
76 __tablename__ = 'persons'
77 idx = Column(Integer, primary_key=True)
78 #groupIdx = Column(Integer, ForeignKey('groups.idx'))
79 age = Column(String)
80 gender = Column(SQLEnum(GenderEnum), nullable=False)
81 disability = Column(String) # could be enum
82 stroller = Column(Boolean) # the booleans could be strings or enum to have more information
83 bag = Column(Boolean)
84 animal = Column(Boolean)
85
86 #group = relationship('Group', backref = backref('persons'))
87
88 def __init__(self, age = 'unknown', gender = 'unknown', disability = False, stroller = False, bag = False, animal = False):
89 self.age = age
90 self.gender = gender
91 self.disability = disability
92 self.stroller = stroller
93 self.bag = bag
94 self.animal = animal
95
96 def getAgeNum(self):
97 if str.isnumeric(self.age):
98 return int(self.age)
99 elif '.' in self.age:
100 try:
101 return float(self.age)
102 except ValueError:
103 pass
104 else:
105 return self.age
106
107 def getGroups(self):
108 if len(self.groupBelongings) > 0:
109 return [gb.group for gb in self.groupBelongings]
110 else:
111 return None
112
113 class Vehicle(Base):
114 __tablename__ = 'vehicles'
115 idx = Column(Integer, primary_key=True)
116 category = Column(SQLEnum(VehicleEnum), nullable=False)
117 trailer = Column(Boolean)
118
119 def __init__(self, category, trailer = False):
120 self.category = category
121 self.trailer = trailer
122
123 class Point(Base):
124 __tablename__ = 'points'
125 idx = Column(Integer, primary_key=True)
126 x = Column(Float)
127 y = Column(Float)
128
129 def __init__(self, x, y):
130 self.x = x
131 self.y = y
132
133 pointLineAssociation = Table('pointlines', Base.metadata,
134 Column('pointIdx', Integer, ForeignKey('points.idx')),
135 Column('lineIdx', Integer, ForeignKey('lines.idx')))
136
137 class Line(Base):
138 __tablename__ = 'lines'
139 idx = Column(Integer, primary_key=True)
140
141 points = relationship('Point', secondary=pointLineAssociation)
142
143 def __init__(self, x1, y1, x2, y2):
144 self.points = [Point(x1, y1), Point(x2, y2)]
145
146 pointZoneAssociation = Table('pointzones', Base.metadata,
147 Column('pointIdx', Integer, ForeignKey('points.idx')),
148 Column('zoneIdx', Integer, ForeignKey('zones.idx')))
149
150 class Zone(Base):
151 __tablename__ = 'zones'
152 idx = Column(Integer, primary_key=True)
153
154 points = relationship('Point', secondary=pointZoneAssociation)
155
156 def __init__(self, xs = None, ys = None):
157 'xs and ys are the list of x and y coordinates'
158 if xs is not None and ys is not None:
159 for x,y in zip(xs, ys):
160 self.addPoint(x,y)
161
162 def addPoint(self, x, y):
163 self.points.append(Point(x, y))
164
165 class AbstractPassing:
166 def initPersonGroupPassing(self, group, person, transport, vehicle):
167 if person is None and group is not None: # create group
168 self.group = group
169 if transport is not None:
170 Mode.initGroup(transport, group, vehicle)
171 elif person is not None and group is None: # create person
172 self.group = Group([person])
173 if transport is not None:
174 Mode(transport, person, vehicle)
175 else:
176 print('Warning: passing person and group or both None')
177
178 class LinePassing(AbstractPassing,Base):
179 __tablename__ = 'linepassings'
180 idx = Column(Integer, primary_key=True)
181 lineIdx = Column(Integer, ForeignKey('lines.idx'))
182 groupIdx = Column(Integer, ForeignKey('groups.idx'))
183 pointIdx = Column(Integer, ForeignKey('points.idx'))
184 instant = Column(DateTime)
185 speed = Column(Float)
186 wrongDirection = Column(Boolean)
187
188 line = relationship('Line')
189 group = relationship('Group')
190 point = relationship('Point')
191
192 def __init__(self, line, instant, speed = None, wrongDirection = None, p = None, group = None, person = None, transport = None, vehicle = None):
193 # makes it possible to create person and mode for just counting
194 # pass transport as string to instantiate after
195 self.line = line
196 self.instant = instant
197 self.speed = speed
198 self.wrongDirection = wrongDirection
199 self.point = p
200 self.initPersonGroupPassing(group, person, transport, vehicle)
201
202 class ZonePassing(AbstractPassing,Base):
203 __tablename__ = 'zonepassings'
204 idx = Column(Integer, primary_key=True)
205 zoneIdx = Column(Integer, ForeignKey('zones.idx'))
206 groupIdx = Column(Integer, ForeignKey('groups.idx'))
207 pointIdx = Column(Integer, ForeignKey('points.idx'))
208 instant = Column(DateTime)
209 entering = Column(Boolean)
210
211 zone = relationship('Zone')
212 group = relationship('Group')
213 point = relationship('Point')
214
215 def __init__(self, zone, instant, entering, p = None, group = None, person = None, transport = None, vehicle = None):
216 self.zone = zone
217 self.instant = instant
218 self.entering = entering
219 self.point = p
220 self.initPersonGroupPassing(group, person, transport, vehicle)
221
222 class Activity(AbstractPassing,Base):
223 __tablename__ = 'activities'
224 idx = Column(Integer, primary_key=True)
225 activity = Column(String) # could be enum
226 groupIdx = Column(Integer, ForeignKey('groups.idx'))
227 # can an activity be done in a vehicle? Is it relevant? Can it be unambiguously identified?
228 startTime = Column(DateTime)
229 endTime = Column(DateTime)
230 zoneIdx = Column(Integer, ForeignKey('zones.idx'))
231 pointIdx = Column(Integer, ForeignKey('points.idx'))
232
233 group = relationship('Group')
234 zone = relationship('Zone')
235 point = relationship('Point')
236
237 def __init__(self, activity, startTime, endTime, zone, p = None, group = None, person = None, transport = None, vehicle = None):
238 self.activity = activity
239 self.startTime = startTime
240 self.endTime = endTime
241 self.zone = zone
242 self.point = p
243 self.initPersonGroupPassing(group, person, transport, vehicle)
244
245 def createDatabase(filename):
246 'creates a session to query the filename'
247 if Path(filename).is_file():
248 print('The file '+filename+' exists')
249 return None
250 else:
251 engine = create_engine('sqlite:///'+filename)
252 Base.metadata.create_all(engine)
253 Session = sessionmaker(bind=engine)
254 return Session()
255
256 def connectDatabase(filename):
257 'creates a session to query the filename'
258 if Path(filename).is_file():
259 engine = create_engine('sqlite:///'+filename)
260 Session = sessionmaker(bind=engine)
261 return Session()
262 else:
263 print('The file '+filename+' does not exist')
264 return None
265
266 if __name__ == '__main__': # demo code
267 session = createDatabase('test.sqlite')
268 if session is None:
269 session = connectDatabase('test.sqlite')
270 # count example
271 p = Person(6, 'female', bag = True)
272 veh1 = Vehicle('car')
273 modes = [Mode('cardriver', p, veh1), Mode('walking', p, startTime = datetime(2020,7,7,11,20))]
274
275 line = Line(0.,0.,0.,10.)
276 zone = Zone([0., 0., 1., 1.], [0., 1., 1., 0.])
277 destination = Zone([10., 10., 11., 11.], [10., 11., 11., 10.])
278 counts = [LinePassing(line, datetime(2020,7,2,23,20+i), person = Person(20+i, 'female', disability = True), transport = 'walking') for i in range(5)]
279 group1 = Group([Person(13+i,'female', False, False, True, False) for i in range(3)])
280 groupMode1 = Mode.initGroup('walking', group1)
281 activities = [Activity('walking', datetime(2020,7,2,23,0), datetime(2020,7,2,23,10), zone, person = Person(40, 'male', True, False, True, False)),
282 Activity('eating', datetime(2020,7,2,23,10), datetime(2020,7,2,23,12), zone, person = Person(40, 'male', True, False, True, False)),
283 Activity('playing', datetime(2020,7,2,22,0), datetime(2020,7,2,23,0), zone, group = group1)]
284 counts.append(LinePassing(line, datetime(2020,7,2,23,5), group = group1))
285 counts.append(LinePassing(line, datetime(2020,7,2,23,7), person = Person(23, 'unknown'), transport = 'cardriver', vehicle = Vehicle('car')))
286 counts.append(LinePassing(line, datetime(2020,7,2,23,9), person = Person('teen', 'unknown'), transport = 'scooter', vehicle = Vehicle('scooter')))
287 counts.append(LinePassing(line, datetime(2020,7,2,23,11), person = Person(12, 'female'), transport = 'bike'))
288 counts.append(LinePassing(line, datetime(2020,7,2,23,13), person = Person(), transport = 'car')) # example of counting cars without knowing the driver and passenger's attributes
289 counts.append(LinePassing(line, datetime(2020,7,2,23,15), group = Group([Person(34+i) for i in range(3)]), transport = 'carpassenger'))
290
291
292 counts.append(ZonePassing(zone, datetime(2020,7,7,9,5), True, person = Person(33, 'male', False, False, True, False)))
293
294 session.add_all([line, p, zone, group1, destination]+modes+groupMode1+counts+activities)
295
296 session.commit()
297 session.close()