Browse Source

vote places integration

Florian 4 years ago
parent
commit
f9014f2074
5 changed files with 136 additions and 24 deletions
  1. 54 0
      input/vote_places.csv
  2. 57 15
      plan_gen/plan_gen.py
  3. 21 7
      plan_gen/plan_gen_cli.py
  4. 1 1
      plan_gen/plan_visualizer.py
  5. 3 1
      setup.py

+ 54 - 0
input/vote_places.csv

@@ -0,0 +1,54 @@
+id;nbpeople;lat;lon
+1;1213;50.95256;1.854229
+2;1221;50.946741;1.860733
+3;1068;50.942518;1.856037
+4;1254;50.942518;1.856037
+5;1189;50.942518;1.856037
+6;918;50.940895;1.861631
+7;1132;50.940895;1.861631
+8;1060;50.940895;1.861631
+9;1003;50.93362;1.854266
+10;664;50.962632;1.839084
+11;757;50.960838;1.854921
+12;731;50.960838;1.854921
+13;859;50.960838;1.854921
+14;848;50.954038;1.870802
+15;1018;50.954038;1.870802
+16;896;50.954038;1.870802
+17;994;50.954038;1.870802
+18;1067;50.954038;1.870802
+19;1229;50.948125;1.867516
+20;973;50.948125;1.867516
+21;963;50.948125;1.867516
+22;1214;50.958244;1.888886
+23;681;50.941114;1.881785
+24;831;50.941114;1.881785
+25;1136;50.945744;1.873849
+26;1078;50.945744;1.873849
+27;859;50.945744;1.873849
+28;1213;50.948236;1.886017
+29;1197;50.948236;1.886017
+30;1094;50.948236;1.886017
+31;1125;50.953655;1.898363
+32;786;50.953655;1.898363
+33;732;50.953655;1.898363
+34;718;50.951447;1.90006
+35;632;50.948446;1.902447
+36;845;50.948446;1.902447
+37;1185;50.942199;1.885638
+38;572;50.956107;1.847995
+39;634;50.956107;1.847995
+40;894;50.948126;1.847472
+41;883;50.948126;1.847472
+42;1065;50.948126;1.847472
+43;948;50.944805;1.84784
+44;874;50.944805;1.84784
+45;993;50.943954;1.84265
+46;786;50.943954;1.84265
+47;862;50.93362;1.854266
+48;1016;50.947813;1.827438
+49;1114;50.947813;1.827438
+50;1146;50.947813;1.827438
+51;1171;50.958244;1.888886
+52;847;50.962632;1.839084
+53;789;50.947813;1.827438

+ 57 - 15
plan_gen/plan_gen.py

@@ -1,9 +1,11 @@
 #!/usr/bin/env python3
 ''' plan_gen main functions '''
 
-import time
-import numpy as np
 import lxml.etree as etree
+import numpy as np
+import pandas
+import time
+import utm
 
 # constants
 # ------------------
@@ -30,7 +32,7 @@ def parse_params(param_str):
     if param_str:
         for key_value_str in param_str.split(','):
             key, value = key_value_str.split('=')
-            if key in ['hc', 'wc']:
+            if key in ['hc', 'hw', 'wc', 'ww']:
                 coords = value.split('|')
                 dict_params[key] = [np.fromstring(str(x), dtype=int, sep=':') for x in coords]
             elif key in ['hr', 'wr']:
@@ -39,6 +41,34 @@ def parse_params(param_str):
                 dict_params[key] = parse_value(value)
     return dict_params
 
+def parse_latlon(csv):
+    ''' parse lat and lon from a csv '''
+    df = pandas.read_csv(csv, sep=';')
+    lat = df.lat.tolist()
+    lon = df.lon.tolist()
+    return lat, lon
+
+def parse_weights(csv):
+    ''' parse weights from a csv '''
+    df = pandas.read_csv(csv, sep=';')
+    weights = df.nbpeople.tolist()
+    return weights
+
+def latlon_to_utm(lat, lon):
+    ''' convert lat lon to utm coordinates '''
+    utms = [utm.from_latlon(a, b) for a, b in zip(lat, lon)]
+    xutm = [utm_coords[0] for utm_coords in utms]
+    yutm = [utm_coords[1] for utm_coords in utms]
+    return xutm, yutm
+
+def xy_to_ij(x, y, dx, dy, nb_clusters):
+    i, j = (int(x/dx), int(y/dy))
+    if i >= nb_clusters:
+        i -= 1
+    if j >= nb_clusters:
+        j -= 1
+    return i, j
+
 def get_seconds(time_str):
     ''' returns seconds from a time string '''
     h, m, s = time_str.split(':')
