Skip to content

Commit

Permalink
Merge b6aa0fd into e5e2037
Browse files Browse the repository at this point in the history
  • Loading branch information
fscottfoti committed Sep 2, 2014
2 parents e5e2037 + b6aa0fd commit 912173e
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 9 deletions.
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ install:
- sudo conda init
- sudo conda update --yes conda
- |
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"
conda create -p $HOME/py --yes fiona ipython-notebook jinja2 matplotlib numpy pandas patsy pip scipy statsmodels pandana pytables pytest pyyaml shapely toolz "python=$TRAVIS_PYTHON_VERSION" -c "synthicity"
- export PATH=$HOME/py/bin:$PATH
- pip install simplejson bottle
- pip install simplejson bottle geopandas
- pip install pytest-cov coveralls pep8
- pip install .
before_script:
Expand Down
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
'toolz>=0.7.0'
],
extras_require = {
'pandana': ['pandana>=0.1']
'pandana': ['pandana>=0.1'],
'geopandas': ['geopandas>=0.1.0']
}
)
8 changes: 8 additions & 0 deletions urbansim/maps/dframe_explorer.html
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,11 @@

function style_f(feature) {
if(data && q) {
{% if geom_name %}
var val = data[feature.properties[GEOMNAME]];
{% else %}
var val = data[feature.id];
{% endif %}
var v = q(val);
}
fo = .7;
Expand All @@ -225,7 +229,11 @@
shapeLayer = new L.geoJson(zones, {
style: style_f,
onEachFeature: function (feature, layer) {
{% if geom_name %}
feature_d[feature.properties[GEOMNAME]] = layer;
{% else %}
feature_d[feature.id] = layer;
{% endif %}
//layer.bindPopup("No value");
}
});
Expand Down
91 changes: 87 additions & 4 deletions urbansim/maps/dframe_explorer.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import numpy as np
import pandas as pd
import os
import json
import webbrowser
from jinja2 import Environment


Expand Down Expand Up @@ -60,6 +62,8 @@ def index():

@route('/data/<filename>')
def data_static(filename):
if filename == "internal":
return SHAPES
return static_file(filename, root='./data')


Expand Down Expand Up @@ -89,10 +93,12 @@ def start(views,
zoom : int
The initial zoom level of the map
shape_json : str
The path to the geojson file which contains that shapes that will be
displayed
Can either be the geojson itself or the path to a file which contains
the geojson that describes the shapes to display (uses os.path.exists
to check for a file on the filesystem)
geom_name : str
The field name from the JSON file which contains the id of the geometry
The field name from the JSON file which contains the id of the
geometry - if it's None, use the id of the geojson feature
join_name : str
The column name from the dataframes passed as views (must be in each
view) which joins to geom_name in the shapes
Expand All @@ -111,9 +117,19 @@ def start(views,
queries from a web browser
"""

global DFRAMES, CONFIG
global DFRAMES, CONFIG, SHAPES
DFRAMES = {str(k): views[k] for k in views}

if not testing and not os.path.exists(shape_json):
# if the file doesn't exist, we try to use it as json
try:
json.loads(shape_json)
except:
assert 0, "The json passed in appears to be neither a parsable " \
"json format nor a file that exists on the file system"
SHAPES = shape_json
shape_json = "data/internal"

config = {
'center': str(center),
'zoom': zoom,
Expand All @@ -135,4 +151,71 @@ def start(views,
if testing:
return

# open in a new tab, if possible
webbrowser.open("http://%s:%s" % (host, port), new=2)

run(host=host, port=port, debug=True)


def gdf_explore(gdf,
dataframe_d=None,
center=None,
zoom=11,
geom_name=None, # from JSON file, use index if None
join_name='zone_id', # from data frames
precision=2,
port=8765,
host='localhost',
testing=False):
"""
This method wraps the start method above, but for displaying a geopandas
geodataframe. The parameters are the same as above but many are optional
and the defaults can be derived from the dataframe in the following way.
You are responsible for converting to crs 4326 - using the to_crs method
on the geodataframe (since we don't want to do this conversion every time
and geopandas doesn't check the current crs before converting).
If you don't pass a dataframe_d, only the fields directly on the
geodataframe will be available. The center will be derived from the
center of the dataframe's bounding box. The geom_name is optional and if
it is not set or set to None, the index of the geodataframe will be used
for joining attributes to shapes. Obviously shape_json in the above
method is not used - the shapes on the geodataframe are used directly.
"""
try:
import geopandas
except:
raise ImportError("This method requires that geopandas be installed "
"in order to work correctly")

if dataframe_d is None:
dataframe_d = {}

# add the geodataframe
df = pd.DataFrame(gdf)
if geom_name is None:
df[join_name] = df.index
dataframe_d["local"] = df

# need to check if it's already 4326
# gdf = gdf.to_crs(epsg=4326)

bbox = gdf.total_bounds
if center is None:
center = [(bbox[1]+bbox[3])/2, (bbox[0]+bbox[2])/2]

gdf.to_json()

start(
dataframe_d,
center=center,
zoom=zoom,
shape_json=gdf.to_json(),
geom_name=geom_name, # from JSON file
join_name=join_name, # from data frames
precision=precision,
port=port,
host=host,
testing=testing
)
1 change: 1 addition & 0 deletions urbansim/maps/tests/test.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"type": "FeatureCollection", "features": [{"geometry": {"type": "Polygon", "coordinates": [[[-122.38925866249373, 37.76310903745636], [-122.38927146704587, 37.7632459782484], [-122.38891986285451, 37.76326717960533], [-122.38890672864976, 37.76313025861109], [-122.38925866249373, 37.76310903745636]]]}, "type": "Feature", "id": "92050", "properties": {"new_residential_units": 23, "max_height_per_zoning": 68.0, "max_far_per_zoning": 5.0, "acquisition_cost": "4,060,000", "current_use": "Flat & Store", "current_building_sqft": "3,400", "new_building_sqft": "25,000", "google_maps": "<a href=\"https://maps.google.com/maps?q=2092+3RD+ST%2C+San+Francisco%2C+CA\">Click.</a>", "average_sales_price_sqft": 932, "parcel_size": "5,000", "address": "2092 3RD ST", "new_building_revenue": "16,620,000", "new_building_cost": "7,570,000", "fill": "yellow"}}]}
22 changes: 20 additions & 2 deletions urbansim/maps/tests/test_explorer.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import pytest
import os
import pandas as pd
import geopandas as gpd

from .. import dframe_explorer

Expand All @@ -12,6 +14,12 @@ def simple_map_input():
index=['a', 'b', 'c'])


@pytest.fixture
def simple_geojson():
return gpd.read_file(os.path.join(os.path.dirname(__file__),
"test.geojson"))


def test_explorer(simple_map_input):
dframe_explorer.enable_cors()
dframe_explorer.ans_options()
Expand All @@ -20,9 +28,11 @@ def test_explorer(simple_map_input):
d = {"dfname": simple_map_input}
dframe_explorer.start(d, testing=True)

dframe_explorer.map_query("dfname", "empty", "zone_id", "test_var", "mean()")
dframe_explorer.map_query("dfname", "empty", "zone_id", "test_var",
"mean()")

dframe_explorer.map_query("dfname", "empty", "zone_id", "test_var > 1", "mean()")
dframe_explorer.map_query("dfname", "empty", "zone_id", "test_var > 1",
"mean()")

dframe_explorer.index()

Expand All @@ -33,3 +43,11 @@ def test_explorer(simple_map_input):

with pytest.raises(Exception):
dframe_explorer.start(d, testing=True)


def test_geodf_explorer(simple_map_input, simple_geojson):

d = {"dfname": simple_map_input}
dframe_explorer.gdf_explore(simple_geojson, dataframe_d=d, testing=True)

dframe_explorer.gdf_explore(simple_geojson, testing=True)

0 comments on commit 912173e

Please sign in to comment.