From fe15032462d740131e6d8e945fb2164592f0175e Mon Sep 17 00:00:00 2001 From: Simon Willison Date: Wed, 16 May 2018 08:15:23 -0700 Subject: [PATCH] Clarified relationship between metadata and _facet= facets, updated docs - refs @255 --- datasette/templates/table.html | 7 +- datasette/views/table.py | 7 +- docs/facets.rst | 117 ++++++++++++++++++++++----------- 3 files changed, 91 insertions(+), 40 deletions(-) diff --git a/datasette/templates/table.html b/datasette/templates/table.html index 65b336b6..1ba61f87 100644 --- a/datasette/templates/table.html +++ b/datasette/templates/table.html @@ -104,7 +104,12 @@
{% for facet_info in sorted_facet_results %}
-

{{ facet_info.name }}

+

+ {{ facet_info.name }} + {% if facet_hideable(facet_info.name) %} + + {% endif %} +

    {% for facet_value in facet_info.results %}
  • {{ facet_value.label }} {{ "{:,}".format(facet_value.count) }}
  • diff --git a/datasette/views/table.py b/datasette/views/table.py index cb5a44f7..ab66b880 100644 --- a/datasette/views/table.py +++ b/datasette/views/table.py @@ -537,10 +537,12 @@ class TableView(RowTableShared): # facets support FACET_SIZE = 20 + metadata_facets = table_metadata.get("facets", []) + facets = metadata_facets[:] try: - facets = request.args["_facet"] + facets.extend(request.args["_facet"]) except KeyError: - facets = table_metadata.get("facets", []) + pass facet_results = {} for column in facets: facet_sql = """ @@ -719,6 +721,7 @@ class TableView(RowTableShared): key=lambda f: (len(f["results"]), f["name"]), reverse=True ), + "facet_hideable": lambda facet: facet not in metadata_facets, "is_sortable": any(c["sortable"] for c in display_columns), "path_with_replaced_args": path_with_replaced_args, "path_with_removed_args": path_with_removed_args, diff --git a/docs/facets.rst b/docs/facets.rst index 02ac8d55..51bfc0f5 100644 --- a/docs/facets.rst +++ b/docs/facets.rst @@ -3,8 +3,6 @@ Facets ====== -This feature is currently under development, see `#255 `_ - Datasette facets can be used to add a faceted browse interface to any Datasette table. With facets, tables are displayed along with a summary showing the most common values in specified columns. These values can be selected to further filter the table. Facets can be specified in two ways: using queryset parameters, or in ``metadata.json`` configuration for the table. @@ -18,43 +16,72 @@ To turn on faceting for specific columns on a Datasette table view, add one or m This works for both the HTML interface and the ``.json`` view. When enabled, facets will cause a ``facet_results`` block to be added to the JSON output, looking something like this:: - "facet_results": { - "state": [ - { - "value": "CA", - "count": 10, - "selected": false, - "toggle_url": "http://...&state=CA" - }, - { - "value": "MI", - "count": 4, - "selected": false, - "toggle_url": "http://...&state=MI" - } - ], - "city": [ - { - "value": "San Francisco", - "count": 6, - "selected": false, - "toggle_url": "http://...=San+Francisco" - }, - { - "value": "Detroit", - "count": 4, - "selected": false, - "toggle_url": "http://...&city=Detroit" - }, - { - "value": "Los Angeles", - "count": 4, - "selected": false, - "toggle_url": "http://...=Los+Angeles" - } - ] + { + "state": { + "name": "state", + "results": [ + { + "value": "CA", + "label": "CA", + "count": 10, + "toggle_url": "http://...?_facet=city_id&_facet=state&state=CA", + "selected": false + }, + { + "value": "MI", + "label": "MI", + "count": 4, + "toggle_url": "http://...?_facet=city_id&_facet=state&state=MI", + "selected": false + }, + { + "value": "MC", + "label": "MC", + "count": 1, + "toggle_url": "http://...?_facet=city_id&_facet=state&state=MC", + "selected": false + } + ], + "truncated": false + } + "city_id": { + "name": "city_id", + "results": [ + { + "value": 1, + "label": "San Francisco", + "count": 6, + "toggle_url": "http://...?_facet=city_id&_facet=state&city_id=1", + "selected": false + }, + { + "value": 2, + "label": "Los Angeles", + "count": 4, + "toggle_url": "http://...?_facet=city_id&_facet=state&city_id=2", + "selected": false + }, + { + "value": 3, + "label": "Detroit", + "count": 4, + "toggle_url": "http://...?_facet=city_id&_facet=state&city_id=3", + "selected": false + }, + { + "value": 4, + "label": "Memnonia", + "count": 1, + "toggle_url": "http://...?_facet=city_id&_facet=state&city_id=4", + "selected": false + } + ], + "truncated": false + } } +If Datasette detects that a column is a foreign key, the ``"label"`` proper will be automatically derived from the detected label column on the referenced table. + Facets in metadata.json ----------------------- @@ -73,3 +100,19 @@ Here's an example that turns on faceting by default for the ``qLegalStatus`` col } } } + +Facets defined in this way will always be shown in the interface and returned in the API, regardless of the ``_facet`` arguments passed to the view. + +Suggested facets +---------------- + +Datasette's table UI will suggest facets for the user to apply, based on the following criteria: + +For the currently filtered data are there any columns which, if applied as a facet... + +* Will return 20 or less unique options +* Will return more than one unique option +* Will return less unique options than the total number of filtered rows +* And the query used to evaluate this criteria can be completed in under 20ms + +That last point is particularly important: Datasette runs a query for every column that is displayed on a page, which could get expensive - so to avoid slow load times it sets a time limit of just 20ms for each of those queries. This means suggested facets are unlikely to appear for tables with millions of records in them.