@@ -60,29 +90,34 @@ def make_gaussian(size, center=None, radius=10):
 
 def make_clusters(nb_clusters, nodes):
     ''' make a grid of (nb_clusters*nb_clusters) from a nodes list '''
-    xmin, xmax, ymin, ymax = get_extrem_nodes(nodes)
-    dx = (xmax - xmin) / nb_clusters
-    dy = (ymax - ymin) / nb_clusters
+    xmin, xmax, ymin, ymax, dx, dy = get_min_max_steps(nodes, nb_clusters)
     clusters = np.empty((nb_clusters, nb_clusters), dtype=object)
     for node in nodes:
         x, y = (float(node.get('x')) - xmin, float(node.get('y')) - ymin)
-        i, j = (int(x/dx), int(y/dy))
-        if i >= nb_clusters:
-            i -= 1
-        if j >= nb_clusters:
-            j -= 1
+        i, j = xy_to_ij(x, y, dx, dy, nb_clusters)
         if clusters[i][j] is None:
             clusters[i][j] = []
         clusters[i][j] += [node]
     return clusters
 
-def make_densities(nb_clusters, centers=None, radius=None):
+def make_centers(csv, nb_clusters, nodes):
+    ''' make centers from a csv file '''
+    lat, lon = parse_latlon(csv)
+    xutm, yutm = latlon_to_utm(lat, lon)
+    xmin, xmax, ymin, ymax, dx, dy = get_min_max_steps(nodes, nb_clusters)
+    centers = []
+    for x, y in zip(xutm, yutm):
+        i, j = xy_to_ij(x - xmin, y - ymin, dx, dy, nb_clusters)
+        centers.append([i, j])
+    return centers
+
+def make_densities(nb_clusters, centers=None, radius=None, weights=None):
     ''' make a list of gaussian probability densities '''
     if centers is None:
         return make_gaussian(nb_clusters, radius=nb_clusters/2)
     densities = np.zeros((nb_clusters, nb_clusters))
-    for n, c in enumerate(centers):
-        densities += make_gaussian(nb_clusters, center=c, radius=radius[n])
+    for n, (c, w) in enumerate(zip(centers, weights)):
+        densities += w * make_gaussian(nb_clusters, center=c, radius=radius[n])
     return densities
 
 def clean_densities(densities, clusters):
@@ -160,4 +195,11 @@ def get_extrem_nodes(nodes):
     ''' returns extremum coordinates of a nodeslist '''
     x = [float(node.get('x')) for node in nodes]
     y = [float(node.get('y')) for node in nodes]
-    return min(x), max(x), min(y), max(y)
+    return min(x), max(x), min(y), max(y)
+
+def get_min_max_steps(nodes, nb_clusters):
+    ''' returns min max steps '''
+    xmin, xmax, ymin, ymax = get_extrem_nodes(nodes)
+    dx = (xmax - xmin) / nb_clusters
+    dy = (ymax - ymin) / nb_clusters
+    return xmin, xmax, ymin, ymax, dx, dy

+ 21 - 7
plan_gen/plan_gen_cli.py

@@ -7,7 +7,7 @@ import numpy as np
 import joblib as jl
 import plan_gen.plan_gen as pg
 
-NB_CORES = 4
+NB_CORES = 8
 
 def run_rand_person(i):
     ''' parallelisation '''
@@ -24,19 +24,33 @@ if __name__ == '__main__':
     DICT_PARAMS = pg.parse_params(sys.argv[1])
 
     NB_CLUSTERS = DICT_PARAMS['nc']
-    NB_PERSONS = DICT_PARAMS['np']
+    NB_PERSONS  = DICT_PARAMS['np']
     INPUT_NETWORK = DICT_PARAMS['nw']
+    INPUT_HOMES = DICT_PARAMS['hcsv'] if 'hcsv' in DICT_PARAMS else None
+    INPUT_WORKS = DICT_PARAMS['wcsv'] if 'wcsv' in DICT_PARAMS else None
     H_CENTERS = DICT_PARAMS['hc'] if 'hc' in DICT_PARAMS else None
+    H_RADIUS  = DICT_PARAMS['hr'] if 'hr' in DICT_PARAMS else None
+    H_WEIGHTS = DICT_PARAMS['hw'] if 'hw' in DICT_PARAMS else None
     W_CENTERS = DICT_PARAMS['wc'] if 'wc' in DICT_PARAMS else None
-    H_RADIUS = DICT_PARAMS['hr'] if 'hr' in DICT_PARAMS else None
-    W_RADIUS = DICT_PARAMS['wr'] if 'wr' in DICT_PARAMS else None
+    W_RADIUS  = DICT_PARAMS['wr'] if 'wr' in DICT_PARAMS else None
+    W_WEIGHTS = DICT_PARAMS['ww'] if 'ww' in DICT_PARAMS else None
 
     # prepare data
     NODES = pg.get_nodes(INPUT_NETWORK)
     CLUSTERS = pg.make_clusters(NB_CLUSTERS, NODES)
-    H_DENSITIES = pg.make_densities(NB_CLUSTERS, H_CENTERS, H_RADIUS)
+
+    if (H_CENTERS is None and INPUT_HOMES):
+        H_CENTERS = pg.make_centers(INPUT_HOMES, NB_CLUSTERS, NODES)
+        H_WEIGHTS = pg.parse_weights(INPUT_HOMES)
+        H_RADIUS = np.full_like(H_WEIGHTS, 5)
+    if (W_CENTERS is None and INPUT_WORKS):
+        W_CENTERS = pg.make_centers(INPUT_WORKS, NB_CLUSTERS, NODES)
+        W_WEIGHTS = pg.parse_weights(INPUT_WORKS)
+        W_RADIUS = np.full_like(W_WEIGHTS, 5)
+
+    H_DENSITIES = pg.make_densities(NB_CLUSTERS, H_CENTERS, H_RADIUS, H_WEIGHTS)
     H_DENSITIES = pg.clean_densities(H_DENSITIES, CLUSTERS)
-    W_DENSITIES = pg.make_densities(NB_CLUSTERS, W_CENTERS, W_RADIUS)
+    W_DENSITIES = pg.make_densities(NB_CLUSTERS, W_CENTERS, W_RADIUS, W_WEIGHTS)
     W_DENSITIES = pg.clean_densities(W_DENSITIES, CLUSTERS)
 
     # make xml
@@ -48,4 +62,4 @@ if __name__ == '__main__':
     # print XML
     print('<?xml version="1.0" ?>')
     print('<!DOCTYPE plans SYSTEM "http://www.matsim.org/files/dtd/plans_v4.dtd">')
-    print(etree.tostring(PLANS, pretty_print=True).decode('utf-8'))
+    print(etree.tostring(PLANS, pretty_print=True).decode('utf-8'))

+ 1 - 1
plan_gen/plan_visualizer.py

@@ -43,7 +43,7 @@ if __name__ == '__main__':
     PERSONS_X = [float(coord.split('|')[0]) for coord in P_XY_UNIQUE]
     PERSONS_Y = [float(coord.split('|')[1]) for coord in P_XY_UNIQUE]
     SC = AX.scatter(PERSONS_X, PERSONS_Y,
-                     alpha=0.75, s=P_XY_COUNTS*10,
+                     alpha=0.75, s=P_XY_COUNTS*5,
                      c=P_XY_COUNTS, cmap='rainbow')
 
     # plot map

+ 3 - 1
setup.py

@@ -10,7 +10,9 @@ setup(
         'numpy', 
         'lxml',
         'matplotlib',
-        'joblib'
+        'joblib',
+        'pandas',
+        'utm'
     ],
 )