This is an automated email from the ASF dual-hosted git repository.
maximebeauchemin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git
The following commit(s) were added to refs/heads/master by this push:
new f905726 [geo] Added DeckGL GeoJson layer (#4097)
f905726 is described below
commit f905726c24b1d1f65a55b38592cb51c0f45deb15
Author: Hugh A. Miles II <[email protected]>
AuthorDate: Fri Dec 22 17:40:08 2017 -0500
[geo] Added DeckGL GeoJson layer (#4097)
* added deckgl geojson layer
* linting
* fixed comments
* addressed comments
* added override with controls.color_picker > 0
* set var properly
* set colors if property doesnt exist at all
* refacator on property mapping
---
.../assets/images/viz_thumbnails/deck_geojson.png | Bin 0 -> 223242 bytes
.../assets/javascripts/explore/stores/controls.jsx | 37 +++++++++++-
.../assets/javascripts/explore/stores/visTypes.js | 27 +++++++++
superset/assets/visualizations/deckgl/geojson.jsx | 67 +++++++++++++++++++++
superset/assets/visualizations/main.js | 2 +
superset/cli.py | 3 +
superset/data/__init__.py | 30 +++++++++
superset/data/paris_iris.json.gz | Bin 0 -> 4427142 bytes
superset/viz.py | 27 +++++++++
9 files changed, 192 insertions(+), 1 deletion(-)
diff --git a/superset/assets/images/viz_thumbnails/deck_geojson.png
b/superset/assets/images/viz_thumbnails/deck_geojson.png
new file mode 100644
index 0000000..40d1b63
Binary files /dev/null and
b/superset/assets/images/viz_thumbnails/deck_geojson.png differ
diff --git a/superset/assets/javascripts/explore/stores/controls.jsx
b/superset/assets/javascripts/explore/stores/controls.jsx
index 95d4813..7aee160 100644
--- a/superset/assets/javascripts/explore/stores/controls.jsx
+++ b/superset/assets/javascripts/explore/stores/controls.jsx
@@ -36,7 +36,7 @@ const timeColumnOption = {
verbose_name: 'Time',
column_name: '__timestamp',
description: t(
- 'A reference to the [Time] configuration, taking granularity into ' +
+ 'A reference to the [Time] configuration, taking granularity into ' +
'account'),
};
const sortAxisChoices = [
@@ -152,6 +152,22 @@ export const controls = {
renderTrigger: true,
},
+ fill_color_picker: {
+ label: t('Fill Color'),
+ description: t(' Set the opacity to 0 if you do not want to override the
color specified in the GeoJSON'),
+ type: 'ColorPickerControl',
+ default: colorPrimary,
+ renderTrigger: true,
+ },
+
+ stroke_color_picker: {
+ label: t('Stroke Color'),
+ description: t(' Set the opacity to 0 if you do not want to override the
color specified in the GeoJSON'),
+ type: 'ColorPickerControl',
+ default: colorPrimary,
+ renderTrigger: true,
+ },
+
metric: {
type: 'SelectControl',
label: t('Metric'),
@@ -505,6 +521,25 @@ export const controls = {
}),
},
+ geojson: {
+ type: 'SelectControl',
+ label: t('GeoJson Column'),
+ validators: [v.nonEmpty],
+ description: t('Select the geojson column'),
+ mapStateToProps: state => ({
+ choices: (state.datasource) ? state.datasource.all_cols : [],
+ }),
+ },
+
+ point_radius_scale: {
+ type: 'SelectControl',
+ freeForm: true,
+ label: t('Point Radius Scale'),
+ validators: [v.integer],
+ default: null,
+ choices: formatSelectOptions([0, 100, 200, 300, 500]),
+ },
+
all_columns_x: {
type: 'SelectControl',
label: 'X',
diff --git a/superset/assets/javascripts/explore/stores/visTypes.js
b/superset/assets/javascripts/explore/stores/visTypes.js
index 88f6710..f4720f9 100644
--- a/superset/assets/javascripts/explore/stores/visTypes.js
+++ b/superset/assets/javascripts/explore/stores/visTypes.js
@@ -455,6 +455,33 @@ export const visTypes = {
},
},
+ deck_geojson: {
+ label: t('Deck.gl - geoJson'),
+ requiresTime: true,
+ controlPanelSections: [
+ {
+ label: t('Query'),
+ expanded: true,
+ controlSetRows: [
+ ['geojson', 'row_limit'],
+ ],
+ },
+ {
+ label: t('Map'),
+ controlSetRows: [
+ ['mapbox_style', 'viewport'],
+ ],
+ },
+ {
+ label: t('GeoJson Settings'),
+ controlSetRows: [
+ ['fill_color_picker', 'stroke_color_picker'],
+ ['point_radius_scale', null],
+ ],
+ },
+ ],
+ },
+
deck_scatter: {
label: t('Deck.gl - Scatter plot'),
requiresTime: true,
diff --git a/superset/assets/visualizations/deckgl/geojson.jsx
b/superset/assets/visualizations/deckgl/geojson.jsx
new file mode 100644
index 0000000..080d7ee
--- /dev/null
+++ b/superset/assets/visualizations/deckgl/geojson.jsx
@@ -0,0 +1,67 @@
+import React from 'react';
+import ReactDOM from 'react-dom';
+import { GeoJsonLayer } from 'deck.gl';
+import { hexToRGB } from '../../javascripts/modules/colors';
+
+import DeckGLContainer from './DeckGLContainer';
+
+const propertyMap = {
+ fillColor: 'fillColor',
+ color: 'fillColor',
+ fill: 'fillColor',
+ 'fill-color': 'fillColor',
+ strokeColor: 'strokeColor',
+ 'stroke-color': 'strokeColor',
+ 'stroke-width': 'strokeWidth',
+};
+
+const convertGeoJsonColorProps = (p, colors) => {
+ const obj = Object.assign(...Object.keys(p).map(k => ({
+ [(propertyMap[k]) ? propertyMap[k] : k]: p[k] })));
+
+ return {
+ ...obj,
+ fillColor: (colors.fillColor[3] !== 0) ? colors.fillColor :
hexToRGB(obj.fillColor),
+ strokeColor: (colors.strokeColor[3] !== 0) ? colors.strokeColor :
hexToRGB(obj.strokeColor),
+ };
+};
+
+function DeckGeoJsonLayer(slice, payload, setControlValue) {
+ const fd = slice.formData;
+ const fc = fd.fill_color_picker;
+ const sc = fd.stroke_color_picker;
+ const data = payload.data.geojson.features.map(d => ({
+ ...d,
+ properties: convertGeoJsonColorProps(
+ d.properties, {
+ fillColor: [fc.r, fc.g, fc.b, 255 * fc.a],
+ strokeColor: [sc.r, sc.g, sc.b, 255 * sc.a],
+ }),
+ }));
+
+ const layer = new GeoJsonLayer({
+ id: 'geojson-layer',
+ data,
+ filled: true,
+ stroked: false,
+ extruded: true,
+ pointRadiusScale: fd.point_radius_scale,
+ });
+
+ const viewport = {
+ ...fd.viewport,
+ width: slice.width(),
+ height: slice.height(),
+ };
+ ReactDOM.render(
+ <DeckGLContainer
+ mapboxApiAccessToken={payload.data.mapboxApiKey}
+ viewport={viewport}
+ layers={[layer]}
+ mapStyle={fd.mapbox_style}
+ setControlValue={setControlValue}
+ />,
+ document.getElementById(slice.containerId),
+ );
+}
+module.exports = DeckGeoJsonLayer;
diff --git a/superset/assets/visualizations/main.js
b/superset/assets/visualizations/main.js
index 06d30a1..e692c10 100644
--- a/superset/assets/visualizations/main.js
+++ b/superset/assets/visualizations/main.js
@@ -43,6 +43,7 @@ export const VIZ_TYPES = {
deck_grid: 'deck_grid',
deck_hex: 'deck_hex',
deck_path: 'deck_path',
+ deck_geojson: 'deck_geojson',
};
const vizMap = {
@@ -88,5 +89,6 @@ const vizMap = {
[VIZ_TYPES.deck_grid]: require('./deckgl/grid.jsx'),
[VIZ_TYPES.deck_hex]: require('./deckgl/hex.jsx'),
[VIZ_TYPES.deck_path]: require('./deckgl/path.jsx'),
+ [VIZ_TYPES.deck_geojson]: require('./deckgl/geojson.jsx'),
};
export default vizMap;
diff --git a/superset/cli.py b/superset/cli.py
index 56ead72..14a592b 100755
--- a/superset/cli.py
+++ b/superset/cli.py
@@ -139,6 +139,9 @@ def load_examples(load_test_data):
print('Loading DECK.gl demo')
data.load_deck_dash()
+ print('Loading Paris geojson data')
+ data.load_paris_iris_geojson()
+
if load_test_data:
print('Loading [Unicode test data]')
data.load_unicode_test_data()
diff --git a/superset/data/__init__.py b/superset/data/__init__.py
index b3cb4a8..bddc014 100644
--- a/superset/data/__init__.py
+++ b/superset/data/__init__.py
@@ -1522,6 +1522,36 @@ def load_flights():
obj.fetch_metadata()
+def load_paris_iris_geojson():
+ tbl_name = 'paris_iris_mapping'
+
+ with gzip.open(os.path.join(DATA_FOLDER, 'paris_iris.json.gz')) as f:
+ df = pd.read_json(f)
+ df['features'] = df.features.map(json.dumps)
+
+ df.to_sql(
+ tbl_name,
+ db.engine,
+ if_exists='replace',
+ chunksize=500,
+ dtype={
+ 'color': String(255),
+ 'name': String(255),
+ 'features': Text,
+ 'type': Text,
+ },
+ index=False)
+ print("Creating table {} reference".format(tbl_name))
+ tbl = db.session.query(TBL).filter_by(table_name=tbl_name).first()
+ if not tbl:
+ tbl = TBL(table_name=tbl_name)
+ tbl.description = "Map of Paris"
+ tbl.database = get_or_create_main_db()
+ db.session.merge(tbl)
+ db.session.commit()
+ tbl.fetch_metadata()
+
+
def load_bart_lines():
tbl_name = 'bart_lines'
with gzip.open(os.path.join(DATA_FOLDER, 'bart-lines.json.gz')) as f:
diff --git a/superset/data/paris_iris.json.gz b/superset/data/paris_iris.json.gz
new file mode 100644
index 0000000..4a964c9
Binary files /dev/null and b/superset/data/paris_iris.json.gz differ
diff --git a/superset/viz.py b/superset/viz.py
index 55f2603..2a6b494 100644
--- a/superset/viz.py
+++ b/superset/viz.py
@@ -1942,6 +1942,33 @@ class DeckHex(BaseDeckGLViz):
verbose_name = _('Deck.gl - 3D HEX')
+class DeckGeoJson(BaseDeckGLViz):
+
+ """deck.gl's GeoJSONLayer"""
+
+ viz_type = 'deck_geojson'
+ verbose_name = _('Deck.gl - GeoJSON')
+
+ def query_obj(self):
+ d = super(DeckGeoJson, self).query_obj()
+ d['columns'] = [self.form_data.get('geojson')]
+ d['metrics'] = []
+ d['groupby'] = []
+ return d
+
+ def get_data(self, df):
+ fd = self.form_data
+ geojson = {
+ 'type': 'FeatureCollection',
+ 'features': [json.loads(item) for item in df[fd.get('geojson')]],
+ }
+
+ return {
+ 'geojson': geojson,
+ 'mapboxApiKey': config.get('MAPBOX_API_KEY'),
+ }
+
+
class EventFlowViz(BaseViz):
"""A visualization to explore patterns in event sequences"""
--
To stop receiving notification emails like this one, please contact
['"[email protected]" <[email protected]>'].