Mercurial > hg > nsaunier > traffic-intelligence
comparison trafficintelligence/iframework.py @ 1293:4dd446835e7d
update closer to Studio iframework
| author | Nicolas Saunier <nicolas.saunier@polymtl.ca> |
|---|---|
| date | Wed, 02 Oct 2024 12:19:12 -0400 |
| parents | c4c50678c856 |
| children |
comparison
equal
deleted
inserted
replaced
| 1292:41219193baa0 | 1293:4dd446835e7d |
|---|---|
| 9 from sqlalchemy.orm import relationship, backref, sessionmaker, declarative_base | 9 from sqlalchemy.orm import relationship, backref, sessionmaker, declarative_base |
| 10 | 10 |
| 11 Base = declarative_base() | 11 Base = declarative_base() |
| 12 | 12 |
| 13 GenderEnum = Enum('GenderEnum', 'male female unknown') | 13 GenderEnum = Enum('GenderEnum', 'male female unknown') |
| 14 ModeEnum = Enum('ModeEnum', 'cardriver carpassenger transit taxi motorcycle cycling walking other') # the idea is that the mode could be sufficient to record all events (line and zone crossings), whether the actual, more precise vehicle, is | 14 ModeEnum = Enum('ModeEnum', 'car_driver car_passenger transit taxi motorcycle cycling walking other') # the idea is that the mode could be sufficient to record all events (line and zone crossings), whether the actual, more precise vehicle, is |
| 15 VehicleEnum = Enum('VehicleEnum', 'car suv van truck motorcycle bus bike scooter skate rollers') | 15 VehicleEnum = Enum('VehicleEnum', 'car bike van truck bus taxi motorcycle scooter skate rollers mobility_scooter') |
| 16 ActivityEnum = Enum('ActivityEnum', 'unknown strolling jogging shopping sitting talking resting eating playing doing_exercise smoking using_cellphone observing reading_writing performing selling playing_with_pet taking_pet_for_walk') | |
| 17 DisabilityEnum = Enum('DisabilityEnum', 'none wheelchair walker cane white_cane') | |
| 18 AgeEnum = Enum('AgeEnum', 'unknown infant toddler child teen young_adult adult senior') # 0-1, 1-4, 4-12, 12-18... | |
| 16 | 19 |
| 17 # should there be a survey object for site info, observer, etc? | 20 # should there be a survey object for site info, observer, etc? |
| 18 | 21 |
| 19 class Mode(Base): | 22 class Mode(Base): |
| 20 '''A mode is personal, because in a group (family), some might have a scooter or rollers''' | 23 '''A mode is personal, because in a group (family), some might have a scooter or rollers''' |
| 72 # 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 # 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 |
| 73 class Person(Base): | 76 class Person(Base): |
| 74 __tablename__ = 'persons' | 77 __tablename__ = 'persons' |
| 75 idx = Column(Integer, primary_key=True) | 78 idx = Column(Integer, primary_key=True) |
| 76 #groupIdx = Column(Integer, ForeignKey('groups.idx')) | 79 #groupIdx = Column(Integer, ForeignKey('groups.idx')) |
| 77 age = Column(String) | 80 age = Column(SQLEnum(AgeEnum), nullable=True) #Column(String) |
| 78 gender = Column(SQLEnum(GenderEnum), nullable=False) | 81 gender = Column(SQLEnum(GenderEnum), nullable=False) |
| 79 disability = Column(String) # could be enum | 82 disability = Column(String) #Column(SQLEnum(DisabilityEnum) #Boolean in Studio |
| 80 stroller = Column(Boolean) # the booleans could be strings or enum to have more information | 83 stroller = Column(Boolean) # the booleans could be strings or enum to have more information |
| 81 bag = Column(Boolean) | 84 bag = Column(Boolean) |
| 82 animal = Column(Boolean) | 85 animal = Column(Boolean) |
| 86 # databaseFilename = Column(String) # refers to trajectory database, relative path | |
| 87 # objectIdx = Column(Integer) # refers to object id in trajectory database | |
| 83 | 88 |
| 84 #group = relationship('Group', backref = backref('persons')) | 89 #group = relationship('Group', backref = backref('persons')) |
| 85 | 90 |
| 86 def __init__(self, age = 'unknown', gender = 'unknown', disability = False, stroller = False, bag = False, animal = False): | 91 def __init__(self, age = 'unknown', gender = 'unknown', disability = False, stroller = False, bag = False, animal = False): |
| 87 self.age = age | 92 self.age = age |
| 98 try: | 103 try: |
| 99 return float(self.age) | 104 return float(self.age) |
| 100 except ValueError: | 105 except ValueError: |
| 101 pass | 106 pass |
| 102 else: | 107 else: |
| 103 return self.age | 108 return self.age |
| 104 | 109 |
| 105 def getGroups(self): | 110 def getGroups(self): |
| 106 if len(self.groupBelongings) > 0: | 111 if len(self.groupBelongings) > 0: |
| 107 return [gb.group for gb in self.groupBelongings] | 112 return [gb.group for gb in self.groupBelongings] |
| 108 else: | 113 else: |
| 109 return None | 114 return None |
| 110 | 115 |
| 111 class Vehicle(Base): | 116 class Vehicle(Base): |
| 112 __tablename__ = 'vehicles' | 117 __tablename__ = 'vehicles' |
| 113 idx = Column(Integer, primary_key=True) | 118 idx = Column(Integer, primary_key=True) |
| 114 category = Column(SQLEnum(VehicleEnum), nullable=False) | 119 category = Column(SQLEnum(VehicleEnum), nullable=False) |
| 115 trailer = Column(Boolean) | 120 trailer = Column(Boolean) |
| 121 # databaseFilename = Column(String) # refers to trajectory database, relative path | |
| 122 # objectIdx = Column(Integer) # refers to object id in trajectory database | |
| 116 | 123 |
| 117 def __init__(self, category, trailer = False): | 124 def __init__(self, category, trailer = False): |
| 118 self.category = category | 125 self.category = category |
| 119 self.trailer = trailer | 126 self.trailer = trailer |
| 120 | 127 |
| 129 self.y = y | 136 self.y = y |
| 130 | 137 |
| 131 pointLineAssociation = Table('pointlines', Base.metadata, | 138 pointLineAssociation = Table('pointlines', Base.metadata, |
| 132 Column('pointIdx', Integer, ForeignKey('points.idx')), | 139 Column('pointIdx', Integer, ForeignKey('points.idx')), |
| 133 Column('lineIdx', Integer, ForeignKey('lines.idx'))) | 140 Column('lineIdx', Integer, ForeignKey('lines.idx'))) |
| 134 | 141 |
| 135 class Line(Base): | 142 class Line(Base): |
| 136 __tablename__ = 'lines' | 143 __tablename__ = 'lines' |
| 137 idx = Column(Integer, primary_key=True) | 144 idx = Column(Integer, primary_key=True) |
| 138 name = Column(String) | 145 name = Column(String) |
| 139 # todo define lines for access counting: add type? - AccessLine? | 146 # todo define lines for access counting: add type? - AccessLine? |
| 157 | 164 |
| 158 def __init__(self, name, xs = None, ys = None): | 165 def __init__(self, name, xs = None, ys = None): |
| 159 'xs and ys are the list of x and y coordinates' | 166 'xs and ys are the list of x and y coordinates' |
| 160 self.name = name | 167 self.name = name |
| 161 if xs is not None and ys is not None: | 168 if xs is not None and ys is not None: |
| 162 for x,y in zip(xs, ys): | 169 for x, y in zip(xs, ys): |
| 163 self.addPoint(x,y) | 170 self.addPoint(x, y) |
| 164 | 171 |
| 165 def addPoint(self, x, y): | 172 def addPoint(self, x, y): |
| 166 self.points.append(Point(x, y)) | 173 self.points.append(Point(x, y)) |
| 167 | 174 |
| 168 class AbstractCrossing: | 175 class AbstractCrossing: |
| 169 def initPersonGroupCrossing(self, group, person, modeName, vehicle): | 176 def initPersonGroupCrossing(self, group, person, modeName, vehicle): |
| 188 lineIdx = Column(Integer, ForeignKey('lines.idx')) | 195 lineIdx = Column(Integer, ForeignKey('lines.idx')) |
| 189 groupIdx = Column(Integer, ForeignKey('groups.idx')) | 196 groupIdx = Column(Integer, ForeignKey('groups.idx')) |
| 190 pointIdx = Column(Integer, ForeignKey('points.idx')) | 197 pointIdx = Column(Integer, ForeignKey('points.idx')) |
| 191 instant = Column(DateTime) | 198 instant = Column(DateTime) |
| 192 speed = Column(Float) | 199 speed = Column(Float) |
| 193 wrongDirection = Column(Boolean) | 200 # wrongDirection = Column(Boolean) |
| 201 rightToLeft = Column(Boolean) | |
| 194 | 202 |
| 195 line = relationship('Line') | 203 line = relationship('Line') |
| 196 group = relationship('Group') | 204 group = relationship('Group') |
| 197 point = relationship('Point') | 205 point = relationship('Point') |
| 198 | 206 |
| 212 zoneIdx = Column(Integer, ForeignKey('zones.idx')) | 220 zoneIdx = Column(Integer, ForeignKey('zones.idx')) |
| 213 groupIdx = Column(Integer, ForeignKey('groups.idx')) | 221 groupIdx = Column(Integer, ForeignKey('groups.idx')) |
| 214 pointIdx = Column(Integer, ForeignKey('points.idx')) | 222 pointIdx = Column(Integer, ForeignKey('points.idx')) |
| 215 instant = Column(DateTime) | 223 instant = Column(DateTime) |
| 216 entering = Column(Boolean) | 224 entering = Column(Boolean) |
| 225 speed = Column(Float) | |
| 217 | 226 |
| 218 zone = relationship('Zone') | 227 zone = relationship('Zone') |
| 219 group = relationship('Group') | 228 group = relationship('Group') |
| 220 point = relationship('Point') | 229 point = relationship('Point') |
| 221 | 230 |
| 222 def __init__(self, zone, instant, entering, p = None, group = None, person = None, modeName = None, vehicle = None): | 231 def __init__(self, zone, instant, entering, speed = None, p = None, group = None, person = None, modeName = None, vehicle = None): |
| 223 self.zone = zone | 232 self.zone = zone |
| 224 self.instant = instant | 233 self.instant = instant |
| 225 self.entering = entering | 234 self.entering = entering |
| 235 self.speed = speed | |
| 226 self.point = p | 236 self.point = p |
| 227 self.initPersonGroupCrossing(group, person, modeName, vehicle) | 237 self.initPersonGroupCrossing(group, person, modeName, vehicle) |
| 228 | 238 |
| 229 class Activity(AbstractCrossing,Base): | 239 class Activity(AbstractCrossing,Base): |
| 230 __tablename__ = 'activities' | 240 __tablename__ = 'activities' |
| 231 idx = Column(Integer, primary_key=True) | 241 idx = Column(Integer, primary_key=True) |
| 232 activity = Column(String) # could be enum | 242 activity = Column(SQLEnum(ActivityEnum), nullable=False) #Column(String) |
| 233 groupIdx = Column(Integer, ForeignKey('groups.idx')) | 243 groupIdx = Column(Integer, ForeignKey('groups.idx')) |
| 234 # can an activity be done in a vehicle? Is it relevant? Can it be unambiguously identified? | 244 # can an activity be done in a vehicle? Is it relevant? Can it be unambiguously identified? |
| 235 startTime = Column(DateTime) | 245 startTime = Column(DateTime) |
| 236 endTime = Column(DateTime) | 246 endTime = Column(DateTime) |
| 237 zoneIdx = Column(Integer, ForeignKey('zones.idx')) | 247 zoneIdx = Column(Integer, ForeignKey('zones.idx')) |
| 238 pointIdx = Column(Integer, ForeignKey('points.idx')) | 248 pointIdx = Column(Integer, ForeignKey('points.idx')) |
| 239 | 249 |
| 240 group = relationship('Group') | 250 group = relationship('Group') |
| 241 zone = relationship('Zone') | 251 zone = relationship('Zone') |
| 242 point = relationship('Point') | 252 point = relationship('Point') |
| 243 | 253 |
| 244 def __init__(self, activity, startTime, endTime, zone, p = None, group = None, person = None, modeName = None, vehicle = None): | 254 def __init__(self, activity, startTime, endTime, zone, p = None, group = None, person = None, modeName = None, vehicle = None): |
| 254 if Path(filename).is_file() and not insertInExisting: | 264 if Path(filename).is_file() and not insertInExisting: |
| 255 print('The file '+filename+' exists') | 265 print('The file '+filename+' exists') |
| 256 return None | 266 return None |
| 257 else: | 267 else: |
| 258 engine = create_engine('sqlite:///'+filename) | 268 engine = create_engine('sqlite:///'+filename) |
| 259 if createOnlyGroupTables: | 269 if createOnlyGroupTables: |
| 260 Base.metadata.create_all(engine, tables = [Base.metadata.tables['modes'], Base.metadata.tables['groups'], Base.metadata.tables['groupbelongings'], Base.metadata.tables['persons'], Base.metadata.tables['vehicles'], Base.metadata.tables['points']]) | 270 Base.metadata.create_all(engine, tables = [Base.metadata.tables['modes'], Base.metadata.tables['groups'], Base.metadata.tables['groupbelongings'], Base.metadata.tables['persons'], Base.metadata.tables['vehicles'], Base.metadata.tables['points']]) |
| 261 else: | 271 else: |
| 262 Base.metadata.create_all(engine) | 272 Base.metadata.create_all(engine) |
| 263 Session = sessionmaker(bind=engine) | 273 Session = sessionmaker(bind=engine) |
| 264 return Session() | 274 return Session() |
| 276 if __name__ == '__main__': # demo code | 286 if __name__ == '__main__': # demo code |
| 277 session = createDatabase('test.sqlite') | 287 session = createDatabase('test.sqlite') |
| 278 if session is None: | 288 if session is None: |
| 279 session = connectDatabase('test.sqlite') | 289 session = connectDatabase('test.sqlite') |
| 280 # count example | 290 # count example |
| 281 p = Person(6, 'female', bag = True) | 291 p = Person('infant', 'female', bag = True) |
| 282 veh1 = Vehicle('car') | 292 veh1 = Vehicle('car') |
| 283 modes = [Mode('cardriver', p, veh1), Mode('walking', p, startTime = datetime(2020,7,7,11,20))] | 293 modes = [Mode('cardriver', p, veh1), Mode('walking', p, startTime = datetime(2020,7,7,11,20))] |
| 284 | 294 |
| 285 line = Line('line1', 0.,0.,0.,10.) | 295 line = Line('line1', 0.,0.,0.,10.) |
| 286 zone = Zone('zone1', [0., 0., 1., 1.], [0., 1., 1., 0.]) | 296 zone = Zone('zone1', [0., 0., 1., 1.], [0., 1., 1., 0.]) |
| 287 destination = Zone('destination1', [10., 10., 11., 11.], [10., 11., 11., 10.]) | 297 destination = Zone('destination1', [10., 10., 11., 11.], [10., 11., 11., 10.]) |
| 288 counts = [LineCrossing(line, datetime(2020,7,2,23,20+i), person = Person(20+i, 'female', disability = True), modeName = 'walking') for i in range(5)] | 298 counts = [LineCrossing(line, datetime(2020,7,2,23,20+i), person = Person(AgeEnum(1+i), 'female', disability = True), modeName = 'walking') for i in range(5)] |
| 289 group1 = Group([Person(13+i,'female', False, False, True, False) for i in range(3)]) | 299 group1 = Group([Person(AgeEnum(3+i),'female', False, False, True, False) for i in range(3)]) |
| 290 groupMode1 = Mode.initGroup('walking', group1) | 300 groupMode1 = Mode.initGroup('walking', group1) |
| 291 activities = [Activity('walking', datetime(2020,7,2,23,0), datetime(2020,7,2,23,10), zone, person = Person(40, 'male', True, False, True, False)), | 301 activities = [Activity('strolling', datetime(2020,7,2,23,0), datetime(2020,7,2,23,10), zone, person = Person('adult', 'male', True, False, True, False)), |
| 292 Activity('eating', datetime(2020,7,2,23,10), datetime(2020,7,2,23,12), zone, person = Person(40, 'male', True, False, True, False)), | 302 Activity('eating', datetime(2020,7,2,23,10), datetime(2020,7,2,23,12), zone, person = Person('senior', 'male', True, False, True, False)), |
| 293 Activity('playing', datetime(2020,7,2,22,0), datetime(2020,7,2,23,0), zone, group = group1)] | 303 Activity('playing', datetime(2020,7,2,22,0), datetime(2020,7,2,23,0), zone, group = group1)] |
| 294 counts.append(LineCrossing(line, datetime(2020,7,2,23,5), group = group1)) | 304 counts.append(LineCrossing(line, datetime(2020,7,2,23,5), group = group1)) |
| 295 counts.append(LineCrossing(line, datetime(2020,7,2,23,7), person = Person(23, 'unknown'), modeName = 'cardriver', vehicle = Vehicle('car'))) | 305 counts.append(LineCrossing(line, datetime(2020,7,2,23,7), person = Person('young_adult', 'unknown'), modeName = 'cardriver', vehicle = Vehicle('car'))) |
| 296 counts.append(LineCrossing(line, datetime(2020,7,2,23,9), person = Person('teen', 'unknown'), modeName = 'other', vehicle = Vehicle('scooter'))) | 306 counts.append(LineCrossing(line, datetime(2020,7,2,23,9), person = Person('teen', 'unknown'), modeName = 'other', vehicle = Vehicle('scooter'))) |
| 297 counts.append(LineCrossing(line, datetime(2020,7,2,23,11), person = Person(12, 'female'), modeName = 'cycling')) | 307 counts.append(LineCrossing(line, datetime(2020,7,2,23,11), person = Person('teen', 'female'), modeName = 'cycling')) |
| 298 counts.append(LineCrossing(line, datetime(2020,7,2,23,13), person = Person(), modeName = 'cardriver')) # example of counting cars without knowing the driver and passenger's attributes | 308 counts.append(LineCrossing(line, datetime(2020,7,2,23,13), person = Person(), modeName = 'cardriver')) # example of counting cars without knowing the driver and passenger's attributes |
| 299 counts.append(LineCrossing(line, datetime(2020,7,2,23,15), group = Group([Person(34+i) for i in range(3)]), modeName = 'carpassenger')) | 309 counts.append(LineCrossing(line, datetime(2020,7,2,23,15), group = Group([Person(AgeEnum(6+i)) for i in range(3)]), modeName = 'car_passenger')) |
| 300 | 310 |
| 301 | 311 counts.append(ZoneCrossing(zone, datetime(2020,7,7,9,5), True, person = Person('adult', 'male', False, False, True, False))) |
| 302 counts.append(ZoneCrossing(zone, datetime(2020,7,7,9,5), True, person = Person(33, 'male', False, False, True, False))) | |
| 303 | 312 |
| 304 session.add_all([line, p, zone, group1, destination]+modes+groupMode1+counts+activities) | 313 session.add_all([line, p, zone, group1, destination]+modes+groupMode1+counts+activities) |
| 305 | 314 |
| 306 session.commit() | 315 session.commit() |
| 307 session.close() | 316 session.close() |
