delta-rho / trelliscope

Detailed Visualization of Large Complex Data in R
Other
115 stars 34 forks source link

State handling feature #52

Closed hafen closed 10 years ago

hafen commented 10 years ago

This covers a few of the outstanding issues. The idea is to have an overall notion of state in Trelliscope displays. By state, we are talking about being able to specify how a display is being shown with respect to sorting, filtering, panel layout, panel labels, etc.

Places where we would like to specify the state include:

The approach I have been working on uses a URL hash to store the state as interactions occur. Any time a state variable is changed (sorting, etc.), the URL will update. Thus at any point in the viewing process, the URL can be copied and shared with others to preserve the state (not everything is preserved, such as the current page you are on and related displays).

State is specified from the R console by a named list. Consider this example:

library(trelliscope)
vdbConn(file.path(tempdir(), "testVDB"), name = "test", autoYes = TRUE)

set.seed(1234)
iris$alpha <- sample(letters[1:5], 150, replace =TRUE)

bySpeciesAlpha <- divide(iris, by = c("Species", "alpha"))

makeDisplay(bySpeciesAlpha,
   name = "testBySpeciesAlpha",
   panelFn = function(x)
      plot(x$Sepal.Length, x$Sepal.Width)
)

view("testBySpeciesAlpha", state = list(
   layout = list(nrow = 2, ncol = 2),
   sort = list(Species = "asc", alpha = "desc"),
   filter = list(
      alpha = list(select = c("a", "b", "c")),
      Species = list(regex = "a$"))
      labels = c("Species", "alpha")
))

Here, we add a new categorical variable to the iris data, split on both species and this new variable, and then create a dummy plot. Then, when we call view, we tell the viewer to launch with that display showing, reflecting the specified state. The panels will be laid out in 2 rows and 2 columns. Note that we can also specify arrange="row" (default) or arrange="col" in the layout. The panels will be sorted by Species ascending and alpha descending. The panels will be filtered on alpha so that panels only for the letters a-c are showing and filter on Species so that only species ending with the letter a are showing. For numeric variables, we can specify, for example with a variable called var, the following: filter = list(var = list(from = 0, to = 1)). Finally, we can specify labels by simply providing a character vector of cognostic variable names to display beneath each panel. By default, all splitting variables will be shown (if labels is not specified).

A function, validateState() should be available to ensure the state is specified correctly and optionally check if it matches variables for a given display (provided through the display name).

This display will launch and should have the following URL:

http://127.0.0.1:8100/#name=testBySpeciesAlpha&group=common&layout=nrow:2,ncol:2&sort=Species:asc,alpha:desc&filter=alpha:(select:a;b;c)&labels=Species,alpha

As you interact with the display, the URL should reflect what you have done, and if you paste this URL in a new window, the display should be shown in the state specified by the URL.

Another thing we would like to be able to do is make it easy to reference other displays through cognostics. For example, suppose that I also have a division of the iris data by species. For each display of species, I might want to have a link the use can click on that will open up our display by both species and alpha but only show the panels for the corresponding species. This should be done through a cognostics helper function, cogDisplayHref(). Here's an example:

bySpecies <- divide(iris, by = "Species")

makeDisplay(bySpecies,
   name = "testBySpecies",
   panelFn = function(x)
      plot(x$Sepal.Length, x$Sepal.Width),
   cogFn = function(x) {
      list(alphaLink = cogDisplayHref(
         desc = "species broken down by alpha",
         displayName = "testBySpeciesAlpha",
         displayGroup = "common",
         state = list(
            filter = list(Species = list(select = getSplitVar(x, "Species"))),
            layout = list(nrow = 1, ncol = 5)
         )
      ))
   }
)

view(name = "testBySpecies", state = list(labels = c("Species", "alphaLink"), layout = list(ncol = 3)))

Here, we create the display with a cognostic that builds a link to our previous display, but should filter on the species we would like to view them for. After calling the view statement, we should see the three panels with a link showing (since we specified it with labels =) that we can click on.

hafen commented 10 years ago

I've pushed a solution to this issue to hafen/trelliscope in the state_preserving branch. It needs lots of testing. But the examples above should work. If anyone wants to try it out, please do so and report back here if there are issues or other things I should consider.

devtools::install_github("hafen/trelliscope", ref = "state_preserving")
hafen commented 10 years ago

This is now in the master branch. Any bugs can be addressed by new issues.