From 6d3f6c77163ae7c23f840296432725c3ec989ed2 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Wed, 1 Mar 2017 18:09:41 +0100 Subject: [PATCH] add a geojson export of visualization data (fixes #15180) --- bijoe/engine.py | 13 +++++++++++++ bijoe/schemas.py | 2 ++ bijoe/settings.py | 1 + bijoe/visualization/forms.py | 3 ++- bijoe/visualization/urls.py | 1 + bijoe/visualization/views.py | 30 ++++++++++++++++++++++++++++++ setup.py | 2 +- 7 files changed, 50 insertions(+), 2 deletions(-) diff --git a/bijoe/engine.py b/bijoe/engine.py index f52c55e..be8645d 100644 --- a/bijoe/engine.py +++ b/bijoe/engine.py @@ -27,6 +27,19 @@ psycopg2.extensions.register_type(psycopg2.extensions.UNICODE) psycopg2.extensions.register_type(psycopg2.extensions.UNICODEARRAY) +def cast_point(value, cur): + if value is None: + return None + return schemas.Point._make(map(float, value[1:-1].split(','))) + + +POINT = psycopg2.extensions.new_type((600,), "POINT", cast_point) +psycopg2.extensions.register_type(POINT) + +POINT_ARRAY = psycopg2.extensions.new_array_type((1017,), "POINT[]", POINT) +psycopg2.extensions.register_type(POINT_ARRAY) + + def to_tuple(cur, values): return cur.mogrify(', '.join(['%s'] * len(values)), values) diff --git a/bijoe/schemas.py b/bijoe/schemas.py index 5486bf7..8bb5bc0 100644 --- a/bijoe/schemas.py +++ b/bijoe/schemas.py @@ -22,6 +22,7 @@ import collections from .relative_time import RelativeDate +Point = collections.namedtuple('Point', ['x', 'y']) TYPE_MAP = { 'duration': datetime.timedelta, @@ -29,6 +30,7 @@ TYPE_MAP = { 'integer': int, 'decimal': decimal.Decimal, 'percent': float, + 'point': Point, } diff --git a/bijoe/settings.py b/bijoe/settings.py index 60cd2eb..2425780 100644 --- a/bijoe/settings.py +++ b/bijoe/settings.py @@ -57,6 +57,7 @@ INSTALLED_APPS = ( 'xstatic.pkg.chartnew_js', 'django_select2', 'gadjo', + 'rest_framework', 'bijoe', 'bijoe.visualization', ) diff --git a/bijoe/visualization/forms.py b/bijoe/visualization/forms.py index d4e6ff1..dd420cb 100644 --- a/bijoe/visualization/forms.py +++ b/bijoe/visualization/forms.py @@ -192,7 +192,8 @@ class CubeForm(forms.Form): required=False) # measures - choices = [(measure.name, measure.label) for measure in cube.measures] + choices = [(measure.name, measure.label) + for measure in cube.measures if measure.type != 'point'] self.base_fields['measure'] = forms.ChoiceField( label=_('Measure'), choices=choices) diff --git a/bijoe/visualization/urls.py b/bijoe/visualization/urls.py index 4215ce5..4b2fcdd 100644 --- a/bijoe/visualization/urls.py +++ b/bijoe/visualization/urls.py @@ -31,6 +31,7 @@ urlpatterns = patterns( url(r'warehouse/(?P[^/]*)/(?P[^/]*)/save/$', views.create_visualization, name='create-visualization'), url(r'(?P\d+)/$', views.visualization, name='visualization'), + url(r'(?P\d+)/geojson/$', views.visualization_geojson, name='visualization-geojson'), url(r'(?P\d+)/iframe/$', views.visualization_iframe, name='visualization-iframe'), url(r'(?P\d+)/rename/$', views.rename_visualization, name='rename-visualization'), url(r'(?P\d+)/delete/$', views.visualization, name='delete-visualization'), diff --git a/bijoe/visualization/views.py b/bijoe/visualization/views.py index 294be84..7b53c4c 100644 --- a/bijoe/visualization/views.py +++ b/bijoe/visualization/views.py @@ -27,6 +27,9 @@ from django.http import HttpResponse, Http404 from django.core.exceptions import PermissionDenied from django.views.decorators.clickjacking import xframe_options_exempt +from rest_framework import generics +from rest_framework.response import Response + from ..utils import get_warehouses from ..engine import Engine from . import models, forms, signature @@ -230,6 +233,32 @@ class VisualizationsJSONView(MultipleObjectMixin, View): class CubeIframeView(CubeView): template_name = 'bijoe/cube_raw.html' + +class VisualizationGeoJSONView(generics.GenericAPIView): + permission_classes = () + queryset = models.Visualization.objects.all() + + def get(self, request, pk, format=None): + instance = self.get_object() + visualization = Visualization.from_json(instance.parameters, request=request) + visualization.measure = visualization.cube.measures['geolocation'] + drilldown = visualization.drilldown + geojson = [] + for row in visualization.data(): + properties = {} + for dim in row[:len(drilldown)]: + properties[dim['label']] = dim['value'] + geojson.append({ + 'type': 'Feature', + 'geometry': { + 'type': 'Multipoint', + 'coordinates': row[len(drilldown)]['value'] or [], + }, + 'properties': properties, + }) + return Response(geojson) + + warehouse = WarehouseView.as_view() cube = CubeView.as_view() cube_iframe = xframe_options_exempt(CubeIframeView.as_view()) @@ -240,6 +269,7 @@ delete_visualization = DeleteVisualizationView.as_view() rename_visualization = RenameVisualization.as_view() visualization = VisualizationView.as_view() visualization_iframe = xframe_options_exempt(VisualizationIframeView.as_view()) +visualization_geojson = VisualizationGeoJSONView.as_view() cube_iframe.mellon_no_passive = True visualization_iframe.mellon_no_passive = True diff --git a/setup.py b/setup.py index 4e955ae..83ee63b 100644 --- a/setup.py +++ b/setup.py @@ -94,7 +94,7 @@ setup(name="bijoe", include_package_data=True, install_requires=['requests', 'django', 'psycopg2', 'isodate', 'Django-Select2<5', 'XStatic-ChartNew.js', 'gadjo', 'django-jsonfield<1.0.0', - 'python-dateutil'], + 'python-dateutil', 'djangorestframework<3.4'], scripts=['bijoe-ctl'], cmdclass={ 'sdist': eo_sdist, -- 2.1.4