Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
37 changes: 36 additions & 1 deletion superset/assets/javascripts/explore/stores/controls.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand Down Expand Up @@ -143,6 +143,22 @@ export const controls = {
renderTrigger: true,
},

fill_color_picker: {
label: t('Fill Color'),
description: t('Use to set fill color of geojson'),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • 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('Use to set stroke color of geojson'),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • 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'),
Expand Down Expand Up @@ -496,6 +512,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',
Expand Down
29 changes: 29 additions & 0 deletions superset/assets/javascripts/explore/stores/visTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,35 @@ export const visTypes = {
},
},

deck_geojson: {
label: t('Deck.gl - geoJson'),
requiresTime: true,
controlPanelSections: [
{
label: t('Query'),
expanded: true,
controlSetRows: [
['geojson'],

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: you can fit those 2 controls on the same row here

['row_limit'],
],
},
{
label: t('Map'),
controlSetRows: [
['mapbox_style', 'viewport'],
],
},
{
label: t('GeoJson Settings'),
controlSetRows: [
['fill_color_picker', null],

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fit 2 color pickers on one row

['stroke_color_picker', null],
['point_radius_scale', null],
],
},
],
},

deck_scatter: {
label: t('Deck.gl - Scatter plot'),
requiresTime: true,
Expand Down
45 changes: 45 additions & 0 deletions superset/assets/visualizations/deckgl/geojson.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { GeoJsonLayer } from 'deck.gl';

import DeckGLContainer from './DeckGLContainer';


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: {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this will fully override properties ind d which is not what we want. We should enforce the precedence rule here.

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;
2 changes: 2 additions & 0 deletions superset/assets/visualizations/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -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;
3 changes: 3 additions & 0 deletions superset/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
34 changes: 34 additions & 0 deletions superset/data/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1522,6 +1522,37 @@ 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)


Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one empty line is enough

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:
Expand Down Expand Up @@ -1550,3 +1581,6 @@ def load_bart_lines():
db.session.merge(tbl)
db.session.commit()
tbl.fetch_metadata()



Binary file added superset/data/paris_iris.json.gz
Binary file not shown.
27 changes: 27 additions & 0 deletions superset/viz.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"""
Expand Down