Clarified relationship between metadata and _facet= facets, updated docs - refs @255

This commit is contained in:
Simon Willison 2018-05-16 08:15:23 -07:00 committed by Simon Willison
commit 566f2d31d6
3 changed files with 91 additions and 40 deletions

View file

@ -104,7 +104,12 @@
<div class="facet-results"> <div class="facet-results">
{% for facet_info in sorted_facet_results %} {% for facet_info in sorted_facet_results %}
<div class="facet-info facet-{{ database|to_css_class }}-{{ table|to_css_class }}-{{ facet_info.name|to_css_class }}"> <div class="facet-info facet-{{ database|to_css_class }}-{{ table|to_css_class }}-{{ facet_info.name|to_css_class }}">
<p class="facet-info-name"><strong>{{ facet_info.name }}</strong> <a href="{{ path_with_removed_args(request, {'_facet': facet_info['name']}) }}">&#x2716;</a></p> <p class="facet-info-name">
<strong>{{ facet_info.name }}</strong>
{% if facet_hideable(facet_info.name) %}
<a href="{{ path_with_removed_args(request, {'_facet': facet_info['name']}) }}">&#x2716;</a>
{% endif %}
</p>
<ul> <ul>
{% for facet_value in facet_info.results %} {% for facet_value in facet_info.results %}
<li><a href="{{ facet_value.toggle_url }}">{{ facet_value.label }}</a> {{ "{:,}".format(facet_value.count) }}</li> <li><a href="{{ facet_value.toggle_url }}">{{ facet_value.label }}</a> {{ "{:,}".format(facet_value.count) }}</li>

View file

@ -537,10 +537,12 @@ class TableView(RowTableShared):
# facets support # facets support
FACET_SIZE = 20 FACET_SIZE = 20
metadata_facets = table_metadata.get("facets", [])
facets = metadata_facets[:]
try: try:
facets = request.args["_facet"] facets.extend(request.args["_facet"])
except KeyError: except KeyError:
facets = table_metadata.get("facets", []) pass
facet_results = {} facet_results = {}
for column in facets: for column in facets:
facet_sql = """ facet_sql = """
@ -719,6 +721,7 @@ class TableView(RowTableShared):
key=lambda f: (len(f["results"]), f["name"]), key=lambda f: (len(f["results"]), f["name"]),
reverse=True reverse=True
), ),
"facet_hideable": lambda facet: facet not in metadata_facets,
"is_sortable": any(c["sortable"] for c in display_columns), "is_sortable": any(c["sortable"] for c in display_columns),
"path_with_replaced_args": path_with_replaced_args, "path_with_replaced_args": path_with_replaced_args,
"path_with_removed_args": path_with_removed_args, "path_with_removed_args": path_with_removed_args,

View file

@ -3,8 +3,6 @@
Facets Facets
====== ======
This feature is currently under development, see `#255 <https://github.com/simonw/datasette/issues/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. 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. 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:: 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": [ "state": {
{ "name": "state",
"value": "CA", "results": [
"count": 10, {
"selected": false, "value": "CA",
"toggle_url": "http://...&state=CA" "label": "CA",
}, "count": 10,
{ "toggle_url": "http://...?_facet=city_id&_facet=state&state=CA",
"value": "MI", "selected": false
"count": 4, },
"selected": false, {
"toggle_url": "http://...&state=MI" "value": "MI",
} "label": "MI",
], "count": 4,
"city": [ "toggle_url": "http://...?_facet=city_id&_facet=state&state=MI",
{ "selected": false
"value": "San Francisco", },
"count": 6, {
"selected": false, "value": "MC",
"toggle_url": "http://...=San+Francisco" "label": "MC",
}, "count": 1,
{ "toggle_url": "http://...?_facet=city_id&_facet=state&state=MC",
"value": "Detroit", "selected": false
"count": 4, }
"selected": false, ],
"toggle_url": "http://...&city=Detroit" "truncated": false
}, }
{ "city_id": {
"value": "Los Angeles", "name": "city_id",
"count": 4, "results": [
"selected": false, {
"toggle_url": "http://...=Los+Angeles" "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 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.