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

Provide support for multiple outputs #119

Merged
merged 26 commits into from
Sep 3, 2019
Merged

Provide support for multiple outputs #119

merged 26 commits into from
Sep 3, 2019

Conversation

rpkyle
Copy link
Contributor

@rpkyle rpkyle commented Aug 23, 2019

This PR provides support for multiple outputs, as originally described in plotly/dash#436. Several changes are proposed:

  • a createCallbackId function is introduced to simplify generating output IDs for either single outputs (container.style) or multiple outputs (..text-box.children...container.style..)
  • an insertIntoCallbackMap function is also introduced to add additional callback handlers into the map
  • callback handlers may now return values which are targeted at multiple callbacks, and these targets are inferred solely from the sequence of the output declaration (i.e. no names are required for the return object elements)
  • partial updates are properly supported
  • modifications to CircleCI test config to install the correct package versions for a given plotly/dashR version, and to avoid repeatedly launching R for package installs

The following checks are now performed within Dash for R:

  • validateOutput now checks the ID formatting for single and multiple outputs
  • assert_valid_callbacks now checks for circular inputs and outputs for multiple outputs also
  • insertIntoCallbackMap checks for duplicated outputs across callbacks before allowing a new callback to be added to the callback map

An additional test is also proposed to ensure that multiple outputs are functioning properly, and that partial outputs are allowed.

Finally, the following checks are implemented as in Dash for Python:

  • Ensuring that no output is specified twice #f1f4724
  • Ensuring that no output is used in two overlapping multi-output sets (e.g. you cannot have ..o1.value...o2.value.. with ..o1.value...o3.value..) #508eeb1
  • Ensuring that both methods of supplying an output parameter are working (e.g. using output=list(id='graph', property='figure') or output=output(id='graph', property='figure')) #5521a93

Closes #114.

@rpkyle rpkyle self-assigned this Aug 23, 2019
@rpkyle
Copy link
Contributor Author

rpkyle commented Aug 23, 2019

A sample app is provided here:

library(dash)
library(dashHtmlComponents)
library(dashCoreComponents)
library(plotly)
library(dashTable)

sample_data <- list(
  series = list(
    data = list(
      list(title = 'Game of Thrones', 
           score = 9.5),
      list(title = 'Stranger Things', 
           score = 8.9),
      list(title = 'Vikings', 
           score = 8.6)
      ),
    style = list(
      backgroundColor = '#ff998a'
    )
  ),
  movies = list(
    data = list(
      list(title = 'Rambo', 
           score = 7.7),
      list(title = 'The Terminator', 
           score = 8.0),
      list(title = 'Alien', 
           score = 8.5)
      ),
    style = list(
      backgroundColor = '#fff289'
    )
  )
)

app <- Dash$new()       

app$layout(
  htmlDiv(list(
    htmlH1('Multi output example'),
    dccDropdown(id='data-dropdown',
                options = list(
                  list(label = 'Movies',
                       value = 'movies'),
                  list(label = 'Series',
                       value = 'series')
                ),
                value = 'movies'),
    htmlDiv(list(
      dccGraph(id = 'graph'),
      dashDataTable(id = 'data-table',
                    columns = list(
                      list(name = 'Title',
                           id = 'title'),
                      list(name = 'Score',
                           id = 'score')
                    )
      )
    )
    )
  ),
  id = 'container'
  )
)

app$callback(output=list(
  output(id='graph', property='figure'),
  output(id='data-table', property='data'),
  output(id='data-table', property='columns'),
  output(id='container', property='style')
  ),
  params=list(
    input(id='data-dropdown', property='value')
  ),
  function(value) {
    if (is.null(value)) {
      return(dashNoUpdate())
    }

    selected <- sample_data[[value]]
    
    subdata <- selected[['data']]

    columns <- list(
      list(
        name = 'Title',
        id = 'title'
      ),
      list(
        name = 'Score',
        id = 'score'
      )
    )
    
    figure <- plot_ly(
      x = vapply(subdata, function(x) x$score, numeric(1)),
      text = vapply(subdata, function(x) x$title, character(1)),
      name = vapply(subdata, function(x) x$title, character(1)),
      type = "bar"
    )
    
    browser()
    
    return(list(figure,
                subdata,
                columns,
                selected[['style']]))
})

app$run_server(debug=TRUE)

R/dash.R Outdated Show resolved Hide resolved
R/dash.R Outdated Show resolved Hide resolved
@rpkyle
Copy link
Contributor Author

rpkyle commented Aug 29, 2019

Finishing up tests for the second and third checked items above, but I believe the current version of this code satisfies all requirements noted here.

@rpkyle rpkyle added this to the Dash v1.3.0 milestone Aug 29, 2019
@rpkyle
Copy link
Contributor Author

rpkyle commented Aug 29, 2019

@byronz I made some minor changes to the CircleCI config in 30ba139:

  • R package dependencies are now installed on one line, so we don't repeatedly launch R to complete all package installs before the tests start
  • we install plotly/dashR instead of the core packages, since the latter approach causes us to grab versions that are not locked to the current Dash for R release

@rpkyle
Copy link
Contributor Author

rpkyle commented Aug 30, 2019

@alexcjohnson I've implemented the unit and integration tests for all features/scenarios requested, except for the most recent one you asked about, which I'll do today.

@rpkyle
Copy link
Contributor Author

rpkyle commented Sep 1, 2019

@alexcjohnson OK, test has been added with two DashNoUpdate() returns in the same callback.

@rpkyle rpkyle changed the base branch from master to dev September 1, 2019 18:36
Copy link
Collaborator

@alexcjohnson alexcjohnson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice! Just a small note about commenting the test, then we're ready to go! 💃

@rpkyle rpkyle merged commit d20daa8 into dev Sep 3, 2019
@rpkyle rpkyle deleted the 114-multiple-outputs branch September 3, 2019 13:29
@rpkyle rpkyle mentioned this pull request Jan 3, 2020
rpkyle added a commit that referenced this pull request Jan 4, 2020
* Provide support for no_update in Dash for R (#111)

* Use dev_tools_prune_errors instead of pruned_errors (#113)

* Better handling for user-defined error conditions in debug mode (#116)

* Provide support for multiple outputs (#119)

* Provide support for hot reloading in Dash for R (#127)

* Implement support for clientside callbacks in Dash for R (#130)

* Add line number context to stack traces when srcrefs are available (#133)

* Update dash-renderer to 1.2.2 and fix dev tools UI display of stack traces (#137)

* Support for meta tags in Dash for R (#142)

* Fixes for hot reloading interval handling and refreshing apps within viewer pane (#148)

* Support for asynchronous loading/compression in Dash for R (#157)

* Support returning asset URLs via public method within Dash class (#160)

* Minor fix for get_asset_url + docs, add url_base_pathname (#161)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants