From 04eccddf82c9c142277f3a3148c5d4a95fc681f3 Mon Sep 17 00:00:00 2001 From: Fletcher Foti Date: Fri, 22 Aug 2014 11:36:15 -0700 Subject: [PATCH 1/4] code to append the filters --- urbansim/utils/pnetworks.py | 58 +++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 urbansim/utils/pnetworks.py diff --git a/urbansim/utils/pnetworks.py b/urbansim/utils/pnetworks.py new file mode 100644 index 00000000..51114e50 --- /dev/null +++ b/urbansim/utils/pnetworks.py @@ -0,0 +1,58 @@ +import yaml + +import numpy as np +import pandas as pd +import logging + +from . import misc +from ..models import util +import urbansim.sim.simulation as sim + +logger = logging.getLogger(__name__) + + +def from_yaml(net, cfgname): + print "Computing accessibility variables" + cfg = yaml.load(open(misc.config(cfgname))) + + nodes = pd.DataFrame(index=net.node_ids) + + assert "node_col" in cfg, "Need to specify from where to take the node id" + node_col = cfg.get('node_col') + + for variable in cfg['variable_definitions']: + + name = variable["name"] + print "Computing %s" % name + + decay = variable.get("decay", "linear") + agg = variable.get("aggregation", "sum") + vname = variable.get("varname", None) + radius = variable["radius"] + dfname = variable["dataframe"] + + flds = [vname] if vname else [] + flds.append(node_col) + if "filters" in variable: + flds += util.columns_in_filters(variable["filters"]) + logger.info(" Fields available to aggregate =", ', '.join(flds)) + + df = sim.get_table(dfname).to_frame(flds) + + if "filters" in variable: + df = util.apply_filter_query(df, variable["filters"]) + logger.info(" Filters = %s" % variable["filters"]) + + logger.info(" dataframe = %s, varname=%s" % (dfname, vname)) + logger.info(" radius = %s, aggregation = %s, decay = %s" % ( + radius, agg, decay)) + + # set the variable + net.set(df[node_col], variable=df[vname] if vname else None) + # aggregate it + nodes[name] = net.aggregate(radius, type=agg, decay=decay) + + if "apply" in variable: + nodes[name] = nodes[name].apply(eval(variable["apply"])) + + return nodes \ No newline at end of file From 7047e206c19d9dabc8d1c351f84f0638c6a11958 Mon Sep 17 00:00:00 2001 From: Fletcher Foti Date: Fri, 22 Aug 2014 11:41:18 -0700 Subject: [PATCH 2/4] pep8 --- urbansim/utils/pnetworks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/urbansim/utils/pnetworks.py b/urbansim/utils/pnetworks.py index 51114e50..0e4967c4 100644 --- a/urbansim/utils/pnetworks.py +++ b/urbansim/utils/pnetworks.py @@ -55,4 +55,4 @@ def from_yaml(net, cfgname): if "apply" in variable: nodes[name] = nodes[name].apply(eval(variable["apply"])) - return nodes \ No newline at end of file + return nodes From da9aeac7d1000be8a368ba2dc415d186c403f13c Mon Sep 17 00:00:00 2001 From: Fletcher Foti Date: Tue, 2 Sep 2014 11:49:13 -0700 Subject: [PATCH 3/4] adding tests for using pandana with urbansim --- .travis.yml | 2 +- setup.py | 5 +- urbansim/utils/networks.py | 129 +++----------------------- urbansim/utils/pnetworks.py | 58 ------------ urbansim/utils/tests/osm_sample.h5 | Bin 0 -> 102264 bytes urbansim/utils/tests/test_networks.py | 91 ++++++++++++++++++ 6 files changed, 110 insertions(+), 175 deletions(-) delete mode 100644 urbansim/utils/pnetworks.py create mode 100644 urbansim/utils/tests/osm_sample.h5 create mode 100644 urbansim/utils/tests/test_networks.py diff --git a/.travis.yml b/.travis.yml index 06d22229..c81abeab 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ install: - sudo pip install conda - sudo conda init - | - conda create -p $HOME/py --yes ipython-notebook jinja2 matplotlib numpy pandas patsy pip scipy statsmodels pytables pytest pyyaml toolz "python=$TRAVIS_PYTHON_VERSION" + conda create -p $HOME/py --yes ipython-notebook jinja2 matplotlib numpy pandas patsy pip scipy statsmodels pandana pytables pytest pyyaml toolz "python=$TRAVIS_PYTHON_VERSION" -c "synthicity" - export PATH=$HOME/py/bin:$PATH - pip install simplejson bottle - pip install pytest-cov coveralls pep8 diff --git a/setup.py b/setup.py index c7dbba6c..4d258c85 100644 --- a/setup.py +++ b/setup.py @@ -33,5 +33,8 @@ 'statsmodels>=0.5.0', 'tables>=3.1.0', 'toolz>=0.7.0' - ] + ], + extras_require = { + 'pandana': ['pandana>=0.1'] + } ) diff --git a/urbansim/utils/networks.py b/urbansim/utils/networks.py index 3f2ca5c8..0e4967c4 100644 --- a/urbansim/utils/networks.py +++ b/urbansim/utils/networks.py @@ -1,4 +1,3 @@ -import cPickle import yaml import numpy as np @@ -11,46 +10,32 @@ logger = logging.getLogger(__name__) -NETWORKS = None - -def from_yaml(cfgname): +def from_yaml(net, cfgname): print "Computing accessibility variables" cfg = yaml.load(open(misc.config(cfgname))) - nodes = pd.DataFrame(index=NETWORKS.external_nodeids) + nodes = pd.DataFrame(index=net.node_ids) - node_col = cfg.get('node_col', None) + assert "node_col" in cfg, "Need to specify from where to take the node id" + node_col = cfg.get('node_col') for variable in cfg['variable_definitions']: name = variable["name"] print "Computing %s" % name - decay = { - "exponential": "DECAY_EXP", - "linear": "DECAY_LINEAR", - "flat": "DECAY_FLAT" - }.get(variable.get("decay", "linear")) - - agg = { - "sum": "AGG_SUM", - "average": "AGG_AVE", - "stddev": "AGG_STDDEV" - }.get(variable.get("aggregation", "sum")) - + decay = variable.get("decay", "linear") + agg = variable.get("aggregation", "sum") vname = variable.get("varname", None) - radius = variable["radius"] - dfname = variable["dataframe"] flds = [vname] if vname else [] - if 'add_fields' in variable: - flds += variable['add_fields'] - if node_col: - flds.append(node_col) - logger.info(" Fields available to accvar =", ', '.join(flds)) + flds.append(node_col) + if "filters" in variable: + flds += util.columns_in_filters(variable["filters"]) + logger.info(" Fields available to aggregate =", ', '.join(flds)) df = sim.get_table(dfname).to_frame(flds) @@ -62,98 +47,12 @@ def from_yaml(cfgname): logger.info(" radius = %s, aggregation = %s, decay = %s" % ( radius, agg, decay)) - nodes[name] = NETWORKS.accvar( - df, radius, node_ids=node_col, agg=agg, decay=decay, - vname=vname).astype('float').values + # set the variable + net.set(df[node_col], variable=df[vname] if vname else None) + # aggregate it + nodes[name] = net.aggregate(radius, type=agg, decay=decay) if "apply" in variable: nodes[name] = nodes[name].apply(eval(variable["apply"])) return nodes - - -class Networks: - - # flatten_nodeids is used when there is one graph to make a list of nodeids - # rather than a list of lists - it doesn't work right now unfortunately - def __init__(self, filenames, factors, maxdistances, twoway, - impedances=None, flatten_nodeids=False): - if not filenames: - return - from pyaccess.pyaccess import PyAccess - self.pya = PyAccess() - self.pya.createGraphs(len(filenames)) - if impedances is None: - impedances = [None] * len(filenames) - self.nodeids = [] - self.external_nodeids = [] - for num, filename, factor, maxdistance, twoway, impedance in \ - zip(range(len(filenames)), filenames, factors, maxdistances, - twoway, impedances): - net = cPickle.load(open(filename)) - if impedance is None: - impedance = "net['edgeweights']" - impedance = eval(impedance) - self.pya.createGraph( - num, net['nodeids'], net['nodes'], net['edges'], - impedance * factor, twoway=twoway) - if len(filenames) == 1 and flatten_nodeids: - self.nodeids = net['nodeids'] - else: - # these are the internal ids - self.nodeids += zip([num] * len(net['nodeids']), - range(len(net['nodeids']))) - self.external_nodeids.append(net['nodeids']) - self.pya.precomputeRange(maxdistance, num) - - def accvar(self, df, distance, node_ids=None, xname='x', yname='y', - vname=None, agg="AGG_SUM", decay="DECAY_LINEAR"): - assert self.pya # need to generate pyaccess first - pya = self.pya - if isinstance(agg, str): - agg = getattr(pya, agg) - if isinstance(decay, str): - decay = getattr(pya, decay) - if vname: - df = df.dropna(subset=[vname]) - if node_ids is None: - xys = np.array(df[[xname, yname]], dtype="float32") - node_ids = [] - for gno in range(pya.numgraphs): - node_ids.append(pya.XYtoNode(xys, distance=1000, gno=gno)) - if isinstance(node_ids, str): - l = len(df) - df = df.dropna(subset=[node_ids]) - newl = len(df) - if newl-l > 0: - print "Removed %d rows because there are no node_ids" % (newl-l) - node_ids = [df[node_ids].astype("int32").values] - elif not isinstance(node_ids, list): - node_ids = [node_ids] - - pya.initializeAccVars(1) - num = 0 - aggvar = df[vname].astype('float32') if vname is not None else np.ones( - len(df.index), dtype='float32') - pya.initializeAccVar(num, node_ids, aggvar, preaggregate=0) - res = [] - for gno in range(pya.numgraphs): - res.append(pya.getAllAggregateAccessibilityVariables( - distance, num, agg, decay, gno=gno)) - return pd.Series( - np.concatenate(res), index=pd.MultiIndex.from_tuples(self.nodeids)) - - def addnodeid(self, df): - - try: - xys = np.array(df[['x', 'y']], dtype="float32") - except: - xys = np.array(df[['X', 'Y']], dtype="float32") - - for gno in range(self.pya.numgraphs): - df['_node_id%d' % gno] = pd.Series( - self.pya.XYtoNode(xys, gno=gno), index=df.index) - # assign the external id as well - df['_node_id'] = pd.Series(self.pya.getGraphIDS()[df['_node_id0'].values], - index=df.index) - return df diff --git a/urbansim/utils/pnetworks.py b/urbansim/utils/pnetworks.py deleted file mode 100644 index 0e4967c4..00000000 --- a/urbansim/utils/pnetworks.py +++ /dev/null @@ -1,58 +0,0 @@ -import yaml - -import numpy as np -import pandas as pd -import logging - -from . import misc -from ..models import util -import urbansim.sim.simulation as sim - -logger = logging.getLogger(__name__) - - -def from_yaml(net, cfgname): - print "Computing accessibility variables" - cfg = yaml.load(open(misc.config(cfgname))) - - nodes = pd.DataFrame(index=net.node_ids) - - assert "node_col" in cfg, "Need to specify from where to take the node id" - node_col = cfg.get('node_col') - - for variable in cfg['variable_definitions']: - - name = variable["name"] - print "Computing %s" % name - - decay = variable.get("decay", "linear") - agg = variable.get("aggregation", "sum") - vname = variable.get("varname", None) - radius = variable["radius"] - dfname = variable["dataframe"] - - flds = [vname] if vname else [] - flds.append(node_col) - if "filters" in variable: - flds += util.columns_in_filters(variable["filters"]) - logger.info(" Fields available to aggregate =", ', '.join(flds)) - - df = sim.get_table(dfname).to_frame(flds) - - if "filters" in variable: - df = util.apply_filter_query(df, variable["filters"]) - logger.info(" Filters = %s" % variable["filters"]) - - logger.info(" dataframe = %s, varname=%s" % (dfname, vname)) - logger.info(" radius = %s, aggregation = %s, decay = %s" % ( - radius, agg, decay)) - - # set the variable - net.set(df[node_col], variable=df[vname] if vname else None) - # aggregate it - nodes[name] = net.aggregate(radius, type=agg, decay=decay) - - if "apply" in variable: - nodes[name] = nodes[name].apply(eval(variable["apply"])) - - return nodes diff --git a/urbansim/utils/tests/osm_sample.h5 b/urbansim/utils/tests/osm_sample.h5 new file mode 100644 index 0000000000000000000000000000000000000000..31e59c6e671c3167f1a39431fe0bb3a7d358e79b GIT binary patch literal 102264 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⁡Fv_ehTY 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 .1 + """ + + f = open(test_file, "w") + f.write(s) + f.close() + + df = networks.from_yaml(sample_osm, test_file) + + assert len(df) == 1498 + assert df.describe()['test_attr']['max'] > 0 + assert df.describe()['test_attr']['min'] == 0 + assert df.describe()['test_attr']['std'] > 0 + ind = pd.Series(df.index).describe() + assert ind.loc['min'] > 0 + assert ind.loc['count'] == 1498 + + From a382bb920f411914c0b80ae4418f4fb2a1f0bf6d Mon Sep 17 00:00:00 2001 From: Fletcher Foti Date: Tue, 2 Sep 2014 11:50:05 -0700 Subject: [PATCH 4/4] pep8 --- urbansim/utils/tests/test_networks.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/urbansim/utils/tests/test_networks.py b/urbansim/utils/tests/test_networks.py index 61b44842..41fafcdc 100644 --- a/urbansim/utils/tests/test_networks.py +++ b/urbansim/utils/tests/test_networks.py @@ -87,5 +87,3 @@ def source(): ind = pd.Series(df.index).describe() assert ind.loc['min'] > 0 assert ind.loc['count'] == 1498 - -