Skip to content

Commit

Permalink
Add FSA to deck.gl Polygon
Browse files Browse the repository at this point in the history
(cherry picked from commit 600d580)
(cherry picked from commit 1fe113a)
(cherry picked from commit f56b291)
(cherry picked from commit 66e8955)
(cherry picked from commit 112a2b7)
(cherry picked from commit 8cddc63)
  • Loading branch information
betodealmeida authored and xtinec committed Mar 26, 2019
1 parent f3fc08a commit 896e1cf
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 3 deletions.
25 changes: 25 additions & 0 deletions superset/assets/src/explore/components/controls/SpatialControl.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const spatialTypes = {
delimited: 'delimited',
geohash: 'geohash',
zipcode: 'zipcode',
fsa: 'fsa',
};

const propTypes = {
Expand Down Expand Up @@ -65,6 +66,7 @@ export default class SpatialControl extends React.Component {
reverseCheckbox: v.reverseCheckbox || false,
geohashCol: v.geohashCol || defaultCol,
zipcodeCol: v.zipcodeCol || defaultCol,
fsaCol: v.fsaCol || defaultCol,
value: null,
errors: [],
};
Expand Down Expand Up @@ -105,6 +107,12 @@ export default class SpatialControl extends React.Component {
if (!value.zipcodeCol) {
errors.push(errMsg);
}
} else if (type === spatialTypes.fsa) {
value.fsaCol = this.state.fsaCol;
value.reverseCheckbox = this.state.reverseCheckbox;
if (!value.fsaCol) {
errors.push(errMsg);
}
}
this.setState({ value, errors });
this.props.onChange(value, errors);
Expand All @@ -130,6 +138,8 @@ export default class SpatialControl extends React.Component {
return `${this.state.geohashCol}`;
} else if (this.state.type === spatialTypes.zipcode) {
return `${this.state.zipcodeCol}`;
} else if (this.state.type === spatialTypes.fsa) {
return `${this.state.fsaCol}`;
}
return null;
}
Expand Down Expand Up @@ -224,6 +234,21 @@ export default class SpatialControl extends React.Component {
</Col>
</Row>
</PopoverSection>
<PopoverSection
title={t('FSA')}
isSelected={this.state.type === spatialTypes.fsa}
onSelect={this.setType.bind(this, spatialTypes.fsa)}
>
<Row>
<Col md={6}>
Column
{this.renderSelect('fsaCol', spatialTypes.fsa)}
</Col>
<Col md={6}>
{this.renderReverseCheckbox()}
</Col>
</Row>
</PopoverSection>
<div className="clearfix">
<Button
bsSize="small"
Expand Down
1 change: 1 addition & 0 deletions superset/assets/src/explore/controls.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2253,6 +2253,7 @@ export const controls = {
['json', 'JSON'],
['geohash', 'geohash (square)'],
['zipcode', 'ZIP code'],
['fsa', 'FSA'],
],
},

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export function commonLayerProps(formData, setTooltip, onSelect) {
let tooltipContentGenerator;
if (fd.jsTooltip) {
tooltipContentGenerator = sandboxedEval(fd.jsTooltip);
} else if (fd.lineColumn && fd.metric && ['geohash', 'zipcode'].indexOf(fd.lineType) >= 0) {
} else if (fd.lineColumn && fd.metric && ['geohash', 'zipcode', 'fsa'].indexOf(fd.lineType) >= 0) {
const metricLabel = fd.metric.label || fd.metric;
tooltipContentGenerator = o => (
<div>
Expand Down
64 changes: 62 additions & 2 deletions superset/viz.py
Original file line number Diff line number Diff line change
Expand Up @@ -2129,6 +2129,8 @@ def get_spatial_columns(self, key):
return [spatial.get('geohashCol')]
elif spatial.get('type') == 'zipcode':
return [spatial.get('zipcodeCol')]
elif spatial.get('type') == 'fsa':
return [spatial.get('fsaCol')]

@staticmethod
def parse_coordinates(s):
Expand All @@ -2151,6 +2153,11 @@ def reverse_zipcode_decode(zipcode):
raise NotImplementedError(
'No mapping from ZIP code to single latitude/longitude')

@staticmethod
def reverse_fsa_decode(fsa):
raise NotImplementedError(
'No mapping from FSA code to single latitude/longitude')

@staticmethod
def reverse_latlong(df, key):
df[key] = [
Expand Down Expand Up @@ -2179,6 +2186,9 @@ def process_spatial_data_obj(self, key, df):
elif spatial.get('type') == 'zipcode':
df[key] = df[spatial.get('zipcodeCol')].map(self.reverse_zipcode_decode)
del df[spatial.get('zipcodeCol')]
elif spatial.get('type') == 'fsa':
df[key] = df[spatial.get('fsaCol')].map(self.reverse_fsa_decode)
del df[spatial.get('fsaCol')]

if spatial.get('reverseCheckbox'):
self.reverse_latlong(df, key)
Expand Down Expand Up @@ -2377,6 +2387,15 @@ def deser(zipcode):
return deser


def fsa_deser(fsas):
geojson = fsas_to_json(fsas)

def deser(fsa):
if fsa in geojson:
return geojson[fsa][0][0]
return deser


def zipcodes_to_json(zipcodes):
user = os.environ.get('CREDENTIALS_LYFTPG_USER', '')
password = os.environ.get('CREDENTIALS_LYFTPG_PASSWORD', '')
Expand All @@ -2400,7 +2419,7 @@ def zipcodes_to_json(zipcodes):
if not missing:
return out

# fetch missing geojson from lyftpg
# fetch missing geojson from
in_clause = ', '.join(['%s'] * len(missing))
query = (
'SELECT zipcode, geojson FROM zip_codes WHERE zipcode IN ({0})'
Expand All @@ -2420,6 +2439,43 @@ def zipcodes_to_json(zipcodes):
return out


def fsas_to_json(fsas):
url = 'presto://prestoproxy.lyft.net:8443/hive'

out = {}
missing = set()
for fsa in fsas:
cache_key = 'fsa_geojson_{}'.format(fsa)
geojson = cache and cache.get(cache_key)
if geojson:
out[fsa] = geojson
else:
missing.add(fsa)

if not missing:
return out

# fetch missing geojson from lyftpg
in_clause = ', '.join(['%s'] * len(missing))
query = (
'SELECT fsa, geo_json FROM jbridgem.test_geo_json_fsa WHERE fsa IN ({0})'
.format(in_clause))
conn = sqlalchemy.create_engine(url, connect_args={'protocol': 'https'})
results = conn.execute(query, tuple(missing)).fetchall()

for fsa, geojson in results:
geojson = json.loads(geojson)
out[fsa] = geojson
if cache and len(results) < 10000: # avoid storing too much
cache_key = 'fsa_geojson_{}'.format(fsa)
try:
cache.set(cache_key, geojson, timeout=86400)
except Exception:
pass

return out


class DeckPathViz(BaseDeckGLViz):

"""deck.gl's PathLayer"""
Expand All @@ -2433,6 +2489,7 @@ class DeckPathViz(BaseDeckGLViz):
'polyline': polyline.decode,
'geohash': geohash_to_json,
'zipcode': None, # per request
'fsa': None, # per request
}

def query_obj(self):
Expand All @@ -2458,7 +2515,7 @@ def get_properties(self, d):
if fd.get('reverse_long_lat'):
path = [(o[1], o[0]) for o in path]
d[self.deck_viz_key] = path
if line_type not in ['geohash', 'zipcode']:
if line_type not in ['geohash', 'zipcode', 'fsa']:
del d[line_column]
d['__timestamp'] = d.get(DTTM_ALIAS) or d.get('__time')
return d
Expand All @@ -2470,6 +2527,9 @@ def get_data(self, df):
if line_type == 'zipcode':
zipcodes = df[fd['line_column']].unique()
self.deser_map['zipcode'] = zipcode_deser(zipcodes)
elif line_type == 'fsa':
fsas = df[fd['line_column']].unique()
self.deser_map['fsa'] = fsa_deser(fsas)

return super(DeckPathViz, self).get_data(df)

Expand Down

0 comments on commit 896e1cf

Please sign in to comment.