Skip to content
This repository was archived by the owner on Sep 22, 2025. It is now read-only.

Commit 5c9c2d1

Browse files
authored
Merge pull request #81 from StratoDem/78-drivetime
78 drivetime
2 parents 84d1e15 + 19efca6 commit 5c9c2d1

4 files changed

Lines changed: 128 additions & 7 deletions

File tree

CHANGELOG.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,30 @@
22

33
All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/).
44

5+
## [3.3.0] - 2019-09-18
6+
### Adds
7+
- Adds new buffer types to the `DrivetimeFilter`. It now supports:
8+
- `'drivetime'`
9+
- `'drivetime_simple'`
10+
- `'drivetime_unweighted'`
11+
- `'drivetime_destination'`
12+
- `'drivetime_destination_simple'`
13+
- `'drivetime_destination_unweighted'`
14+
- Adds a `WalktimeFilter` which supports the following types:
15+
- `'walktime'`
16+
- `'walktime_unweighted'`
17+
- `'walktime_destination'`
18+
- `'walktime_destination_unweighted'`
19+
- Adds `detailed_type` as a new optional argument to `OverlapsDrivetimeFilter` which allows:
20+
- `'overlaps_drivetime'`
21+
- `'overlaps_drivetime_destination'`
22+
- Adds `detailed_type` as a new optional argument to `OverlapsWalktimeFilter` which allows:
23+
- `'overlaps_walktime'`
24+
- `'overlaps_walktime_destination'`
25+
26+
## Related issues
27+
- [69](https://github.com/StratoDem/strato-query/issues/69)
28+
529
## [3.2.0] - 2019-09-10
630
### Adds
731
- Adds new query param classes

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
setup(
1515
name='strato_query',
16-
version='3.2.0',
16+
version='3.3.0',
1717
author='Michael Clawar, Raaid Arshad, Eric Linden',
1818
author_email='tech@stratodem.com',
1919
packages=[

strato_query/examples/examples.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,36 @@ def example_count_query(cls):
5858
print(df.head())
5959
print('Results truncated')
6060

61+
@classmethod
62+
def example_count_query_destination(cls):
63+
# Number of households ages 25-39 with net worth of at least $50,000
64+
# within 20-minute drive to a location South of Boston in the year 2017
65+
66+
df = cls.query_api_df(
67+
query_params=APIQueryParams(
68+
query_type='COUNT',
69+
table='networth_tract_annual_net_worth_age',
70+
data_fields=('year', 'age_g_bottom_coded', 'net_worth_g', 'households'),
71+
data_filters=(
72+
BetweenFilter(var='age_g_bottom_coded', val=[6, 8]).to_dict(),
73+
GreaterThanOrEqualToFilter(var='net_worth_g', val=3).to_dict(),
74+
EqualToFilter(var='year', val=2017).to_dict(),
75+
DrivetimeFilter(
76+
latitude=42.256922,
77+
longitude=-71.040571,
78+
detailed_type='drivetime_destination',
79+
minutes=20).to_dict(),
80+
),
81+
groupby=(),
82+
order=(),
83+
aggregations=(),
84+
)
85+
)
86+
87+
print('Number of households 25-39 with $50k+ net worth in 2017 in a 20 min drive to coord:')
88+
print(df.head())
89+
print('Results truncated')
90+
6191
@classmethod
6292
def example_query_with_area_join_and_aggregation(cls):
6393
# Population density in the Boston MSA by year prior to 2015
@@ -271,6 +301,8 @@ def example_pure_shape_union_query(cls):
271301
def run_examples():
272302
ExampleQueries.example_count_query()
273303
print('\n\n')
304+
ExampleQueries.example_count_query_destination()
305+
print('\n\n')
274306
ExampleQueries.example_query_with_area_join_and_aggregation()
275307
print('\n\n')
276308
ExampleQueries.example_median_query()

strato_query/filters.py

Lines changed: 71 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
'NotEqualToFilter',
2626
'NotInFilter',
2727
'DrivetimeFilter',
28+
'WalktimeFilter',
2829
'MileRadiusFilter',
2930
'IntersectsFilter',
3031
'OverlapsMileRadiusFilter',
@@ -166,20 +167,33 @@ def __init__(self,
166167
longitude: float
167168
Center longitude
168169
minutes: int or float
169-
Minutes drive from latitude-longitude center
170+
Minutes drive from or to latitude-longitude center
170171
detailed_type: str
171172
One of:
172173
- 'drivetime': use a normal drivetime, which weights results
173174
- 'drivetime_simple': use a drivetime with weights, but using simplified shapes
174175
- 'drivetime_unweighted': return unweighted results (used to get all geographies
175176
intersecting at all with the drive time area)
177+
- 'drivetime_destination': use a normal drivetime, which weights results, but the
178+
location is the destination instead of the start point
179+
- 'drivetime_destination_simple': use a drivetime with weights, but using simplified
180+
shapes, and the location as the destination
181+
- 'drivetime_destination_unweighted': return unweighted results (used to get all
182+
geographies intersecting at all with the drive time area), and use the location as
183+
the destination
176184
with_traffic: bool
177185
Use traffic estimates to compute the drive time area?
178186
start_time: str
179187
The departure time for the drivetime, used in concert with "with_traffic" set to True
180188
e.g., "2019-05-25T18:00:00"
181189
"""
182-
assert detailed_type in {'drivetime', 'drivetime_simple', 'drivetime_unweighted'}
190+
assert detailed_type in {
191+
'drivetime',
192+
'drivetime_simple',
193+
'drivetime_unweighted',
194+
'drivetime_destination',
195+
'drivetime_destination_simple',
196+
'drivetime_destination_unweighted'}
183197
assert isinstance(with_traffic, bool)
184198
assert start_time is None or isinstance(start_time, str)
185199

@@ -194,6 +208,49 @@ def __init__(self,
194208
start_time=start_time))
195209

196210

211+
class WalktimeFilter(BaseFilter):
212+
def __init__(self,
213+
latitude: float,
214+
longitude: float,
215+
minutes: Union[int, float],
216+
detailed_type: str = 'walktime'):
217+
"""
218+
Filter a query to geographies contained by the walktime area
219+
220+
Parameters
221+
----------
222+
latitude: float
223+
Center latitude
224+
longitude: float
225+
Center longitude
226+
minutes: int or float
227+
Minutes walk from latitude-longitude center
228+
detailed_type: str
229+
One of:
230+
- 'walktime': use a normal walktime, which weights results
231+
- 'walktime_unweighted': return unweighted results (used to get all geographies
232+
intersecting at all with the walk time area)
233+
- 'walktime_destination': use a normal walktime, which weights results, but the
234+
location is the destination instead of the start point
235+
- 'walktime_destination_unweighted': return unweighted results (used to get all
236+
geographies intersecting at all with the walk time area), and use the location as
237+
the destination
238+
"""
239+
assert detailed_type in {
240+
'walktime',
241+
'walktime_unweighted',
242+
'walktime_destination',
243+
'walktime_destination_unweighted'}
244+
245+
super().__init__(
246+
filter_type=detailed_type,
247+
filter_variable='',
248+
filter_value=dict(
249+
latitude=latitude,
250+
longitude=longitude,
251+
minutes=minutes))
252+
253+
197254
class IntersectsFilter(BaseFilter):
198255
def __init__(self, var: str, val: dict):
199256
super().__init__(
@@ -240,6 +297,7 @@ def __init__(self,
240297
latitude: float,
241298
longitude: float,
242299
minutes: Union[int, float],
300+
detailed_type: str = 'overlaps_drivetime',
243301
with_traffic: bool = False,
244302
start_time: Optional[str] = None):
245303
"""
@@ -252,7 +310,9 @@ def __init__(self,
252310
latitude: float
253311
longitude: float
254312
minutes: int or float
255-
Minutes drive from latitude-longitude center
313+
Minutes drive from or to the latitude-longitude center
314+
detailed_type: str
315+
One of either "overlaps_drivetime" or "overlaps_drivetime_destination"
256316
with_traffic: bool
257317
Use traffic estimates to compute the drive time area?
258318
start_time: str
@@ -265,9 +325,10 @@ def __init__(self,
265325
assert isinstance(minutes, (int, float))
266326
assert with_traffic is None or isinstance(with_traffic, bool)
267327
assert start_time is None or isinstance(start_time, str)
328+
assert detailed_type in {'overlaps_drivetime', 'overlaps_drivetime_destination'}
268329

269330
super().__init__(
270-
filter_type='overlaps_drivetime',
331+
filter_type=detailed_type,
271332
filter_variable=var,
272333
filter_value=dict(
273334
latitude=latitude,
@@ -282,7 +343,8 @@ def __init__(self,
282343
var: str,
283344
latitude: float,
284345
longitude: float,
285-
minutes: Union[int, float]):
346+
minutes: Union[int, float],
347+
detailed_type: str = 'overlaps_walktime'):
286348
"""
287349
Filter a query by geometries overlapping the point's surrounding buffer
288350
@@ -294,14 +356,17 @@ def __init__(self,
294356
longitude: float
295357
minutes: int or float
296358
Minutes walk from latitude-longitude center
359+
detailed_type: str
360+
One of either "overlaps_walktime" or "overlaps_walktime_destination"
297361
"""
298362
assert isinstance(var, str)
299363
assert isinstance(latitude, float)
300364
assert isinstance(longitude, float)
301365
assert isinstance(minutes, (int, float))
366+
assert detailed_type in {'overlaps_walktime', 'overlaps_walktime_destination'}
302367

303368
super().__init__(
304-
filter_type='overlaps_walktime',
369+
filter_type=detailed_type,
305370
filter_variable=var,
306371
filter_value=dict(
307372
latitude=latitude,

0 commit comments

Comments
 (0)