Skip to content

Commit 2c60b36

Browse files
authored
Develop (#4)
* classes, tests * fix ci * fix ci * fix ci * fix ci
1 parent 8f7a7bd commit 2c60b36

7 files changed

Lines changed: 99 additions & 35 deletions

File tree

.github/workflows/push.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,4 @@ jobs:
3838
python -m venv venv
3939
source venv/bin/activate
4040
python setup.py install
41-
python -c "from esridumpgdf import layer_to_gdf"
41+
python -c "from esridumpgdf import Layer, Service"

README.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
# esridumpgdf
22

3-
Export ArcGIS Map and Feature services to GeoDataFrame
4-
5-
3+
Simple functions using [pyesridump](https://github.com/openaddresses/pyesridump)
4+
and [geopandas](https://github.com/geopandas/geopandas) to create GeoDataFrames.
65

76
## Install
87
```
98
pip install git+https://github.com/wchatx/esridumpgdf.git
10-
```
9+
```
10+
11+
## Usage
12+
For exporting a single Map or Feature service to GeoDataFrame:
13+
```python
14+
15+
```
16+

esridumpgdf/__init__.py

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,2 @@
1-
from pandas import to_datetime
2-
from geopandas import GeoDataFrame
3-
from esridump.dumper import EsriDumper
4-
5-
6-
def layer_to_gdf(url: str, **kwargs) -> GeoDataFrame:
7-
"""
8-
Export an ArcGIS Server Map or Feature service to GeoDataFrame
9-
10-
::
11-
from esridumpgdf import layer_to_gdf
12-
layer = 'https://sampleserver6.arcgisonline.com/arcgis/rest/services/911CallsHotspot/MapServer/1'
13-
gdf = layer_to_gdf(layer)
14-
15-
:param url: url of the esri layer
16-
:return: GeoDataFrame
17-
"""
18-
crs = kwargs.get('crs') or 4326
19-
layer = EsriDumper(url, outSR=crs, **kwargs)
20-
gdf = GeoDataFrame.from_features(features=layer, crs=crs)
21-
for field in layer.get_metadata()['fields']:
22-
if field['type'] == 'esriFieldTypeOID':
23-
gdf.set_index(field['name'], inplace=True)
24-
if field['type'] == 'esriFieldTypeDate':
25-
gdf[field['name']] = to_datetime(gdf[field['name']], unit='ms')
26-
return gdf
1+
from .layer import Layer
2+
from .service import Service

esridumpgdf/base.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from requests import Session
2+
3+
4+
class Base(object):
5+
def __init__(self, url, **kwargs):
6+
self.url = url
7+
self.session = kwargs.get('session') or Session()
8+
9+
@property
10+
def meta(self) -> dict:
11+
return self.session.get(self.url, params=dict(f='pjson')).json()

esridumpgdf/layer.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from pandas import to_datetime
2+
from geopandas import GeoDataFrame
3+
from esridump.dumper import EsriDumper
4+
5+
from .base import Base
6+
7+
8+
class Layer(Base):
9+
def __init__(self, url: str, **kwargs):
10+
super(Layer, self).__init__(url, **kwargs)
11+
12+
def to_gdf(self, **kwargs) -> GeoDataFrame:
13+
crs = kwargs.get('crs') or 4326
14+
layer = EsriDumper(self.url, outSR=crs, **kwargs)
15+
16+
if self.meta['type'] == 'Group Layer':
17+
raise Exception('Provided URL is a Group Layer. This is currently unsupported')
18+
19+
gdf = GeoDataFrame.from_features(features=layer, crs=crs)
20+
for field in self.meta['fields']:
21+
if field['type'] == 'esriFieldTypeOID':
22+
gdf.set_index(field['name'], inplace=True)
23+
if field['type'] == 'esriFieldTypeDate':
24+
gdf[field['name']] = to_datetime(gdf[field['name']], unit='ms')
25+
if field['type'] == 'esriFieldTypeInteger':
26+
gdf[field['name']] = gdf[field['name']].astype('Int64')
27+
return gdf

esridumpgdf/service.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
from collections import OrderedDict
2+
from typing import List, Dict
3+
4+
from geopandas import GeoDataFrame
5+
6+
from .base import Base
7+
from .layer import Layer
8+
9+
10+
class Service(Base):
11+
def __init__(self, url, **kwargs):
12+
super(Service, self).__init__(url, **kwargs)
13+
14+
@property
15+
def layers(self) -> List[dict]:
16+
return self.meta['layers']
17+
18+
@property
19+
def tables(self) -> List[dict]:
20+
return self.meta['tables']
21+
22+
def to_gdfs(self, include_tables=True, **kwargs) -> Dict[str, GeoDataFrame]:
23+
"""
24+
Export a complete ArcGIS Server Map or Feature service to list of GeoDataFrames
25+
26+
"""
27+
layers = [layer for layer in self.meta['layers'] if layer['type'] != 'Group Layer']
28+
tables = self.meta['tables']
29+
gdfs = OrderedDict(
30+
{layer['name']: Layer(f'{self.url}/{layer["id"]}', **kwargs).to_gdf()
31+
for layer in sorted(layers, key=lambda _: _['name'])}
32+
)
33+
if tables and include_tables:
34+
gdfs.update({table['name']: Layer(f'{self.url}/{table["id"]}').to_gdf() for table in tables})
35+
gdfs = sorted(gdfs.items())
36+
return gdfs

tests.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
1-
from esridumpgdf import layer_to_gdf
1+
from collections import OrderedDict
2+
3+
from esridumpgdf import Layer, Service
24

35

46
def test_layer_to_gdf():
57
layer = 'https://sampleserver6.arcgisonline.com/arcgis/rest/services/911CallsHotspot/MapServer/1'
6-
gdf = layer_to_gdf(layer)
8+
gdf = Layer(layer).to_gdf()
79

810
assert gdf.shape[0]
911
assert gdf.index.name == 'FID'
12+
assert gdf.geometry.name == 'geometry'
13+
14+
15+
def test_service_to_gdfs():
16+
service = 'https://sampleserver6.arcgisonline.com/arcgis/rest/services/Wildfire/MapServer'
17+
gdfs = Service(service).to_gdfs()
1018

19+
assert gdfs
20+
assert isinstance(gdfs, OrderedDict)
1121

12-
if __name__ == '__main__':
13-
test_layer_to_gdf()

0 commit comments

Comments
 (0)