Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drilldown support #5884

Open
jbednar opened this issue Sep 12, 2023 · 9 comments
Open

Drilldown support #5884

jbednar opened this issue Sep 12, 2023 · 9 comments
Labels
TRIAGE Needs triaging

Comments

@jbednar
Copy link
Member

jbednar commented Sep 12, 2023

(I could have sworn we had a several-year-old issue about this, but if so I can't find it!)

From my observations, many of what people consider "custom" dashboards are really just trying to show how multiple dimensions of data relate to each other, given the limitations of a 2D computer screen. Linked selections addresses some of the issues, letting you put up various plots of q vs t, h vs g, g vs w, and relate any given data points to the ones shown in other plots, so that you can see how the various quantities that can be measured correlate or distinguish different samples. Many applications of linked selections would have previously had to be complex logic implemented just for that dashboard, and instead the existing linked selections support can simply implement the general notion of linking related data across separate plots once and for all.

The concept of "drilldown" covers another huge swath of "custom" functionality, and I think that if we can provide general drilldown support in HoloViews, we can vastly reduce the complexity of most of the more-ambitious dashboards that people try to build in Panel. With drilldown, usually a given plot shows some aggregated quantity or some subset of dimensions, and the user selects a particular point, manifold (e.g. a line on an image plot), or selection, and a separate plot is then brought up or updated to show unaggregated data or data from different dimensions. E.g. clicking on a location in a map plot could show a curve of some variable at that location over time, or (as in our LANDSAT example) clicking on an RGB pixel can show the full hyperspectral spectrum of the measurements at that pixel across many different frequency bands.

HoloViz developers have discussed drilldown in the context of many different projects over the years, but we have never properly addressed the topic. Sure, Streams make it relatively easy to set up interactive behavior that connects different plots, but Streams are at a much lower level than I am envisioning, because they require some fairly specific plumbing to connect multiple plots. Maybe Streams are as good as it gets, and if so then we need some detailed examples showing how to solve various drilldown situations. But I think we can do much better than that, with generic support for drilldown where we define one of a few supported types of selection, define what the target is (hovering plot, popup plot, plot updated adjacent to the main one, etc.), and connect everything up in a straightforward way.

E.g. given a plot X and a plot Y, I want something that lets me define some selection on X, map something about that selection to Y, and then either display Y or update it if it is already displayed.

Bokeh's hover support is a good initial target: bokeh/bokeh#13375
image

Can we make it almost as easy to specify such a hovering plot as it is to lay two Elements or Overlays out, side by side? How can we define the connection between those two plots in a general way?

That one goes by points, but by lines is also really useful, providing a cross section on the right sampled across an additional depth dimension for the two lines drawn on the left:
https://earthsim.holoviz.org/user_guide/Analyzing_Meshes.html

image

There are many, many more examples that can be added here, and I think supporting easy drill down will provide power to ordinary people that really exploits and demonstrates the value of the HoloViews approach.

@jbednar jbednar added the TRIAGE Needs triaging label Sep 12, 2023
@ahuang11
Copy link
Collaborator

ahuang11 commented Sep 12, 2023

Here's an example using hvplot / holoviews. I had to make some internal changes here https://github.com/holoviz/holoviews/pull/5885/files

And I was able to create an example:

import holoviews as hv

from bokeh.plotting import figure
from bokeh.models.tools import HoverTool
from bokeh.models import RendererGroup
from bokeh.models.dom import (
    Div,
    Index,
    Span,
    Styles,
    Template,
    ValueRef,
    ToggleGroup,
)

hv.extension("bokeh")


def timeseries():
    plot = figure(
        width=150,
        height=75,
        toolbar_location=None,
        x_axis_label="Hours Ago",
        y_axis_label="Temperature (F)",
    )
    groups = []
    for station, station_df in df.groupby("station"):
        hours = (station_df["valid"].iloc[0] - station_df["valid"]).dt.total_seconds() / 3600
        tmpf = station_df["tmpf"]
        group = RendererGroup(visible=False)
        groups.append(group)
        glyph = plot.line(x=hours, y=tmpf, line_width=2, line_color="black")
        glyph.group = group
    return plot, groups


def tooltips():
    plot, groups = timeseries()

    style = Styles(
        display="grid",
        grid_template_columns="auto auto",
        column_gap="10px",
    )
    grid = Div(style=style)
    grid.children = [
        Span(),
        Span(children=["#", Index()]),
        "Station",
        Span(style=dict(font_weight="bold"), children=[ValueRef(field="station")]),
        "Longitude", ValueRef(field="lon"),
        "Latitude", ValueRef(field="lat"),
    ]
    return Template(children=[grid, plot], actions=[ToggleGroup(groups=groups)])


import hvplot.pandas
import pandas as pd


df = pd.read_csv(
    "https://mesonet.agron.iastate.edu/cgi-bin/request/asos.py?station=SEA&station=BFI&data=tmpf&year1=2023&month1=9&day1=11&year2=2023&month2=9&day2=12&tz=Etc%2FUTC&format=onlycomma&latlon=yes&elev=no&missing=empty&trace=0.0001&direct=no&report_type=3&report_type=4",
    index_col="valid",
    parse_dates=True,
).reset_index()
df.head()

hover = HoverTool(tooltips=tooltips())
df.hvplot.points(
    "lon", "lat", width=500, height=400, tools=[hover], hover_cols=["station"], tiles=True, geo=True
)

Which outputs:
image

However, a few unresolved issues:

  1. Projecting this onto a map causes the lat/lon to also be in Mercator.
  2. I couldn't get an hvplot version working in timeseries(), even with hv.render(), because I think it requires a single bokeh plot figure.

This works for hovering only one point, but upon hovering on a second point, it displays an empty plot.

import holoviews as hv

from bokeh.plotting import figure
from bokeh.models.tools import HoverTool
from bokeh.models import RendererGroup
from bokeh.models.dom import (
    Div,
    Index,
    Span,
    Styles,
    Template,
    ValueRef,
    ToggleGroup,
)

hv.extension("bokeh")


def timeseries():
    plot = figure(
        width=150,
        height=75,
        toolbar_location=None,
        x_axis_label="Hours Ago",
        y_axis_label="Temperature (F)",
    )
    groups = []
    for station, station_df in df.groupby("station"):
        station_df["hours_ago"] = (station_df["valid"].iloc[0] - station_df["valid"]).dt.total_seconds() / 3600
        group = RendererGroup(visible=False)
        groups.append(group)
        glyph = hv.render(station_df.hvplot(x="hours_ago", y="tmpf", visible=False)).renderers[0]
        plot.renderers.append(glyph)
        glyph.group = group
    return plot, groups


def tooltips():
    plot, groups = timeseries()

    style = Styles(
        display="grid",
        grid_template_columns="auto auto",
        column_gap="10px",
    )
    grid = Div(style=style)
    grid.children = [
        Span(),
        Span(children=["#", Index()]),
        "Station",
        Span(style=dict(font_weight="bold"), children=[ValueRef(field="station")]),
        "Longitude", ValueRef(field="lon"),
        "Latitude", ValueRef(field="lat"),
    ]
    return Template(children=[grid, plot], actions=[ToggleGroup(groups=groups)])


import hvplot.pandas
import pandas as pd


df = pd.read_csv(
    "https://mesonet.agron.iastate.edu/cgi-bin/request/asos.py?station=SEA&station=BFI&data=tmpf&year1=2023&month1=9&day1=11&year2=2023&month2=9&day2=12&tz=Etc%2FUTC&format=onlycomma&latlon=yes&elev=no&missing=empty&trace=0.0001&direct=no&report_type=3&report_type=4",
    index_col="valid",
    parse_dates=True,
).reset_index()
df.head()

hover = HoverTool(tooltips=tooltips())
df.hvplot.points(
    "lon", "lat", width=500, height=400, tools=[hover], hover_cols=["station"], tiles=True, geo=True
)

@maximlt
Copy link
Member

maximlt commented Sep 13, 2023

Thanks for opening this issue @jbednar, that was on my TODO list for a while but never got to it.

The ability for Bokeh to embed a real plot in a tooltip is interesting. The only problem I see starting with that is that I don't imagine you'd embed yet another plot in the tooltip plot (if that's even possible), while if we are to generalize drilldown I guess we don't want to be limited to drilling down to 1 level but to as many levels as required.

@ahuang11
Copy link
Collaborator

ahuang11 commented Sep 13, 2023

The only problem I see starting with that is that I don't imagine you'd embed yet another plot in the tooltip plot (if that's even possible),

For now, I think it'd still be immensely useful if there's a convenient/easy way to add plots to the tooltip, but I agree that drilling down would be also very good; I imagine that would take a lot more work though.

@jbednar
Copy link
Member Author

jbednar commented Sep 13, 2023

Thanks for opening this issue @jbednar, that was on my TODO list for a while but never got to it.

That's funny! At the same time I filed this issue, it reminded me that I needed to chase you about filing whatever issue we had discussed you filing a few weeks ago, so I wrote that down too. I guess "drilldown" was that issue, so I can cross off the chasing task! :-) If you have any notes from our discussion of it at that time, please add them here.

The ability for Bokeh to embed a real plot in a tooltip is interesting. The only problem I see starting with that is that I don't imagine you'd embed yet another plot in the tooltip plot (if that's even possible), while if we are to generalize drilldown I guess we don't want to be limited to drilling down to 1 level but to as many levels as required.

Interesting idea; basically like a browser tab: Click on one point in a plot to bring up a drilldown plot, then click on a point in that plot to drill down further, and so on. Could be implemented and might be useful, but I'm not asking for that! I imagine people would quickly lose track of what they are doing if we keep spawning popups like that. Instead, I was expecting multiple-level drilldown to work more left to right in a layout, not using hover but instead controlling a plot on the right, then clicking on that plot would control a plot to the right of that or below it, etc. That's what I more often see, anyway; hover is for a streamlined simpler case.

@maximlt
Copy link
Member

maximlt commented Sep 14, 2023

Interesting idea; basically like a browser tab: Click on one point in a plot to bring up a drilldown plot, then click on a point in that plot to drill down further, and so on. Could be implemented and might be useful, but I'm not asking for that! I imagine people would quickly lose track of what they are doing if we keep spawning popups like that. Instead, I was expecting multiple-level drilldown to work more left to right in a layout, not using hover but instead controlling a plot on the right, then clicking on that plot would control a plot to the right of that or below it, etc. That's what I more often see, anyway; hover is for a streamlined simpler case.

Oh I didn't mean that we should implement multiple-level drill-down with popups. Instead I tried to say that starting with the plot embedded in a tooltip approach may not be the right one to design the drill-down API as it's hard to see how more than 1 level can be of any use.

I also expect multiple-level drilldown to work more in a layout, and hopefully more in a Panel layout than in the less flexible HoloViews layout.

That's funny! At the same time I filed this issue, it reminded me that I needed to chase you about filing whatever issue we had discussed you filing a few weeks ago, so I wrote that down too. I guess "drilldown" was that issue, so I can cross off the chasing task! :-) If you have any notes from our discussion of it at that time, please add them here.

In that discussion you shared with me a report that linked to PRs that implemented linked selections in HoloVIews. The description was stating "allow creating new plots based on a selection" and you were wondering whether that was made possible in #4547. Maybe @philippjfr knows better? :)

Simpler Drill-Down Dashboard Options
PRs: HoloViews #4362, #4364, #4437, #4481, #4547

Added support for creating new plots determined by selections on existing plots. This support was built on the "link_selections" command added to HoloViews previously, generalizing it significantly so that it can support not just linking subselections between simultaneously visible plots, but to allow creating new plots based on a selection. Lasso support was also added to allow arbitrary-shaped selection of subsets of datasets.

You also shared some notes taken from a discussion with you and Philipp I believe, from some years ago.

Philipp & Jim update
Focus on the ability to link/drill down to useful data.
Idea: Any view in Panel (particularly plots) should be able to expose to other views in well-defined ways. Ability to reference in Lumen.
Example: Holoviews plot and want the current selection to flow to another data source
Can publish that info.
2 ways to use:
More general, “drill-down” You make a selection and want to drill down. Example: build a dashboard where you have ship tracks and you can select a specific ship and track. You have a separate table ship ID, take filter, filter one of the data sources, and feed into a merge with another data source. Merge that with my table of ship information. What you come up with for that ship, you have the other info: name, origin, picture of the ship, etc. Full flexibility of simple selections, but can also allow it to point to other information about that subject.

And you stated the following goal:

My goal would be to get to the point where we can specify drilldown in Lumen, i.e., that we've captured it at a high enough level that it makes sense to specify that a particular plot in a Lumen dashboard is a drilldown expansion from some selection in another plot. Is that enough for you to synthesize the above info into an issue about drilldown, or do you need me to do that?

@jbednar
Copy link
Member Author

jbednar commented Sep 18, 2023

Oh I didn't mean that we should implement multiple-level drill-down with popups. Instead I tried to say that starting with the plot embedded in a tooltip approach may not be the right one to design the drill-down API as it's hard to see how more than 1 level can be of any use.

Right; I think we are in agreement about that. But your dismissal of multi-level popups made me at least consider that possibility, which I had not previously. :-)

Ok, thanks for keeping those notes; I had now indeed lost track of all that! Sounds like it captures what we've been thinking about.

@jbednar
Copy link
Member Author

jbednar commented Sep 20, 2023

Another relevant drilldown example we have already (examples.holoviz.org/landsat):
image

@jbednar
Copy link
Member Author

jbednar commented Sep 20, 2023

@ahuang11
Copy link
Collaborator

ahuang11 commented Oct 27, 2023

Just wanted to share this additional resource here (using CustomJSHover to access Python dict values)
https://discourse.holoviz.org/t/applying-a-function-to-a-hover-tool-tooltip-value/6271/8?u=ahuang11

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
TRIAGE Needs triaging
Projects
None yet
Development

No branches or pull requests

3 participants