Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
e5b0cfe
contribute test script
Aug 3, 2020
a242d49
remove version updating in DESCRIPTION
Aug 3, 2020
f1b81d6
fix EOL
rpkyle Aug 4, 2020
4d234cb
Merge pull request #222 from plotly/212-untangle-dashr-build
rpkyle Aug 4, 2020
4e4ccb1
Add support for user-defined server routes (#225)
rpkyle Aug 28, 2020
5bd1bbb
Provide support for script and stylesheet attributes (#226)
rpkyle Sep 4, 2020
3f862f9
Authenticate on pulls from Docker Hub (#231)
rpkyle Oct 6, 2020
3a3ee2f
Add support for callback graph improvements and timing (#224)
rpkyle Oct 9, 2020
766e3a8
Update CHANGELOG.md
rpkyle Oct 12, 2020
3b54773
189 - Add Pattern Matching Callbacks for Dash R (#228)
HammadTheOne Oct 21, 2020
03ed383
Fixing Null error with glue::glue interpolation (#233)
HammadTheOne Oct 21, 2020
5b31534
Update CHANGELOG.md
rpkyle Oct 26, 2020
2fdd157
Update dash-renderer to v1.8.2 (#234)
rpkyle Oct 26, 2020
bb9fc6a
bump package version to v0.8.0
Oct 26, 2020
314ced8
Update R/dash.R
rpkyle Oct 27, 2020
3f9f9f1
Update tests/testthat/test-wildcards.R
rpkyle Oct 27, 2020
e093463
Update DESCRIPTION
rpkyle Oct 27, 2020
6ee2702
Merge branch 'master' into dev
rpkyle Oct 27, 2020
b477fe0
add PMC example
Oct 27, 2020
6fffb44
update documentation
Oct 27, 2020
b4ca5f9
update CHANGELOG release date
Oct 27, 2020
24b491a
Merge branch 'dev' of github.com:plotly/dashR into dev
Oct 27, 2020
c120ab2
:hammer: PMC docs refactor
Oct 27, 2020
56d1dc0
Update tests/integration/callbacks/test_pattern_matching.py
rpkyle Oct 27, 2020
226f949
Update tests/integration/callbacks/test_pattern_matching.py
rpkyle Oct 27, 2020
fd5f3da
Update tests/integration/callbacks/test_pattern_matching.py
rpkyle Oct 28, 2020
c3a34b6
add import of glue
Oct 28, 2020
877f463
add glue to imports.R
Oct 28, 2020
b238a57
fix line length issue
Oct 28, 2020
ff858ac
Fix setCallbackContext for wildcard and ordinary inputs (#237)
HammadTheOne Oct 30, 2020
7a23405
Merge branch 'master' into dev
rpkyle Oct 31, 2020
aac1db5
bump dependency versions
Oct 31, 2020
b7b1cfa
update CHANGELOG
Oct 31, 2020
4326e08
update dash-renderer to v1.8.3
Oct 31, 2020
ed022c8
update CHANGELOG
Oct 31, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,6 +2,18 @@
All notable changes to `dash` will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).

## [0.9.0] - 2020-10-31

### Fixed
- Fixes a minor bug in `setCallbackContext` (described in [#236](https://github.com/plotly/dashR/issues/236)) which prevented pattern-matching callbacks from working properly if one or more `input` statements did not include a selector. [#237](https://github.com/plotly/dashR/pull/237)

### Changed

- Dash for R now depends on v1.1.1 of `dashHtmlComponents`
- Dash for R now depends on v1.13.0 of `dashCoreComponents`
- Dash for R now depends on v4.11.0 of `dashTable`
- `dash-renderer` version is now v1.8.3

## [0.8.0] - 2020-10-27
### Fixed
- Usage of `glue` has been corrected to address [#232](https://github.com/plotly/dashR/issues/232) via [#233](https://github.com/plotly/dashR/pull/233).
Expand Down
14 changes: 7 additions & 7 deletions DESCRIPTION
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
Package: dash
Title: An Interface to the Dash Ecosystem for Authoring Reactive Web Applications
Version: 0.8.0
Version: 0.9.0
Authors@R: c(person("Chris", "Parmer", role = c("aut"), email = "chris@plotly.com"), person("Ryan Patrick", "Kyle", role = c("aut", "cre"), comment = c(ORCID = "0000-0001-5829-9867"), email = "ryan@plotly.com"), person("Carson", "Sievert", role = c("aut"), comment = c(ORCID = "0000-0002-4958-2844")), person("Hammad", "Khan", role = c("aut"), comment = c(ORCID = "0000-0003-2479-9841"), email = "hammadkhan@plotly.com"), person(family = "Plotly Technologies", role = "cph"))
Description: A framework for building analytical web applications, Dash offers a pleasant and productive development experience. No JavaScript required.
Depends:
R (>= 3.0.2)
Imports:
dashHtmlComponents (== 1.0.3),
dashCoreComponents (== 1.10.2),
dashTable (== 4.9.0),
dashHtmlComponents (== 1.1.1),
dashCoreComponents (== 1.13.0),
dashTable (== 4.11.0),
R6,
fiery (> 1.0.0),
routr (> 0.2.0),
Expand All@@ -33,9 +33,9 @@ Collate:
'imports.R'
'print.R'
'internal.R'
Remotes: plotly/dash-html-components@e63acfa,
plotly/dash-core-components@0770afb,
plotly/dash-table@75ac3d9
Remotes: plotly/dash-html-components@7209e0a,
plotly/dash-core-components@91a424e,
plotly/dash-table@aa519b7
License: MIT + file LICENSE
Encoding: UTF-8
LazyData: true
Expand Down
24 changes: 12 additions & 12 deletions R/internal.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -36,9 +36,9 @@
all_files = FALSE),
class = "html_dependency"),
`dash-renderer-dev` = structure(list(name = "dash-renderer",
version = "1.8.2",
src = list(href = "https://unpkg.com/dash-renderer@1.8.2",
file = "lib/dash-renderer@1.8.2"),
version = "1.8.3",
src = list(href = "https://unpkg.com/dash-renderer@1.8.3",
file = "lib/dash-renderer@1.8.3"),
meta = NULL,
script = "dash-renderer/dash_renderer.dev.js",
stylesheet = NULL,
Expand All@@ -48,9 +48,9 @@
all_files = FALSE),
class = "html_dependency"),
`dash-renderer-map-dev` = structure(list(name = "dash-renderer",
version = "1.8.2",
src = list(href = "https://unpkg.com/dash-renderer@1.8.2",
file = "lib/dash-renderer@1.8.2"),
version = "1.8.3",
src = list(href = "https://unpkg.com/dash-renderer@1.8.3",
file = "lib/dash-renderer@1.8.3"),
meta = NULL,
script = "dash-renderer/dash_renderer.dev.js.map",
stylesheet = NULL,
Expand All@@ -60,9 +60,9 @@
all_files = FALSE),
class = "html_dependency"),
`dash-renderer-prod` = structure(list(name = "dash-renderer",
version = "1.8.2",
src = list(href = "https://unpkg.com/dash-renderer@1.8.2",
file = "lib/dash-renderer@1.8.2"),
version = "1.8.3",
src = list(href = "https://unpkg.com/dash-renderer@1.8.3",
file = "lib/dash-renderer@1.8.3"),
meta = NULL,
script = "dash-renderer/dash_renderer.min.js",
stylesheet = NULL,
Expand All@@ -72,9 +72,9 @@
all_files = FALSE),
class = "html_dependency"),
`dash-renderer-map-prod` = structure(list(name = "dash-renderer",
version = "1.8.2",
src = list(href = "https://unpkg.com/dash-renderer@1.8.2",
file = "lib/dash-renderer@1.8.2"),
version = "1.8.3",
src = list(href = "https://unpkg.com/dash-renderer@1.8.3",
file = "lib/dash-renderer@1.8.3"),
meta = NULL,
script = "dash-renderer/dash_renderer.min.js.map",
stylesheet = NULL,
Expand Down
14 changes: 9 additions & 5 deletions R/utils.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -1054,26 +1054,30 @@ setCallbackContext <- function(callback_elements) {
function(x) {
input_id <- splitIdProp(x)[1]
prop <- splitIdProp(x)[2]

# The following conditionals check whether the callback is a pattern-matching callback and if it has been triggered.
if (startsWith(input_id, "{")){
id_match <- vapply(callback_elements$inputs, function(x) {
x <- unlist(x)
any(x[grepl("id.", names(x))] %in% jsonlite::fromJSON(input_id)[[1]])
}, logical(1))[[1]]
} else {
id_match <- vapply(callback_elements$inputs, function(x) x$id %in% input_id, logical(1))
id_match <- vapply(callback_elements$inputs, function(x) {
unlist(x)
any(x$id %in% input_id)}, logical(1))
}

if (startsWith(input_id, "{")){
prop_match <- vapply(callback_elements$inputs, function(x) {
x <- unlist(x)
any(x[names(x) == "property"] %in% prop)
}, logical(1))[[1]]
} else {
prop_match <- vapply(callback_elements$inputs, function(x) x$property %in% prop, logical(1))
prop_match <- vapply(callback_elements$inputs, function(x) {
unlist(x)
any(x$property %in% prop)}, logical(1))
}

if (startsWith(input_id, "{")){
if (length(callback_elements$inputs) == 1 || !is.null(unlist(callback_elements$inputs, recursive = F)$value)) {
value <- sapply(callback_elements$inputs[id_match & prop_match], `[[`, "value")
Expand Down
127 changes: 127 additions & 0 deletions tests/integration/callbacks/test_pattern_matching.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -318,6 +318,120 @@
"""


graphs_app = """
library(dash)
library(dashHtmlComponents)
library(dashCoreComponents)
library(plotly)

df <- read.csv(
file = "https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv",
stringsAsFactor=FALSE,
check.names=FALSE
)

app <- Dash$new()

app$layout(
htmlDiv(
list(
htmlDiv(
list(
dccDropdown(options = lapply(unique(df[,"country"]), function(x) {
list(label = x, value = x)
}),
value = "Canada",
id = "country",
style = list(display = "inline-block",
width = 200)
),
htmlButton(
"add Chart",
id = "add-chart",
n_clicks = 0,
style = list(display = "inline-block")
)
)
),
htmlDiv(id = "container", children=list()),
htmlDiv(id = "output-delay")
)
)
)

create_figure <- function(df, column_x, column_y, country) {
df <- df[which(df[, "country"] == country),]
if (column_x == "year") {
fig <- plot_ly(df, x = df[,column_x], y = df[,column_y], name = column_x, type = "scatter", mode = "lines")
} else {
fig <- plot_ly(df, x = df[,column_x], y = df[,column_y], name = column_x, type = "scatter", mode = "markers")
}
fig <- plotly::layout(fig, plot_bgcolor="lightblue", xaxis = list(title=""),
yaxis = list(title=""), title=list(text=paste(country, column_y, "vs", column_x),
xanchor="right", margin_l=10, margin_r=0, margin_b=30))
return(fig)
}

app$callback(
output = list(
output(id = "container", property = "children"),
output(id = "output-delay", property = "children")
),
params = list(
input(id = "add-chart", property = "n_clicks"),
state(id = "country", property = "value"),
state(id = "container", property = "children")
),
function(n_clicks, country, children) {
default_column_x <- "year"
default_column_y <- "gdpPercap"

new_element <- htmlDiv(
style = list(width = "23%", display = "inline-block", outline = "thin lightgrey solid", padding = 10),
children = list(
dccGraph(
id = list(type = "dynamic-output", index = n_clicks),
style = list(height = 300),
figure = create_figure(df, default_column_x, default_column_y, country)
),
dccDropdown(
id = list(type = "dynamic-dropdown-x", index = n_clicks),
options = lapply(colnames(df), function(x) {
list(label = x, value = x)
}),
value = default_column_x
),
dccDropdown(
id = list(type = "dynamic-dropdown-y", index = n_clicks),
options = lapply(colnames(df), function(x) {
list(label = x, value = x)
}),
value = default_column_y
)
)
)

children <- c(children, list(new_element))
return(list(children, n_clicks))
}
)

app$callback(
output(id = list("index" = MATCH, "type" = "dynamic-output"), property = "figure"),
params = list(
input(id = list("index" = MATCH, "type" = "dynamic-dropdown-x"), property = "value"),
input(id = list("index" = MATCH, "type" = "dynamic-dropdown-y"), property = "value"),
input(id = "country", property = "value")
),
function(column_x, column_y, country) {
return(create_figure(df, column_x, column_y, country))
}
)

app$run_server()
"""


def test_rpmc001_pattern_matching_all(dashr):
dashr.start_server(all_app)
dashr.find_element("#add-filter").click()
Expand DownExpand Up@@ -370,3 +484,16 @@ def test_rpmc004_pattern_matching_todo(dashr):
dashr.find_element("#add").click()
dashr.find_element('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"done\\"\\}').click()
assert dashr.wait_for_text_to_equal("#totals", "1 of 1 items completed - 100%")


def test_rpmc005_pattern_matching_graphs(dashr):
dashr.start_server(graphs_app)
dashr.select_dcc_dropdown("#country", "Cameroon")
dashr.wait_for_text_to_equal("#output-delay", "0")
dashr.find_element("#add-chart").click()
dashr.wait_for_text_to_equal("#output-delay", "1")
dashr.find_element('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"dynamic-output\\"\\}')
dashr.select_dcc_dropdown('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"dynamic-dropdown-x\\"\\}', "year")
dashr.select_dcc_dropdown('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"dynamic-dropdown-y\\"\\}', "pop")
dashr.percy_snapshot("r-pmc-graphs")
dashr.wait_for_element('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"dynamic-output\\"\\}')
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
e5b0cfe
contribute test script
Aug 3, 2020
a242d49
remove version updating in DESCRIPTION
Aug 3, 2020
f1b81d6
fix EOL
rpkyle Aug 4, 2020
4d234cb
Merge pull request #222 from plotly/212-untangle-dashr-build
rpkyle Aug 4, 2020
4e4ccb1
Add support for user-defined server routes (#225)
rpkyle Aug 28, 2020
5bd1bbb
Provide support for script and stylesheet attributes (#226)
rpkyle Sep 4, 2020
3f862f9
Authenticate on pulls from Docker Hub (#231)
rpkyle Oct 6, 2020
3a3ee2f
Add support for callback graph improvements and timing (#224)
rpkyle Oct 9, 2020
766e3a8
Update CHANGELOG.md
rpkyle Oct 12, 2020
3b54773
189 - Add Pattern Matching Callbacks for Dash R (#228)
HammadTheOne Oct 21, 2020
03ed383
Fixing Null error with glue::glue interpolation (#233)
HammadTheOne Oct 21, 2020
5b31534
Update CHANGELOG.md
rpkyle Oct 26, 2020
2fdd157
Update dash-renderer to v1.8.2 (#234)
rpkyle Oct 26, 2020
bb9fc6a
bump package version to v0.8.0
Oct 26, 2020
314ced8
Update R/dash.R
rpkyle Oct 27, 2020
3f9f9f1
Update tests/testthat/test-wildcards.R
rpkyle Oct 27, 2020
e093463
Update DESCRIPTION
rpkyle Oct 27, 2020
6ee2702
Merge branch 'master' into dev
rpkyle Oct 27, 2020
b477fe0
add PMC example
Oct 27, 2020
6fffb44
update documentation
Oct 27, 2020
b4ca5f9
update CHANGELOG release date
Oct 27, 2020
24b491a
Merge branch 'dev' of github.com:plotly/dashR into dev
Oct 27, 2020
c120ab2
:hammer: PMC docs refactor
Oct 27, 2020
56d1dc0
Update tests/integration/callbacks/test_pattern_matching.py
rpkyle Oct 27, 2020
226f949
Update tests/integration/callbacks/test_pattern_matching.py
rpkyle Oct 27, 2020
fd5f3da
Update tests/integration/callbacks/test_pattern_matching.py
rpkyle Oct 28, 2020
c3a34b6
add import of glue
Oct 28, 2020
877f463
add glue to imports.R
Oct 28, 2020
b238a57
fix line length issue
Oct 28, 2020
ff858ac
Fix setCallbackContext for wildcard and ordinary inputs (#237)
HammadTheOne Oct 30, 2020
7a23405
Merge branch 'master' into dev
rpkyle Oct 31, 2020
aac1db5
bump dependency versions
Oct 31, 2020
b7b1cfa
update CHANGELOG
Oct 31, 2020
4326e08
update dash-renderer to v1.8.3
Oct 31, 2020
ed022c8
update CHANGELOG
Oct 31, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,6 +2,18 @@
All notable changes to `dash` will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).

## [0.9.0] - 2020-10-31

### Fixed
- Fixes a minor bug in `setCallbackContext` (described in [#236](https://github.com/plotly/dashR/issues/236)) which prevented pattern-matching callbacks from working properly if one or more `input` statements did not include a selector. [#237](https://github.com/plotly/dashR/pull/237)

### Changed

- Dash for R now depends on v1.1.1 of `dashHtmlComponents`
- Dash for R now depends on v1.13.0 of `dashCoreComponents`
- Dash for R now depends on v4.11.0 of `dashTable`
- `dash-renderer` version is now v1.8.3

## [0.8.0] - 2020-10-27
### Fixed
- Usage of `glue` has been corrected to address [#232](https://github.com/plotly/dashR/issues/232) via [#233](https://github.com/plotly/dashR/pull/233).
Expand Down
14 changes: 7 additions & 7 deletions DESCRIPTION
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
Package: dash
Title: An Interface to the Dash Ecosystem for Authoring Reactive Web Applications
Version: 0.8.0
Version: 0.9.0
Authors@R: c(person("Chris", "Parmer", role = c("aut"), email = "chris@plotly.com"), person("Ryan Patrick", "Kyle", role = c("aut", "cre"), comment = c(ORCID = "0000-0001-5829-9867"), email = "ryan@plotly.com"), person("Carson", "Sievert", role = c("aut"), comment = c(ORCID = "0000-0002-4958-2844")), person("Hammad", "Khan", role = c("aut"), comment = c(ORCID = "0000-0003-2479-9841"), email = "hammadkhan@plotly.com"), person(family = "Plotly Technologies", role = "cph"))
Description: A framework for building analytical web applications, Dash offers a pleasant and productive development experience. No JavaScript required.
Depends:
R (>= 3.0.2)
Imports:
dashHtmlComponents (== 1.0.3),
dashCoreComponents (== 1.10.2),
dashTable (== 4.9.0),
dashHtmlComponents (== 1.1.1),
dashCoreComponents (== 1.13.0),
dashTable (== 4.11.0),
R6,
fiery (> 1.0.0),
routr (> 0.2.0),
Expand All@@ -33,9 +33,9 @@ Collate:
'imports.R'
'print.R'
'internal.R'
Remotes: plotly/dash-html-components@e63acfa,
plotly/dash-core-components@0770afb,
plotly/dash-table@75ac3d9
Remotes: plotly/dash-html-components@7209e0a,
plotly/dash-core-components@91a424e,
plotly/dash-table@aa519b7
License: MIT + file LICENSE
Encoding: UTF-8
LazyData: true
Expand Down
24 changes: 12 additions & 12 deletions R/internal.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -36,9 +36,9 @@
all_files = FALSE),
class = "html_dependency"),
`dash-renderer-dev` = structure(list(name = "dash-renderer",
version = "1.8.2",
src = list(href = "https://unpkg.com/dash-renderer@1.8.2",
file = "lib/dash-renderer@1.8.2"),
version = "1.8.3",
src = list(href = "https://unpkg.com/dash-renderer@1.8.3",
file = "lib/dash-renderer@1.8.3"),
meta = NULL,
script = "dash-renderer/dash_renderer.dev.js",
stylesheet = NULL,
Expand All@@ -48,9 +48,9 @@
all_files = FALSE),
class = "html_dependency"),
`dash-renderer-map-dev` = structure(list(name = "dash-renderer",
version = "1.8.2",
src = list(href = "https://unpkg.com/dash-renderer@1.8.2",
file = "lib/dash-renderer@1.8.2"),
version = "1.8.3",
src = list(href = "https://unpkg.com/dash-renderer@1.8.3",
file = "lib/dash-renderer@1.8.3"),
meta = NULL,
script = "dash-renderer/dash_renderer.dev.js.map",
stylesheet = NULL,
Expand All@@ -60,9 +60,9 @@
all_files = FALSE),
class = "html_dependency"),
`dash-renderer-prod` = structure(list(name = "dash-renderer",
version = "1.8.2",
src = list(href = "https://unpkg.com/dash-renderer@1.8.2",
file = "lib/dash-renderer@1.8.2"),
version = "1.8.3",
src = list(href = "https://unpkg.com/dash-renderer@1.8.3",
file = "lib/dash-renderer@1.8.3"),
meta = NULL,
script = "dash-renderer/dash_renderer.min.js",
stylesheet = NULL,
Expand All@@ -72,9 +72,9 @@
all_files = FALSE),
class = "html_dependency"),
`dash-renderer-map-prod` = structure(list(name = "dash-renderer",
version = "1.8.2",
src = list(href = "https://unpkg.com/dash-renderer@1.8.2",
file = "lib/dash-renderer@1.8.2"),
version = "1.8.3",
src = list(href = "https://unpkg.com/dash-renderer@1.8.3",
file = "lib/dash-renderer@1.8.3"),
meta = NULL,
script = "dash-renderer/dash_renderer.min.js.map",
stylesheet = NULL,
Expand Down
14 changes: 9 additions & 5 deletions R/utils.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -1054,26 +1054,30 @@ setCallbackContext <- function(callback_elements) {
function(x) {
input_id <- splitIdProp(x)[1]
prop <- splitIdProp(x)[2]

# The following conditionals check whether the callback is a pattern-matching callback and if it has been triggered.
if (startsWith(input_id, "{")){
id_match <- vapply(callback_elements$inputs, function(x) {
x <- unlist(x)
any(x[grepl("id.", names(x))] %in% jsonlite::fromJSON(input_id)[[1]])
}, logical(1))[[1]]
} else {
id_match <- vapply(callback_elements$inputs, function(x) x$id %in% input_id, logical(1))
id_match <- vapply(callback_elements$inputs, function(x) {
unlist(x)
any(x$id %in% input_id)}, logical(1))
}

if (startsWith(input_id, "{")){
prop_match <- vapply(callback_elements$inputs, function(x) {
x <- unlist(x)
any(x[names(x) == "property"] %in% prop)
}, logical(1))[[1]]
} else {
prop_match <- vapply(callback_elements$inputs, function(x) x$property %in% prop, logical(1))
prop_match <- vapply(callback_elements$inputs, function(x) {
unlist(x)
any(x$property %in% prop)}, logical(1))
}

if (startsWith(input_id, "{")){
if (length(callback_elements$inputs) == 1 || !is.null(unlist(callback_elements$inputs, recursive = F)$value)) {
value <- sapply(callback_elements$inputs[id_match & prop_match], `[[`, "value")
Expand Down
127 changes: 127 additions & 0 deletions tests/integration/callbacks/test_pattern_matching.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -318,6 +318,120 @@
"""


graphs_app = """
library(dash)
library(dashHtmlComponents)
library(dashCoreComponents)
library(plotly)

df <- read.csv(
file = "https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv",
stringsAsFactor=FALSE,
check.names=FALSE
)

app <- Dash$new()

app$layout(
htmlDiv(
list(
htmlDiv(
list(
dccDropdown(options = lapply(unique(df[,"country"]), function(x) {
list(label = x, value = x)
}),
value = "Canada",
id = "country",
style = list(display = "inline-block",
width = 200)
),
htmlButton(
"add Chart",
id = "add-chart",
n_clicks = 0,
style = list(display = "inline-block")
)
)
),
htmlDiv(id = "container", children=list()),
htmlDiv(id = "output-delay")
)
)
)

create_figure <- function(df, column_x, column_y, country) {
df <- df[which(df[, "country"] == country),]
if (column_x == "year") {
fig <- plot_ly(df, x = df[,column_x], y = df[,column_y], name = column_x, type = "scatter", mode = "lines")
} else {
fig <- plot_ly(df, x = df[,column_x], y = df[,column_y], name = column_x, type = "scatter", mode = "markers")
}
fig <- plotly::layout(fig, plot_bgcolor="lightblue", xaxis = list(title=""),
yaxis = list(title=""), title=list(text=paste(country, column_y, "vs", column_x),
xanchor="right", margin_l=10, margin_r=0, margin_b=30))
return(fig)
}

app$callback(
output = list(
output(id = "container", property = "children"),
output(id = "output-delay", property = "children")
),
params = list(
input(id = "add-chart", property = "n_clicks"),
state(id = "country", property = "value"),
state(id = "container", property = "children")
),
function(n_clicks, country, children) {
default_column_x <- "year"
default_column_y <- "gdpPercap"

new_element <- htmlDiv(
style = list(width = "23%", display = "inline-block", outline = "thin lightgrey solid", padding = 10),
children = list(
dccGraph(
id = list(type = "dynamic-output", index = n_clicks),
style = list(height = 300),
figure = create_figure(df, default_column_x, default_column_y, country)
),
dccDropdown(
id = list(type = "dynamic-dropdown-x", index = n_clicks),
options = lapply(colnames(df), function(x) {
list(label = x, value = x)
}),
value = default_column_x
),
dccDropdown(
id = list(type = "dynamic-dropdown-y", index = n_clicks),
options = lapply(colnames(df), function(x) {
list(label = x, value = x)
}),
value = default_column_y
)
)
)

children <- c(children, list(new_element))
return(list(children, n_clicks))
}
)

app$callback(
output(id = list("index" = MATCH, "type" = "dynamic-output"), property = "figure"),
params = list(
input(id = list("index" = MATCH, "type" = "dynamic-dropdown-x"), property = "value"),
input(id = list("index" = MATCH, "type" = "dynamic-dropdown-y"), property = "value"),
input(id = "country", property = "value")
),
function(column_x, column_y, country) {
return(create_figure(df, column_x, column_y, country))
}
)

app$run_server()
"""


def test_rpmc001_pattern_matching_all(dashr):
dashr.start_server(all_app)
dashr.find_element("#add-filter").click()
Expand DownExpand Up@@ -370,3 +484,16 @@ def test_rpmc004_pattern_matching_todo(dashr):
dashr.find_element("#add").click()
dashr.find_element('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"done\\"\\}').click()
assert dashr.wait_for_text_to_equal("#totals", "1 of 1 items completed - 100%")


def test_rpmc005_pattern_matching_graphs(dashr):
dashr.start_server(graphs_app)
dashr.select_dcc_dropdown("#country", "Cameroon")
dashr.wait_for_text_to_equal("#output-delay", "0")
dashr.find_element("#add-chart").click()
dashr.wait_for_text_to_equal("#output-delay", "1")
dashr.find_element('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"dynamic-output\\"\\}')
dashr.select_dcc_dropdown('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"dynamic-dropdown-x\\"\\}', "year")
dashr.select_dcc_dropdown('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"dynamic-dropdown-y\\"\\}', "pop")
dashr.percy_snapshot("r-pmc-graphs")
dashr.wait_for_element('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"dynamic-output\\"\\}')
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
e5b0cfe
contribute test script
Aug 3, 2020
a242d49
remove version updating in DESCRIPTION
Aug 3, 2020
f1b81d6
fix EOL
rpkyle Aug 4, 2020
4d234cb
Merge pull request #222 from plotly/212-untangle-dashr-build
rpkyle Aug 4, 2020
4e4ccb1
Add support for user-defined server routes (#225)
rpkyle Aug 28, 2020
5bd1bbb
Provide support for script and stylesheet attributes (#226)
rpkyle Sep 4, 2020
3f862f9
Authenticate on pulls from Docker Hub (#231)
rpkyle Oct 6, 2020
3a3ee2f
Add support for callback graph improvements and timing (#224)
rpkyle Oct 9, 2020
766e3a8
Update CHANGELOG.md
rpkyle Oct 12, 2020
3b54773
189 - Add Pattern Matching Callbacks for Dash R (#228)
HammadTheOne Oct 21, 2020
03ed383
Fixing Null error with glue::glue interpolation (#233)
HammadTheOne Oct 21, 2020
5b31534
Update CHANGELOG.md
rpkyle Oct 26, 2020
2fdd157
Update dash-renderer to v1.8.2 (#234)
rpkyle Oct 26, 2020
bb9fc6a
bump package version to v0.8.0
Oct 26, 2020
314ced8
Update R/dash.R
rpkyle Oct 27, 2020
3f9f9f1
Update tests/testthat/test-wildcards.R
rpkyle Oct 27, 2020
e093463
Update DESCRIPTION
rpkyle Oct 27, 2020
6ee2702
Merge branch 'master' into dev
rpkyle Oct 27, 2020
b477fe0
add PMC example
Oct 27, 2020
6fffb44
update documentation
Oct 27, 2020
b4ca5f9
update CHANGELOG release date
Oct 27, 2020
24b491a
Merge branch 'dev' of github.com:plotly/dashR into dev
Oct 27, 2020
c120ab2
:hammer: PMC docs refactor
Oct 27, 2020
56d1dc0
Update tests/integration/callbacks/test_pattern_matching.py
rpkyle Oct 27, 2020
226f949
Update tests/integration/callbacks/test_pattern_matching.py
rpkyle Oct 27, 2020
fd5f3da
Update tests/integration/callbacks/test_pattern_matching.py
rpkyle Oct 28, 2020
c3a34b6
add import of glue
Oct 28, 2020
877f463
add glue to imports.R
Oct 28, 2020
b238a57
fix line length issue
Oct 28, 2020
ff858ac
Fix setCallbackContext for wildcard and ordinary inputs (#237)
HammadTheOne Oct 30, 2020
7a23405
Merge branch 'master' into dev
rpkyle Oct 31, 2020
aac1db5
bump dependency versions
Oct 31, 2020
b7b1cfa
update CHANGELOG
Oct 31, 2020
4326e08
update dash-renderer to v1.8.3
Oct 31, 2020
ed022c8
update CHANGELOG
Oct 31, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,6 +2,18 @@
All notable changes to `dash` will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).

## [0.9.0] - 2020-10-31

### Fixed
- Fixes a minor bug in `setCallbackContext` (described in [#236](https://github.com/plotly/dashR/issues/236)) which prevented pattern-matching callbacks from working properly if one or more `input` statements did not include a selector. [#237](https://github.com/plotly/dashR/pull/237)

### Changed

- Dash for R now depends on v1.1.1 of `dashHtmlComponents`
- Dash for R now depends on v1.13.0 of `dashCoreComponents`
- Dash for R now depends on v4.11.0 of `dashTable`
- `dash-renderer` version is now v1.8.3

## [0.8.0] - 2020-10-27
### Fixed
- Usage of `glue` has been corrected to address [#232](https://github.com/plotly/dashR/issues/232) via [#233](https://github.com/plotly/dashR/pull/233).
Expand Down
14 changes: 7 additions & 7 deletions DESCRIPTION
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
Package: dash
Title: An Interface to the Dash Ecosystem for Authoring Reactive Web Applications
Version: 0.8.0
Version: 0.9.0
Authors@R: c(person("Chris", "Parmer", role = c("aut"), email = "chris@plotly.com"), person("Ryan Patrick", "Kyle", role = c("aut", "cre"), comment = c(ORCID = "0000-0001-5829-9867"), email = "ryan@plotly.com"), person("Carson", "Sievert", role = c("aut"), comment = c(ORCID = "0000-0002-4958-2844")), person("Hammad", "Khan", role = c("aut"), comment = c(ORCID = "0000-0003-2479-9841"), email = "hammadkhan@plotly.com"), person(family = "Plotly Technologies", role = "cph"))
Description: A framework for building analytical web applications, Dash offers a pleasant and productive development experience. No JavaScript required.
Depends:
R (>= 3.0.2)
Imports:
dashHtmlComponents (== 1.0.3),
dashCoreComponents (== 1.10.2),
dashTable (== 4.9.0),
dashHtmlComponents (== 1.1.1),
dashCoreComponents (== 1.13.0),
dashTable (== 4.11.0),
R6,
fiery (> 1.0.0),
routr (> 0.2.0),
Expand All@@ -33,9 +33,9 @@ Collate:
'imports.R'
'print.R'
'internal.R'
Remotes: plotly/dash-html-components@e63acfa,
plotly/dash-core-components@0770afb,
plotly/dash-table@75ac3d9
Remotes: plotly/dash-html-components@7209e0a,
plotly/dash-core-components@91a424e,
plotly/dash-table@aa519b7
License: MIT + file LICENSE
Encoding: UTF-8
LazyData: true
Expand Down
24 changes: 12 additions & 12 deletions R/internal.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -36,9 +36,9 @@
all_files = FALSE),
class = "html_dependency"),
`dash-renderer-dev` = structure(list(name = "dash-renderer",
version = "1.8.2",
src = list(href = "https://unpkg.com/dash-renderer@1.8.2",
file = "lib/dash-renderer@1.8.2"),
version = "1.8.3",
src = list(href = "https://unpkg.com/dash-renderer@1.8.3",
file = "lib/dash-renderer@1.8.3"),
meta = NULL,
script = "dash-renderer/dash_renderer.dev.js",
stylesheet = NULL,
Expand All@@ -48,9 +48,9 @@
all_files = FALSE),
class = "html_dependency"),
`dash-renderer-map-dev` = structure(list(name = "dash-renderer",
version = "1.8.2",
src = list(href = "https://unpkg.com/dash-renderer@1.8.2",
file = "lib/dash-renderer@1.8.2"),
version = "1.8.3",
src = list(href = "https://unpkg.com/dash-renderer@1.8.3",
file = "lib/dash-renderer@1.8.3"),
meta = NULL,
script = "dash-renderer/dash_renderer.dev.js.map",
stylesheet = NULL,
Expand All@@ -60,9 +60,9 @@
all_files = FALSE),
class = "html_dependency"),
`dash-renderer-prod` = structure(list(name = "dash-renderer",
version = "1.8.2",
src = list(href = "https://unpkg.com/dash-renderer@1.8.2",
file = "lib/dash-renderer@1.8.2"),
version = "1.8.3",
src = list(href = "https://unpkg.com/dash-renderer@1.8.3",
file = "lib/dash-renderer@1.8.3"),
meta = NULL,
script = "dash-renderer/dash_renderer.min.js",
stylesheet = NULL,
Expand All@@ -72,9 +72,9 @@
all_files = FALSE),
class = "html_dependency"),
`dash-renderer-map-prod` = structure(list(name = "dash-renderer",
version = "1.8.2",
src = list(href = "https://unpkg.com/dash-renderer@1.8.2",
file = "lib/dash-renderer@1.8.2"),
version = "1.8.3",
src = list(href = "https://unpkg.com/dash-renderer@1.8.3",
file = "lib/dash-renderer@1.8.3"),
meta = NULL,
script = "dash-renderer/dash_renderer.min.js.map",
stylesheet = NULL,
Expand Down
14 changes: 9 additions & 5 deletions R/utils.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -1054,26 +1054,30 @@ setCallbackContext <- function(callback_elements) {
function(x) {
input_id <- splitIdProp(x)[1]
prop <- splitIdProp(x)[2]

# The following conditionals check whether the callback is a pattern-matching callback and if it has been triggered.
if (startsWith(input_id, "{")){
id_match <- vapply(callback_elements$inputs, function(x) {
x <- unlist(x)
any(x[grepl("id.", names(x))] %in% jsonlite::fromJSON(input_id)[[1]])
}, logical(1))[[1]]
} else {
id_match <- vapply(callback_elements$inputs, function(x) x$id %in% input_id, logical(1))
id_match <- vapply(callback_elements$inputs, function(x) {
unlist(x)
any(x$id %in% input_id)}, logical(1))
}

if (startsWith(input_id, "{")){
prop_match <- vapply(callback_elements$inputs, function(x) {
x <- unlist(x)
any(x[names(x) == "property"] %in% prop)
}, logical(1))[[1]]
} else {
prop_match <- vapply(callback_elements$inputs, function(x) x$property %in% prop, logical(1))
prop_match <- vapply(callback_elements$inputs, function(x) {
unlist(x)
any(x$property %in% prop)}, logical(1))
}

if (startsWith(input_id, "{")){
if (length(callback_elements$inputs) == 1 || !is.null(unlist(callback_elements$inputs, recursive = F)$value)) {
value <- sapply(callback_elements$inputs[id_match & prop_match], `[[`, "value")
Expand Down
127 changes: 127 additions & 0 deletions tests/integration/callbacks/test_pattern_matching.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -318,6 +318,120 @@
"""


graphs_app = """
library(dash)
library(dashHtmlComponents)
library(dashCoreComponents)
library(plotly)

df <- read.csv(
file = "https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv",
stringsAsFactor=FALSE,
check.names=FALSE
)

app <- Dash$new()

app$layout(
htmlDiv(
list(
htmlDiv(
list(
dccDropdown(options = lapply(unique(df[,"country"]), function(x) {
list(label = x, value = x)
}),
value = "Canada",
id = "country",
style = list(display = "inline-block",
width = 200)
),
htmlButton(
"add Chart",
id = "add-chart",
n_clicks = 0,
style = list(display = "inline-block")
)
)
),
htmlDiv(id = "container", children=list()),
htmlDiv(id = "output-delay")
)
)
)

create_figure <- function(df, column_x, column_y, country) {
df <- df[which(df[, "country"] == country),]
if (column_x == "year") {
fig <- plot_ly(df, x = df[,column_x], y = df[,column_y], name = column_x, type = "scatter", mode = "lines")
} else {
fig <- plot_ly(df, x = df[,column_x], y = df[,column_y], name = column_x, type = "scatter", mode = "markers")
}
fig <- plotly::layout(fig, plot_bgcolor="lightblue", xaxis = list(title=""),
yaxis = list(title=""), title=list(text=paste(country, column_y, "vs", column_x),
xanchor="right", margin_l=10, margin_r=0, margin_b=30))
return(fig)
}

app$callback(
output = list(
output(id = "container", property = "children"),
output(id = "output-delay", property = "children")
),
params = list(
input(id = "add-chart", property = "n_clicks"),
state(id = "country", property = "value"),
state(id = "container", property = "children")
),
function(n_clicks, country, children) {
default_column_x <- "year"
default_column_y <- "gdpPercap"

new_element <- htmlDiv(
style = list(width = "23%", display = "inline-block", outline = "thin lightgrey solid", padding = 10),
children = list(
dccGraph(
id = list(type = "dynamic-output", index = n_clicks),
style = list(height = 300),
figure = create_figure(df, default_column_x, default_column_y, country)
),
dccDropdown(
id = list(type = "dynamic-dropdown-x", index = n_clicks),
options = lapply(colnames(df), function(x) {
list(label = x, value = x)
}),
value = default_column_x
),
dccDropdown(
id = list(type = "dynamic-dropdown-y", index = n_clicks),
options = lapply(colnames(df), function(x) {
list(label = x, value = x)
}),
value = default_column_y
)
)
)

children <- c(children, list(new_element))
return(list(children, n_clicks))
}
)

app$callback(
output(id = list("index" = MATCH, "type" = "dynamic-output"), property = "figure"),
params = list(
input(id = list("index" = MATCH, "type" = "dynamic-dropdown-x"), property = "value"),
input(id = list("index" = MATCH, "type" = "dynamic-dropdown-y"), property = "value"),
input(id = "country", property = "value")
),
function(column_x, column_y, country) {
return(create_figure(df, column_x, column_y, country))
}
)

app$run_server()
"""


def test_rpmc001_pattern_matching_all(dashr):
dashr.start_server(all_app)
dashr.find_element("#add-filter").click()
Expand DownExpand Up@@ -370,3 +484,16 @@ def test_rpmc004_pattern_matching_todo(dashr):
dashr.find_element("#add").click()
dashr.find_element('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"done\\"\\}').click()
assert dashr.wait_for_text_to_equal("#totals", "1 of 1 items completed - 100%")


def test_rpmc005_pattern_matching_graphs(dashr):
dashr.start_server(graphs_app)
dashr.select_dcc_dropdown("#country", "Cameroon")
dashr.wait_for_text_to_equal("#output-delay", "0")
dashr.find_element("#add-chart").click()
dashr.wait_for_text_to_equal("#output-delay", "1")
dashr.find_element('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"dynamic-output\\"\\}')
dashr.select_dcc_dropdown('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"dynamic-dropdown-x\\"\\}', "year")
dashr.select_dcc_dropdown('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"dynamic-dropdown-y\\"\\}', "pop")
dashr.percy_snapshot("r-pmc-graphs")
dashr.wait_for_element('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"dynamic-output\\"\\}')
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
e5b0cfe
contribute test script
Aug 3, 2020
a242d49
remove version updating in DESCRIPTION
Aug 3, 2020
f1b81d6
fix EOL
rpkyle Aug 4, 2020
4d234cb
Merge pull request #222 from plotly/212-untangle-dashr-build
rpkyle Aug 4, 2020
4e4ccb1
Add support for user-defined server routes (#225)
rpkyle Aug 28, 2020
5bd1bbb
Provide support for script and stylesheet attributes (#226)
rpkyle Sep 4, 2020
3f862f9
Authenticate on pulls from Docker Hub (#231)
rpkyle Oct 6, 2020
3a3ee2f
Add support for callback graph improvements and timing (#224)
rpkyle Oct 9, 2020
766e3a8
Update CHANGELOG.md
rpkyle Oct 12, 2020
3b54773
189 - Add Pattern Matching Callbacks for Dash R (#228)
HammadTheOne Oct 21, 2020
03ed383
Fixing Null error with glue::glue interpolation (#233)
HammadTheOne Oct 21, 2020
5b31534
Update CHANGELOG.md
rpkyle Oct 26, 2020
2fdd157
Update dash-renderer to v1.8.2 (#234)
rpkyle Oct 26, 2020
bb9fc6a
bump package version to v0.8.0
Oct 26, 2020
314ced8
Update R/dash.R
rpkyle Oct 27, 2020
3f9f9f1
Update tests/testthat/test-wildcards.R
rpkyle Oct 27, 2020
e093463
Update DESCRIPTION
rpkyle Oct 27, 2020
6ee2702
Merge branch 'master' into dev
rpkyle Oct 27, 2020
b477fe0
add PMC example
Oct 27, 2020
6fffb44
update documentation
Oct 27, 2020
b4ca5f9
update CHANGELOG release date
Oct 27, 2020
24b491a
Merge branch 'dev' of github.com:plotly/dashR into dev
Oct 27, 2020
c120ab2
:hammer: PMC docs refactor
Oct 27, 2020
56d1dc0
Update tests/integration/callbacks/test_pattern_matching.py
rpkyle Oct 27, 2020
226f949
Update tests/integration/callbacks/test_pattern_matching.py
rpkyle Oct 27, 2020
fd5f3da
Update tests/integration/callbacks/test_pattern_matching.py
rpkyle Oct 28, 2020
c3a34b6
add import of glue
Oct 28, 2020
877f463
add glue to imports.R
Oct 28, 2020
b238a57
fix line length issue
Oct 28, 2020
ff858ac
Fix setCallbackContext for wildcard and ordinary inputs (#237)
HammadTheOne Oct 30, 2020
7a23405
Merge branch 'master' into dev
rpkyle Oct 31, 2020
aac1db5
bump dependency versions
Oct 31, 2020
b7b1cfa
update CHANGELOG
Oct 31, 2020
4326e08
update dash-renderer to v1.8.3
Oct 31, 2020
ed022c8
update CHANGELOG
Oct 31, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,6 +2,18 @@
All notable changes to `dash` will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).

## [0.9.0] - 2020-10-31

### Fixed
- Fixes a minor bug in `setCallbackContext` (described in [#236](https://github.com/plotly/dashR/issues/236)) which prevented pattern-matching callbacks from working properly if one or more `input` statements did not include a selector. [#237](https://github.com/plotly/dashR/pull/237)

### Changed

- Dash for R now depends on v1.1.1 of `dashHtmlComponents`
- Dash for R now depends on v1.13.0 of `dashCoreComponents`
- Dash for R now depends on v4.11.0 of `dashTable`
- `dash-renderer` version is now v1.8.3

## [0.8.0] - 2020-10-27
### Fixed
- Usage of `glue` has been corrected to address [#232](https://github.com/plotly/dashR/issues/232) via [#233](https://github.com/plotly/dashR/pull/233).
Expand Down
14 changes: 7 additions & 7 deletions DESCRIPTION
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
Package: dash
Title: An Interface to the Dash Ecosystem for Authoring Reactive Web Applications
Version: 0.8.0
Version: 0.9.0
Authors@R: c(person("Chris", "Parmer", role = c("aut"), email = "chris@plotly.com"), person("Ryan Patrick", "Kyle", role = c("aut", "cre"), comment = c(ORCID = "0000-0001-5829-9867"), email = "ryan@plotly.com"), person("Carson", "Sievert", role = c("aut"), comment = c(ORCID = "0000-0002-4958-2844")), person("Hammad", "Khan", role = c("aut"), comment = c(ORCID = "0000-0003-2479-9841"), email = "hammadkhan@plotly.com"), person(family = "Plotly Technologies", role = "cph"))
Description: A framework for building analytical web applications, Dash offers a pleasant and productive development experience. No JavaScript required.
Depends:
R (>= 3.0.2)
Imports:
dashHtmlComponents (== 1.0.3),
dashCoreComponents (== 1.10.2),
dashTable (== 4.9.0),
dashHtmlComponents (== 1.1.1),
dashCoreComponents (== 1.13.0),
dashTable (== 4.11.0),
R6,
fiery (> 1.0.0),
routr (> 0.2.0),
Expand All@@ -33,9 +33,9 @@ Collate:
'imports.R'
'print.R'
'internal.R'
Remotes: plotly/dash-html-components@e63acfa,
plotly/dash-core-components@0770afb,
plotly/dash-table@75ac3d9
Remotes: plotly/dash-html-components@7209e0a,
plotly/dash-core-components@91a424e,
plotly/dash-table@aa519b7
License: MIT + file LICENSE
Encoding: UTF-8
LazyData: true
Expand Down
24 changes: 12 additions & 12 deletions R/internal.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -36,9 +36,9 @@
all_files = FALSE),
class = "html_dependency"),
`dash-renderer-dev` = structure(list(name = "dash-renderer",
version = "1.8.2",
src = list(href = "https://unpkg.com/dash-renderer@1.8.2",
file = "lib/dash-renderer@1.8.2"),
version = "1.8.3",
src = list(href = "https://unpkg.com/dash-renderer@1.8.3",
file = "lib/dash-renderer@1.8.3"),
meta = NULL,
script = "dash-renderer/dash_renderer.dev.js",
stylesheet = NULL,
Expand All@@ -48,9 +48,9 @@
all_files = FALSE),
class = "html_dependency"),
`dash-renderer-map-dev` = structure(list(name = "dash-renderer",
version = "1.8.2",
src = list(href = "https://unpkg.com/dash-renderer@1.8.2",
file = "lib/dash-renderer@1.8.2"),
version = "1.8.3",
src = list(href = "https://unpkg.com/dash-renderer@1.8.3",
file = "lib/dash-renderer@1.8.3"),
meta = NULL,
script = "dash-renderer/dash_renderer.dev.js.map",
stylesheet = NULL,
Expand All@@ -60,9 +60,9 @@
all_files = FALSE),
class = "html_dependency"),
`dash-renderer-prod` = structure(list(name = "dash-renderer",
version = "1.8.2",
src = list(href = "https://unpkg.com/dash-renderer@1.8.2",
file = "lib/dash-renderer@1.8.2"),
version = "1.8.3",
src = list(href = "https://unpkg.com/dash-renderer@1.8.3",
file = "lib/dash-renderer@1.8.3"),
meta = NULL,
script = "dash-renderer/dash_renderer.min.js",
stylesheet = NULL,
Expand All@@ -72,9 +72,9 @@
all_files = FALSE),
class = "html_dependency"),
`dash-renderer-map-prod` = structure(list(name = "dash-renderer",
version = "1.8.2",
src = list(href = "https://unpkg.com/dash-renderer@1.8.2",
file = "lib/dash-renderer@1.8.2"),
version = "1.8.3",
src = list(href = "https://unpkg.com/dash-renderer@1.8.3",
file = "lib/dash-renderer@1.8.3"),
meta = NULL,
script = "dash-renderer/dash_renderer.min.js.map",
stylesheet = NULL,
Expand Down
14 changes: 9 additions & 5 deletions R/utils.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -1054,26 +1054,30 @@ setCallbackContext <- function(callback_elements) {
function(x) {
input_id <- splitIdProp(x)[1]
prop <- splitIdProp(x)[2]

# The following conditionals check whether the callback is a pattern-matching callback and if it has been triggered.
if (startsWith(input_id, "{")){
id_match <- vapply(callback_elements$inputs, function(x) {
x <- unlist(x)
any(x[grepl("id.", names(x))] %in% jsonlite::fromJSON(input_id)[[1]])
}, logical(1))[[1]]
} else {
id_match <- vapply(callback_elements$inputs, function(x) x$id %in% input_id, logical(1))
id_match <- vapply(callback_elements$inputs, function(x) {
unlist(x)
any(x$id %in% input_id)}, logical(1))
}

if (startsWith(input_id, "{")){
prop_match <- vapply(callback_elements$inputs, function(x) {
x <- unlist(x)
any(x[names(x) == "property"] %in% prop)
}, logical(1))[[1]]
} else {
prop_match <- vapply(callback_elements$inputs, function(x) x$property %in% prop, logical(1))
prop_match <- vapply(callback_elements$inputs, function(x) {
unlist(x)
any(x$property %in% prop)}, logical(1))
}

if (startsWith(input_id, "{")){
if (length(callback_elements$inputs) == 1 || !is.null(unlist(callback_elements$inputs, recursive = F)$value)) {
value <- sapply(callback_elements$inputs[id_match & prop_match], `[[`, "value")
Expand Down
127 changes: 127 additions & 0 deletions tests/integration/callbacks/test_pattern_matching.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -318,6 +318,120 @@
"""


graphs_app = """
library(dash)
library(dashHtmlComponents)
library(dashCoreComponents)
library(plotly)

df <- read.csv(
file = "https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv",
stringsAsFactor=FALSE,
check.names=FALSE
)

app <- Dash$new()

app$layout(
htmlDiv(
list(
htmlDiv(
list(
dccDropdown(options = lapply(unique(df[,"country"]), function(x) {
list(label = x, value = x)
}),
value = "Canada",
id = "country",
style = list(display = "inline-block",
width = 200)
),
htmlButton(
"add Chart",
id = "add-chart",
n_clicks = 0,
style = list(display = "inline-block")
)
)
),
htmlDiv(id = "container", children=list()),
htmlDiv(id = "output-delay")
)
)
)

create_figure <- function(df, column_x, column_y, country) {
df <- df[which(df[, "country"] == country),]
if (column_x == "year") {
fig <- plot_ly(df, x = df[,column_x], y = df[,column_y], name = column_x, type = "scatter", mode = "lines")
} else {
fig <- plot_ly(df, x = df[,column_x], y = df[,column_y], name = column_x, type = "scatter", mode = "markers")
}
fig <- plotly::layout(fig, plot_bgcolor="lightblue", xaxis = list(title=""),
yaxis = list(title=""), title=list(text=paste(country, column_y, "vs", column_x),
xanchor="right", margin_l=10, margin_r=0, margin_b=30))
return(fig)
}

app$callback(
output = list(
output(id = "container", property = "children"),
output(id = "output-delay", property = "children")
),
params = list(
input(id = "add-chart", property = "n_clicks"),
state(id = "country", property = "value"),
state(id = "container", property = "children")
),
function(n_clicks, country, children) {
default_column_x <- "year"
default_column_y <- "gdpPercap"

new_element <- htmlDiv(
style = list(width = "23%", display = "inline-block", outline = "thin lightgrey solid", padding = 10),
children = list(
dccGraph(
id = list(type = "dynamic-output", index = n_clicks),
style = list(height = 300),
figure = create_figure(df, default_column_x, default_column_y, country)
),
dccDropdown(
id = list(type = "dynamic-dropdown-x", index = n_clicks),
options = lapply(colnames(df), function(x) {
list(label = x, value = x)
}),
value = default_column_x
),
dccDropdown(
id = list(type = "dynamic-dropdown-y", index = n_clicks),
options = lapply(colnames(df), function(x) {
list(label = x, value = x)
}),
value = default_column_y
)
)
)

children <- c(children, list(new_element))
return(list(children, n_clicks))
}
)

app$callback(
output(id = list("index" = MATCH, "type" = "dynamic-output"), property = "figure"),
params = list(
input(id = list("index" = MATCH, "type" = "dynamic-dropdown-x"), property = "value"),
input(id = list("index" = MATCH, "type" = "dynamic-dropdown-y"), property = "value"),
input(id = "country", property = "value")
),
function(column_x, column_y, country) {
return(create_figure(df, column_x, column_y, country))
}
)

app$run_server()
"""


def test_rpmc001_pattern_matching_all(dashr):
dashr.start_server(all_app)
dashr.find_element("#add-filter").click()
Expand DownExpand Up@@ -370,3 +484,16 @@ def test_rpmc004_pattern_matching_todo(dashr):
dashr.find_element("#add").click()
dashr.find_element('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"done\\"\\}').click()
assert dashr.wait_for_text_to_equal("#totals", "1 of 1 items completed - 100%")


def test_rpmc005_pattern_matching_graphs(dashr):
dashr.start_server(graphs_app)
dashr.select_dcc_dropdown("#country", "Cameroon")
dashr.wait_for_text_to_equal("#output-delay", "0")
dashr.find_element("#add-chart").click()
dashr.wait_for_text_to_equal("#output-delay", "1")
dashr.find_element('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"dynamic-output\\"\\}')
dashr.select_dcc_dropdown('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"dynamic-dropdown-x\\"\\}', "year")
dashr.select_dcc_dropdown('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"dynamic-dropdown-y\\"\\}', "pop")
dashr.percy_snapshot("r-pmc-graphs")
dashr.wait_for_element('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"dynamic-output\\"\\}')
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
e5b0cfe
contribute test script
Aug 3, 2020
a242d49
remove version updating in DESCRIPTION
Aug 3, 2020
f1b81d6
fix EOL
rpkyle Aug 4, 2020
4d234cb
Merge pull request #222 from plotly/212-untangle-dashr-build
rpkyle Aug 4, 2020
4e4ccb1
Add support for user-defined server routes (#225)
rpkyle Aug 28, 2020
5bd1bbb
Provide support for script and stylesheet attributes (#226)
rpkyle Sep 4, 2020
3f862f9
Authenticate on pulls from Docker Hub (#231)
rpkyle Oct 6, 2020
3a3ee2f
Add support for callback graph improvements and timing (#224)
rpkyle Oct 9, 2020
766e3a8
Update CHANGELOG.md
rpkyle Oct 12, 2020
3b54773
189 - Add Pattern Matching Callbacks for Dash R (#228)
HammadTheOne Oct 21, 2020
03ed383
Fixing Null error with glue::glue interpolation (#233)
HammadTheOne Oct 21, 2020
5b31534
Update CHANGELOG.md
rpkyle Oct 26, 2020
2fdd157
Update dash-renderer to v1.8.2 (#234)
rpkyle Oct 26, 2020
bb9fc6a
bump package version to v0.8.0
Oct 26, 2020
314ced8
Update R/dash.R
rpkyle Oct 27, 2020
3f9f9f1
Update tests/testthat/test-wildcards.R
rpkyle Oct 27, 2020
e093463
Update DESCRIPTION
rpkyle Oct 27, 2020
6ee2702
Merge branch 'master' into dev
rpkyle Oct 27, 2020
b477fe0
add PMC example
Oct 27, 2020
6fffb44
update documentation
Oct 27, 2020
b4ca5f9
update CHANGELOG release date
Oct 27, 2020
24b491a
Merge branch 'dev' of github.com:plotly/dashR into dev
Oct 27, 2020
c120ab2
:hammer: PMC docs refactor
Oct 27, 2020
56d1dc0
Update tests/integration/callbacks/test_pattern_matching.py
rpkyle Oct 27, 2020
226f949
Update tests/integration/callbacks/test_pattern_matching.py
rpkyle Oct 27, 2020
fd5f3da
Update tests/integration/callbacks/test_pattern_matching.py
rpkyle Oct 28, 2020
c3a34b6
add import of glue
Oct 28, 2020
877f463
add glue to imports.R
Oct 28, 2020
b238a57
fix line length issue
Oct 28, 2020
ff858ac
Fix setCallbackContext for wildcard and ordinary inputs (#237)
HammadTheOne Oct 30, 2020
7a23405
Merge branch 'master' into dev
rpkyle Oct 31, 2020
aac1db5
bump dependency versions
Oct 31, 2020
b7b1cfa
update CHANGELOG
Oct 31, 2020
4326e08
update dash-renderer to v1.8.3
Oct 31, 2020
ed022c8
update CHANGELOG
Oct 31, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,6 +2,18 @@
All notable changes to `dash` will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).

## [0.9.0] - 2020-10-31

### Fixed
- Fixes a minor bug in `setCallbackContext` (described in [#236](https://github.com/plotly/dashR/issues/236)) which prevented pattern-matching callbacks from working properly if one or more `input` statements did not include a selector. [#237](https://github.com/plotly/dashR/pull/237)

### Changed

- Dash for R now depends on v1.1.1 of `dashHtmlComponents`
- Dash for R now depends on v1.13.0 of `dashCoreComponents`
- Dash for R now depends on v4.11.0 of `dashTable`
- `dash-renderer` version is now v1.8.3

## [0.8.0] - 2020-10-27
### Fixed
- Usage of `glue` has been corrected to address [#232](https://github.com/plotly/dashR/issues/232) via [#233](https://github.com/plotly/dashR/pull/233).
Expand Down
14 changes: 7 additions & 7 deletions DESCRIPTION
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
Package: dash
Title: An Interface to the Dash Ecosystem for Authoring Reactive Web Applications
Version: 0.8.0
Version: 0.9.0
Authors@R: c(person("Chris", "Parmer", role = c("aut"), email = "chris@plotly.com"), person("Ryan Patrick", "Kyle", role = c("aut", "cre"), comment = c(ORCID = "0000-0001-5829-9867"), email = "ryan@plotly.com"), person("Carson", "Sievert", role = c("aut"), comment = c(ORCID = "0000-0002-4958-2844")), person("Hammad", "Khan", role = c("aut"), comment = c(ORCID = "0000-0003-2479-9841"), email = "hammadkhan@plotly.com"), person(family = "Plotly Technologies", role = "cph"))
Description: A framework for building analytical web applications, Dash offers a pleasant and productive development experience. No JavaScript required.
Depends:
R (>= 3.0.2)
Imports:
dashHtmlComponents (== 1.0.3),
dashCoreComponents (== 1.10.2),
dashTable (== 4.9.0),
dashHtmlComponents (== 1.1.1),
dashCoreComponents (== 1.13.0),
dashTable (== 4.11.0),
R6,
fiery (> 1.0.0),
routr (> 0.2.0),
Expand All@@ -33,9 +33,9 @@ Collate:
'imports.R'
'print.R'
'internal.R'
Remotes: plotly/dash-html-components@e63acfa,
plotly/dash-core-components@0770afb,
plotly/dash-table@75ac3d9
Remotes: plotly/dash-html-components@7209e0a,
plotly/dash-core-components@91a424e,
plotly/dash-table@aa519b7
License: MIT + file LICENSE
Encoding: UTF-8
LazyData: true
Expand Down
24 changes: 12 additions & 12 deletions R/internal.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -36,9 +36,9 @@
all_files = FALSE),
class = "html_dependency"),
`dash-renderer-dev` = structure(list(name = "dash-renderer",
version = "1.8.2",
src = list(href = "https://unpkg.com/dash-renderer@1.8.2",
file = "lib/dash-renderer@1.8.2"),
version = "1.8.3",
src = list(href = "https://unpkg.com/dash-renderer@1.8.3",
file = "lib/dash-renderer@1.8.3"),
meta = NULL,
script = "dash-renderer/dash_renderer.dev.js",
stylesheet = NULL,
Expand All@@ -48,9 +48,9 @@
all_files = FALSE),
class = "html_dependency"),
`dash-renderer-map-dev` = structure(list(name = "dash-renderer",
version = "1.8.2",
src = list(href = "https://unpkg.com/dash-renderer@1.8.2",
file = "lib/dash-renderer@1.8.2"),
version = "1.8.3",
src = list(href = "https://unpkg.com/dash-renderer@1.8.3",
file = "lib/dash-renderer@1.8.3"),
meta = NULL,
script = "dash-renderer/dash_renderer.dev.js.map",
stylesheet = NULL,
Expand All@@ -60,9 +60,9 @@
all_files = FALSE),
class = "html_dependency"),
`dash-renderer-prod` = structure(list(name = "dash-renderer",
version = "1.8.2",
src = list(href = "https://unpkg.com/dash-renderer@1.8.2",
file = "lib/dash-renderer@1.8.2"),
version = "1.8.3",
src = list(href = "https://unpkg.com/dash-renderer@1.8.3",
file = "lib/dash-renderer@1.8.3"),
meta = NULL,
script = "dash-renderer/dash_renderer.min.js",
stylesheet = NULL,
Expand All@@ -72,9 +72,9 @@
all_files = FALSE),
class = "html_dependency"),
`dash-renderer-map-prod` = structure(list(name = "dash-renderer",
version = "1.8.2",
src = list(href = "https://unpkg.com/dash-renderer@1.8.2",
file = "lib/dash-renderer@1.8.2"),
version = "1.8.3",
src = list(href = "https://unpkg.com/dash-renderer@1.8.3",
file = "lib/dash-renderer@1.8.3"),
meta = NULL,
script = "dash-renderer/dash_renderer.min.js.map",
stylesheet = NULL,
Expand Down
14 changes: 9 additions & 5 deletions R/utils.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -1054,26 +1054,30 @@ setCallbackContext <- function(callback_elements) {
function(x) {
input_id <- splitIdProp(x)[1]
prop <- splitIdProp(x)[2]

# The following conditionals check whether the callback is a pattern-matching callback and if it has been triggered.
if (startsWith(input_id, "{")){
id_match <- vapply(callback_elements$inputs, function(x) {
x <- unlist(x)
any(x[grepl("id.", names(x))] %in% jsonlite::fromJSON(input_id)[[1]])
}, logical(1))[[1]]
} else {
id_match <- vapply(callback_elements$inputs, function(x) x$id %in% input_id, logical(1))
id_match <- vapply(callback_elements$inputs, function(x) {
unlist(x)
any(x$id %in% input_id)}, logical(1))
}

if (startsWith(input_id, "{")){
prop_match <- vapply(callback_elements$inputs, function(x) {
x <- unlist(x)
any(x[names(x) == "property"] %in% prop)
}, logical(1))[[1]]
} else {
prop_match <- vapply(callback_elements$inputs, function(x) x$property %in% prop, logical(1))
prop_match <- vapply(callback_elements$inputs, function(x) {
unlist(x)
any(x$property %in% prop)}, logical(1))
}

if (startsWith(input_id, "{")){
if (length(callback_elements$inputs) == 1 || !is.null(unlist(callback_elements$inputs, recursive = F)$value)) {
value <- sapply(callback_elements$inputs[id_match & prop_match], `[[`, "value")
Expand Down
127 changes: 127 additions & 0 deletions tests/integration/callbacks/test_pattern_matching.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -318,6 +318,120 @@
"""


graphs_app = """
library(dash)
library(dashHtmlComponents)
library(dashCoreComponents)
library(plotly)

df <- read.csv(
file = "https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv",
stringsAsFactor=FALSE,
check.names=FALSE
)

app <- Dash$new()

app$layout(
htmlDiv(
list(
htmlDiv(
list(
dccDropdown(options = lapply(unique(df[,"country"]), function(x) {
list(label = x, value = x)
}),
value = "Canada",
id = "country",
style = list(display = "inline-block",
width = 200)
),
htmlButton(
"add Chart",
id = "add-chart",
n_clicks = 0,
style = list(display = "inline-block")
)
)
),
htmlDiv(id = "container", children=list()),
htmlDiv(id = "output-delay")
)
)
)

create_figure <- function(df, column_x, column_y, country) {
df <- df[which(df[, "country"] == country),]
if (column_x == "year") {
fig <- plot_ly(df, x = df[,column_x], y = df[,column_y], name = column_x, type = "scatter", mode = "lines")
} else {
fig <- plot_ly(df, x = df[,column_x], y = df[,column_y], name = column_x, type = "scatter", mode = "markers")
}
fig <- plotly::layout(fig, plot_bgcolor="lightblue", xaxis = list(title=""),
yaxis = list(title=""), title=list(text=paste(country, column_y, "vs", column_x),
xanchor="right", margin_l=10, margin_r=0, margin_b=30))
return(fig)
}

app$callback(
output = list(
output(id = "container", property = "children"),
output(id = "output-delay", property = "children")
),
params = list(
input(id = "add-chart", property = "n_clicks"),
state(id = "country", property = "value"),
state(id = "container", property = "children")
),
function(n_clicks, country, children) {
default_column_x <- "year"
default_column_y <- "gdpPercap"

new_element <- htmlDiv(
style = list(width = "23%", display = "inline-block", outline = "thin lightgrey solid", padding = 10),
children = list(
dccGraph(
id = list(type = "dynamic-output", index = n_clicks),
style = list(height = 300),
figure = create_figure(df, default_column_x, default_column_y, country)
),
dccDropdown(
id = list(type = "dynamic-dropdown-x", index = n_clicks),
options = lapply(colnames(df), function(x) {
list(label = x, value = x)
}),
value = default_column_x
),
dccDropdown(
id = list(type = "dynamic-dropdown-y", index = n_clicks),
options = lapply(colnames(df), function(x) {
list(label = x, value = x)
}),
value = default_column_y
)
)
)

children <- c(children, list(new_element))
return(list(children, n_clicks))
}
)

app$callback(
output(id = list("index" = MATCH, "type" = "dynamic-output"), property = "figure"),
params = list(
input(id = list("index" = MATCH, "type" = "dynamic-dropdown-x"), property = "value"),
input(id = list("index" = MATCH, "type" = "dynamic-dropdown-y"), property = "value"),
input(id = "country", property = "value")
),
function(column_x, column_y, country) {
return(create_figure(df, column_x, column_y, country))
}
)

app$run_server()
"""


def test_rpmc001_pattern_matching_all(dashr):
dashr.start_server(all_app)
dashr.find_element("#add-filter").click()
Expand DownExpand Up@@ -370,3 +484,16 @@ def test_rpmc004_pattern_matching_todo(dashr):
dashr.find_element("#add").click()
dashr.find_element('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"done\\"\\}').click()
assert dashr.wait_for_text_to_equal("#totals", "1 of 1 items completed - 100%")


def test_rpmc005_pattern_matching_graphs(dashr):
dashr.start_server(graphs_app)
dashr.select_dcc_dropdown("#country", "Cameroon")
dashr.wait_for_text_to_equal("#output-delay", "0")
dashr.find_element("#add-chart").click()
dashr.wait_for_text_to_equal("#output-delay", "1")
dashr.find_element('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"dynamic-output\\"\\}')
dashr.select_dcc_dropdown('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"dynamic-dropdown-x\\"\\}', "year")
dashr.select_dcc_dropdown('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"dynamic-dropdown-y\\"\\}', "pop")
dashr.percy_snapshot("r-pmc-graphs")
dashr.wait_for_element('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"dynamic-output\\"\\}')
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
e5b0cfe
contribute test script
Aug 3, 2020
a242d49
remove version updating in DESCRIPTION
Aug 3, 2020
f1b81d6
fix EOL
rpkyle Aug 4, 2020
4d234cb
Merge pull request #222 from plotly/212-untangle-dashr-build
rpkyle Aug 4, 2020
4e4ccb1
Add support for user-defined server routes (#225)
rpkyle Aug 28, 2020
5bd1bbb
Provide support for script and stylesheet attributes (#226)
rpkyle Sep 4, 2020
3f862f9
Authenticate on pulls from Docker Hub (#231)
rpkyle Oct 6, 2020
3a3ee2f
Add support for callback graph improvements and timing (#224)
rpkyle Oct 9, 2020
766e3a8
Update CHANGELOG.md
rpkyle Oct 12, 2020
3b54773
189 - Add Pattern Matching Callbacks for Dash R (#228)
HammadTheOne Oct 21, 2020
03ed383
Fixing Null error with glue::glue interpolation (#233)
HammadTheOne Oct 21, 2020
5b31534
Update CHANGELOG.md
rpkyle Oct 26, 2020
2fdd157
Update dash-renderer to v1.8.2 (#234)
rpkyle Oct 26, 2020
bb9fc6a
bump package version to v0.8.0
Oct 26, 2020
314ced8
Update R/dash.R
rpkyle Oct 27, 2020
3f9f9f1
Update tests/testthat/test-wildcards.R
rpkyle Oct 27, 2020
e093463
Update DESCRIPTION
rpkyle Oct 27, 2020
6ee2702
Merge branch 'master' into dev
rpkyle Oct 27, 2020
b477fe0
add PMC example
Oct 27, 2020
6fffb44
update documentation
Oct 27, 2020
b4ca5f9
update CHANGELOG release date
Oct 27, 2020
24b491a
Merge branch 'dev' of github.com:plotly/dashR into dev
Oct 27, 2020
c120ab2
:hammer: PMC docs refactor
Oct 27, 2020
56d1dc0
Update tests/integration/callbacks/test_pattern_matching.py
rpkyle Oct 27, 2020
226f949
Update tests/integration/callbacks/test_pattern_matching.py
rpkyle Oct 27, 2020
fd5f3da
Update tests/integration/callbacks/test_pattern_matching.py
rpkyle Oct 28, 2020
c3a34b6
add import of glue
Oct 28, 2020
877f463
add glue to imports.R
Oct 28, 2020
b238a57
fix line length issue
Oct 28, 2020
ff858ac
Fix setCallbackContext for wildcard and ordinary inputs (#237)
HammadTheOne Oct 30, 2020
7a23405
Merge branch 'master' into dev
rpkyle Oct 31, 2020
aac1db5
bump dependency versions
Oct 31, 2020
b7b1cfa
update CHANGELOG
Oct 31, 2020
4326e08
update dash-renderer to v1.8.3
Oct 31, 2020
ed022c8
update CHANGELOG
Oct 31, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,6 +2,18 @@
All notable changes to `dash` will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).

## [0.9.0] - 2020-10-31

### Fixed
- Fixes a minor bug in `setCallbackContext` (described in [#236](https://github.com/plotly/dashR/issues/236)) which prevented pattern-matching callbacks from working properly if one or more `input` statements did not include a selector. [#237](https://github.com/plotly/dashR/pull/237)

### Changed

- Dash for R now depends on v1.1.1 of `dashHtmlComponents`
- Dash for R now depends on v1.13.0 of `dashCoreComponents`
- Dash for R now depends on v4.11.0 of `dashTable`
- `dash-renderer` version is now v1.8.3

## [0.8.0] - 2020-10-27
### Fixed
- Usage of `glue` has been corrected to address [#232](https://github.com/plotly/dashR/issues/232) via [#233](https://github.com/plotly/dashR/pull/233).
Expand Down
14 changes: 7 additions & 7 deletions DESCRIPTION
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
Package: dash
Title: An Interface to the Dash Ecosystem for Authoring Reactive Web Applications
Version: 0.8.0
Version: 0.9.0
Authors@R: c(person("Chris", "Parmer", role = c("aut"), email = "chris@plotly.com"), person("Ryan Patrick", "Kyle", role = c("aut", "cre"), comment = c(ORCID = "0000-0001-5829-9867"), email = "ryan@plotly.com"), person("Carson", "Sievert", role = c("aut"), comment = c(ORCID = "0000-0002-4958-2844")), person("Hammad", "Khan", role = c("aut"), comment = c(ORCID = "0000-0003-2479-9841"), email = "hammadkhan@plotly.com"), person(family = "Plotly Technologies", role = "cph"))
Description: A framework for building analytical web applications, Dash offers a pleasant and productive development experience. No JavaScript required.
Depends:
R (>= 3.0.2)
Imports:
dashHtmlComponents (== 1.0.3),
dashCoreComponents (== 1.10.2),
dashTable (== 4.9.0),
dashHtmlComponents (== 1.1.1),
dashCoreComponents (== 1.13.0),
dashTable (== 4.11.0),
R6,
fiery (> 1.0.0),
routr (> 0.2.0),
Expand All@@ -33,9 +33,9 @@ Collate:
'imports.R'
'print.R'
'internal.R'
Remotes: plotly/dash-html-components@e63acfa,
plotly/dash-core-components@0770afb,
plotly/dash-table@75ac3d9
Remotes: plotly/dash-html-components@7209e0a,
plotly/dash-core-components@91a424e,
plotly/dash-table@aa519b7
License: MIT + file LICENSE
Encoding: UTF-8
LazyData: true
Expand Down
24 changes: 12 additions & 12 deletions R/internal.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -36,9 +36,9 @@
all_files = FALSE),
class = "html_dependency"),
`dash-renderer-dev` = structure(list(name = "dash-renderer",
version = "1.8.2",
src = list(href = "https://unpkg.com/dash-renderer@1.8.2",
file = "lib/dash-renderer@1.8.2"),
version = "1.8.3",
src = list(href = "https://unpkg.com/dash-renderer@1.8.3",
file = "lib/dash-renderer@1.8.3"),
meta = NULL,
script = "dash-renderer/dash_renderer.dev.js",
stylesheet = NULL,
Expand All@@ -48,9 +48,9 @@
all_files = FALSE),
class = "html_dependency"),
`dash-renderer-map-dev` = structure(list(name = "dash-renderer",
version = "1.8.2",
src = list(href = "https://unpkg.com/dash-renderer@1.8.2",
file = "lib/dash-renderer@1.8.2"),
version = "1.8.3",
src = list(href = "https://unpkg.com/dash-renderer@1.8.3",
file = "lib/dash-renderer@1.8.3"),
meta = NULL,
script = "dash-renderer/dash_renderer.dev.js.map",
stylesheet = NULL,
Expand All@@ -60,9 +60,9 @@
all_files = FALSE),
class = "html_dependency"),
`dash-renderer-prod` = structure(list(name = "dash-renderer",
version = "1.8.2",
src = list(href = "https://unpkg.com/dash-renderer@1.8.2",
file = "lib/dash-renderer@1.8.2"),
version = "1.8.3",
src = list(href = "https://unpkg.com/dash-renderer@1.8.3",
file = "lib/dash-renderer@1.8.3"),
meta = NULL,
script = "dash-renderer/dash_renderer.min.js",
stylesheet = NULL,
Expand All@@ -72,9 +72,9 @@
all_files = FALSE),
class = "html_dependency"),
`dash-renderer-map-prod` = structure(list(name = "dash-renderer",
version = "1.8.2",
src = list(href = "https://unpkg.com/dash-renderer@1.8.2",
file = "lib/dash-renderer@1.8.2"),
version = "1.8.3",
src = list(href = "https://unpkg.com/dash-renderer@1.8.3",
file = "lib/dash-renderer@1.8.3"),
meta = NULL,
script = "dash-renderer/dash_renderer.min.js.map",
stylesheet = NULL,
Expand Down
14 changes: 9 additions & 5 deletions R/utils.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -1054,26 +1054,30 @@ setCallbackContext <- function(callback_elements) {
function(x) {
input_id <- splitIdProp(x)[1]
prop <- splitIdProp(x)[2]

# The following conditionals check whether the callback is a pattern-matching callback and if it has been triggered.
if (startsWith(input_id, "{")){
id_match <- vapply(callback_elements$inputs, function(x) {
x <- unlist(x)
any(x[grepl("id.", names(x))] %in% jsonlite::fromJSON(input_id)[[1]])
}, logical(1))[[1]]
} else {
id_match <- vapply(callback_elements$inputs, function(x) x$id %in% input_id, logical(1))
id_match <- vapply(callback_elements$inputs, function(x) {
unlist(x)
any(x$id %in% input_id)}, logical(1))
}

if (startsWith(input_id, "{")){
prop_match <- vapply(callback_elements$inputs, function(x) {
x <- unlist(x)
any(x[names(x) == "property"] %in% prop)
}, logical(1))[[1]]
} else {
prop_match <- vapply(callback_elements$inputs, function(x) x$property %in% prop, logical(1))
prop_match <- vapply(callback_elements$inputs, function(x) {
unlist(x)
any(x$property %in% prop)}, logical(1))
}

if (startsWith(input_id, "{")){
if (length(callback_elements$inputs) == 1 || !is.null(unlist(callback_elements$inputs, recursive = F)$value)) {
value <- sapply(callback_elements$inputs[id_match & prop_match], `[[`, "value")
Expand Down
127 changes: 127 additions & 0 deletions tests/integration/callbacks/test_pattern_matching.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -318,6 +318,120 @@
"""


graphs_app = """
library(dash)
library(dashHtmlComponents)
library(dashCoreComponents)
library(plotly)

df <- read.csv(
file = "https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv",
stringsAsFactor=FALSE,
check.names=FALSE
)

app <- Dash$new()

app$layout(
htmlDiv(
list(
htmlDiv(
list(
dccDropdown(options = lapply(unique(df[,"country"]), function(x) {
list(label = x, value = x)
}),
value = "Canada",
id = "country",
style = list(display = "inline-block",
width = 200)
),
htmlButton(
"add Chart",
id = "add-chart",
n_clicks = 0,
style = list(display = "inline-block")
)
)
),
htmlDiv(id = "container", children=list()),
htmlDiv(id = "output-delay")
)
)
)

create_figure <- function(df, column_x, column_y, country) {
df <- df[which(df[, "country"] == country),]
if (column_x == "year") {
fig <- plot_ly(df, x = df[,column_x], y = df[,column_y], name = column_x, type = "scatter", mode = "lines")
} else {
fig <- plot_ly(df, x = df[,column_x], y = df[,column_y], name = column_x, type = "scatter", mode = "markers")
}
fig <- plotly::layout(fig, plot_bgcolor="lightblue", xaxis = list(title=""),
yaxis = list(title=""), title=list(text=paste(country, column_y, "vs", column_x),
xanchor="right", margin_l=10, margin_r=0, margin_b=30))
return(fig)
}

app$callback(
output = list(
output(id = "container", property = "children"),
output(id = "output-delay", property = "children")
),
params = list(
input(id = "add-chart", property = "n_clicks"),
state(id = "country", property = "value"),
state(id = "container", property = "children")
),
function(n_clicks, country, children) {
default_column_x <- "year"
default_column_y <- "gdpPercap"

new_element <- htmlDiv(
style = list(width = "23%", display = "inline-block", outline = "thin lightgrey solid", padding = 10),
children = list(
dccGraph(
id = list(type = "dynamic-output", index = n_clicks),
style = list(height = 300),
figure = create_figure(df, default_column_x, default_column_y, country)
),
dccDropdown(
id = list(type = "dynamic-dropdown-x", index = n_clicks),
options = lapply(colnames(df), function(x) {
list(label = x, value = x)
}),
value = default_column_x
),
dccDropdown(
id = list(type = "dynamic-dropdown-y", index = n_clicks),
options = lapply(colnames(df), function(x) {
list(label = x, value = x)
}),
value = default_column_y
)
)
)

children <- c(children, list(new_element))
return(list(children, n_clicks))
}
)

app$callback(
output(id = list("index" = MATCH, "type" = "dynamic-output"), property = "figure"),
params = list(
input(id = list("index" = MATCH, "type" = "dynamic-dropdown-x"), property = "value"),
input(id = list("index" = MATCH, "type" = "dynamic-dropdown-y"), property = "value"),
input(id = "country", property = "value")
),
function(column_x, column_y, country) {
return(create_figure(df, column_x, column_y, country))
}
)

app$run_server()
"""


def test_rpmc001_pattern_matching_all(dashr):
dashr.start_server(all_app)
dashr.find_element("#add-filter").click()
Expand DownExpand Up@@ -370,3 +484,16 @@ def test_rpmc004_pattern_matching_todo(dashr):
dashr.find_element("#add").click()
dashr.find_element('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"done\\"\\}').click()
assert dashr.wait_for_text_to_equal("#totals", "1 of 1 items completed - 100%")


def test_rpmc005_pattern_matching_graphs(dashr):
dashr.start_server(graphs_app)
dashr.select_dcc_dropdown("#country", "Cameroon")
dashr.wait_for_text_to_equal("#output-delay", "0")
dashr.find_element("#add-chart").click()
dashr.wait_for_text_to_equal("#output-delay", "1")
dashr.find_element('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"dynamic-output\\"\\}')
dashr.select_dcc_dropdown('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"dynamic-dropdown-x\\"\\}', "year")
dashr.select_dcc_dropdown('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"dynamic-dropdown-y\\"\\}', "pop")
dashr.percy_snapshot("r-pmc-graphs")
dashr.wait_for_element('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"dynamic-output\\"\\}')
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
e5b0cfe
contribute test script
Aug 3, 2020
a242d49
remove version updating in DESCRIPTION
Aug 3, 2020
f1b81d6
fix EOL
rpkyle Aug 4, 2020
4d234cb
Merge pull request #222 from plotly/212-untangle-dashr-build
rpkyle Aug 4, 2020
4e4ccb1
Add support for user-defined server routes (#225)
rpkyle Aug 28, 2020
5bd1bbb
Provide support for script and stylesheet attributes (#226)
rpkyle Sep 4, 2020
3f862f9
Authenticate on pulls from Docker Hub (#231)
rpkyle Oct 6, 2020
3a3ee2f
Add support for callback graph improvements and timing (#224)
rpkyle Oct 9, 2020
766e3a8
Update CHANGELOG.md
rpkyle Oct 12, 2020
3b54773
189 - Add Pattern Matching Callbacks for Dash R (#228)
HammadTheOne Oct 21, 2020
03ed383
Fixing Null error with glue::glue interpolation (#233)
HammadTheOne Oct 21, 2020
5b31534
Update CHANGELOG.md
rpkyle Oct 26, 2020
2fdd157
Update dash-renderer to v1.8.2 (#234)
rpkyle Oct 26, 2020
bb9fc6a
bump package version to v0.8.0
Oct 26, 2020
314ced8
Update R/dash.R
rpkyle Oct 27, 2020
3f9f9f1
Update tests/testthat/test-wildcards.R
rpkyle Oct 27, 2020
e093463
Update DESCRIPTION
rpkyle Oct 27, 2020
6ee2702
Merge branch 'master' into dev
rpkyle Oct 27, 2020
b477fe0
add PMC example
Oct 27, 2020
6fffb44
update documentation
Oct 27, 2020
b4ca5f9
update CHANGELOG release date
Oct 27, 2020
24b491a
Merge branch 'dev' of github.com:plotly/dashR into dev
Oct 27, 2020
c120ab2
:hammer: PMC docs refactor
Oct 27, 2020
56d1dc0
Update tests/integration/callbacks/test_pattern_matching.py
rpkyle Oct 27, 2020
226f949
Update tests/integration/callbacks/test_pattern_matching.py
rpkyle Oct 27, 2020
fd5f3da
Update tests/integration/callbacks/test_pattern_matching.py
rpkyle Oct 28, 2020
c3a34b6
add import of glue
Oct 28, 2020
877f463
add glue to imports.R
Oct 28, 2020
b238a57
fix line length issue
Oct 28, 2020
ff858ac
Fix setCallbackContext for wildcard and ordinary inputs (#237)
HammadTheOne Oct 30, 2020
7a23405
Merge branch 'master' into dev
rpkyle Oct 31, 2020
aac1db5
bump dependency versions
Oct 31, 2020
b7b1cfa
update CHANGELOG
Oct 31, 2020
4326e08
update dash-renderer to v1.8.3
Oct 31, 2020
ed022c8
update CHANGELOG
Oct 31, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,6 +2,18 @@
All notable changes to `dash` will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).

## [0.9.0] - 2020-10-31

### Fixed
- Fixes a minor bug in `setCallbackContext` (described in [#236](https://github.com/plotly/dashR/issues/236)) which prevented pattern-matching callbacks from working properly if one or more `input` statements did not include a selector. [#237](https://github.com/plotly/dashR/pull/237)

### Changed

- Dash for R now depends on v1.1.1 of `dashHtmlComponents`
- Dash for R now depends on v1.13.0 of `dashCoreComponents`
- Dash for R now depends on v4.11.0 of `dashTable`
- `dash-renderer` version is now v1.8.3

## [0.8.0] - 2020-10-27
### Fixed
- Usage of `glue` has been corrected to address [#232](https://github.com/plotly/dashR/issues/232) via [#233](https://github.com/plotly/dashR/pull/233).
Expand Down
14 changes: 7 additions & 7 deletions DESCRIPTION
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
Package: dash
Title: An Interface to the Dash Ecosystem for Authoring Reactive Web Applications
Version: 0.8.0
Version: 0.9.0
Authors@R: c(person("Chris", "Parmer", role = c("aut"), email = "chris@plotly.com"), person("Ryan Patrick", "Kyle", role = c("aut", "cre"), comment = c(ORCID = "0000-0001-5829-9867"), email = "ryan@plotly.com"), person("Carson", "Sievert", role = c("aut"), comment = c(ORCID = "0000-0002-4958-2844")), person("Hammad", "Khan", role = c("aut"), comment = c(ORCID = "0000-0003-2479-9841"), email = "hammadkhan@plotly.com"), person(family = "Plotly Technologies", role = "cph"))
Description: A framework for building analytical web applications, Dash offers a pleasant and productive development experience. No JavaScript required.
Depends:
R (>= 3.0.2)
Imports:
dashHtmlComponents (== 1.0.3),
dashCoreComponents (== 1.10.2),
dashTable (== 4.9.0),
dashHtmlComponents (== 1.1.1),
dashCoreComponents (== 1.13.0),
dashTable (== 4.11.0),
R6,
fiery (> 1.0.0),
routr (> 0.2.0),
Expand All@@ -33,9 +33,9 @@ Collate:
'imports.R'
'print.R'
'internal.R'
Remotes: plotly/dash-html-components@e63acfa,
plotly/dash-core-components@0770afb,
plotly/dash-table@75ac3d9
Remotes: plotly/dash-html-components@7209e0a,
plotly/dash-core-components@91a424e,
plotly/dash-table@aa519b7
License: MIT + file LICENSE
Encoding: UTF-8
LazyData: true
Expand Down
24 changes: 12 additions & 12 deletions R/internal.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -36,9 +36,9 @@
all_files = FALSE),
class = "html_dependency"),
`dash-renderer-dev` = structure(list(name = "dash-renderer",
version = "1.8.2",
src = list(href = "https://unpkg.com/dash-renderer@1.8.2",
file = "lib/dash-renderer@1.8.2"),
version = "1.8.3",
src = list(href = "https://unpkg.com/dash-renderer@1.8.3",
file = "lib/dash-renderer@1.8.3"),
meta = NULL,
script = "dash-renderer/dash_renderer.dev.js",
stylesheet = NULL,
Expand All@@ -48,9 +48,9 @@
all_files = FALSE),
class = "html_dependency"),
`dash-renderer-map-dev` = structure(list(name = "dash-renderer",
version = "1.8.2",
src = list(href = "https://unpkg.com/dash-renderer@1.8.2",
file = "lib/dash-renderer@1.8.2"),
version = "1.8.3",
src = list(href = "https://unpkg.com/dash-renderer@1.8.3",
file = "lib/dash-renderer@1.8.3"),
meta = NULL,
script = "dash-renderer/dash_renderer.dev.js.map",
stylesheet = NULL,
Expand All@@ -60,9 +60,9 @@
all_files = FALSE),
class = "html_dependency"),
`dash-renderer-prod` = structure(list(name = "dash-renderer",
version = "1.8.2",
src = list(href = "https://unpkg.com/dash-renderer@1.8.2",
file = "lib/dash-renderer@1.8.2"),
version = "1.8.3",
src = list(href = "https://unpkg.com/dash-renderer@1.8.3",
file = "lib/dash-renderer@1.8.3"),
meta = NULL,
script = "dash-renderer/dash_renderer.min.js",
stylesheet = NULL,
Expand All@@ -72,9 +72,9 @@
all_files = FALSE),
class = "html_dependency"),
`dash-renderer-map-prod` = structure(list(name = "dash-renderer",
version = "1.8.2",
src = list(href = "https://unpkg.com/dash-renderer@1.8.2",
file = "lib/dash-renderer@1.8.2"),
version = "1.8.3",
src = list(href = "https://unpkg.com/dash-renderer@1.8.3",
file = "lib/dash-renderer@1.8.3"),
meta = NULL,
script = "dash-renderer/dash_renderer.min.js.map",
stylesheet = NULL,
Expand Down
14 changes: 9 additions & 5 deletions R/utils.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -1054,26 +1054,30 @@ setCallbackContext <- function(callback_elements) {
function(x) {
input_id <- splitIdProp(x)[1]
prop <- splitIdProp(x)[2]

# The following conditionals check whether the callback is a pattern-matching callback and if it has been triggered.
if (startsWith(input_id, "{")){
id_match <- vapply(callback_elements$inputs, function(x) {
x <- unlist(x)
any(x[grepl("id.", names(x))] %in% jsonlite::fromJSON(input_id)[[1]])
}, logical(1))[[1]]
} else {
id_match <- vapply(callback_elements$inputs, function(x) x$id %in% input_id, logical(1))
id_match <- vapply(callback_elements$inputs, function(x) {
unlist(x)
any(x$id %in% input_id)}, logical(1))
}

if (startsWith(input_id, "{")){
prop_match <- vapply(callback_elements$inputs, function(x) {
x <- unlist(x)
any(x[names(x) == "property"] %in% prop)
}, logical(1))[[1]]
} else {
prop_match <- vapply(callback_elements$inputs, function(x) x$property %in% prop, logical(1))
prop_match <- vapply(callback_elements$inputs, function(x) {
unlist(x)
any(x$property %in% prop)}, logical(1))
}

if (startsWith(input_id, "{")){
if (length(callback_elements$inputs) == 1 || !is.null(unlist(callback_elements$inputs, recursive = F)$value)) {
value <- sapply(callback_elements$inputs[id_match & prop_match], `[[`, "value")
Expand Down
127 changes: 127 additions & 0 deletions tests/integration/callbacks/test_pattern_matching.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -318,6 +318,120 @@
"""


graphs_app = """
library(dash)
library(dashHtmlComponents)
library(dashCoreComponents)
library(plotly)

df <- read.csv(
file = "https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv",
stringsAsFactor=FALSE,
check.names=FALSE
)

app <- Dash$new()

app$layout(
htmlDiv(
list(
htmlDiv(
list(
dccDropdown(options = lapply(unique(df[,"country"]), function(x) {
list(label = x, value = x)
}),
value = "Canada",
id = "country",
style = list(display = "inline-block",
width = 200)
),
htmlButton(
"add Chart",
id = "add-chart",
n_clicks = 0,
style = list(display = "inline-block")
)
)
),
htmlDiv(id = "container", children=list()),
htmlDiv(id = "output-delay")
)
)
)

create_figure <- function(df, column_x, column_y, country) {
df <- df[which(df[, "country"] == country),]
if (column_x == "year") {
fig <- plot_ly(df, x = df[,column_x], y = df[,column_y], name = column_x, type = "scatter", mode = "lines")
} else {
fig <- plot_ly(df, x = df[,column_x], y = df[,column_y], name = column_x, type = "scatter", mode = "markers")
}
fig <- plotly::layout(fig, plot_bgcolor="lightblue", xaxis = list(title=""),
yaxis = list(title=""), title=list(text=paste(country, column_y, "vs", column_x),
xanchor="right", margin_l=10, margin_r=0, margin_b=30))
return(fig)
}

app$callback(
output = list(
output(id = "container", property = "children"),
output(id = "output-delay", property = "children")
),
params = list(
input(id = "add-chart", property = "n_clicks"),
state(id = "country", property = "value"),
state(id = "container", property = "children")
),
function(n_clicks, country, children) {
default_column_x <- "year"
default_column_y <- "gdpPercap"

new_element <- htmlDiv(
style = list(width = "23%", display = "inline-block", outline = "thin lightgrey solid", padding = 10),
children = list(
dccGraph(
id = list(type = "dynamic-output", index = n_clicks),
style = list(height = 300),
figure = create_figure(df, default_column_x, default_column_y, country)
),
dccDropdown(
id = list(type = "dynamic-dropdown-x", index = n_clicks),
options = lapply(colnames(df), function(x) {
list(label = x, value = x)
}),
value = default_column_x
),
dccDropdown(
id = list(type = "dynamic-dropdown-y", index = n_clicks),
options = lapply(colnames(df), function(x) {
list(label = x, value = x)
}),
value = default_column_y
)
)
)

children <- c(children, list(new_element))
return(list(children, n_clicks))
}
)

app$callback(
output(id = list("index" = MATCH, "type" = "dynamic-output"), property = "figure"),
params = list(
input(id = list("index" = MATCH, "type" = "dynamic-dropdown-x"), property = "value"),
input(id = list("index" = MATCH, "type" = "dynamic-dropdown-y"), property = "value"),
input(id = "country", property = "value")
),
function(column_x, column_y, country) {
return(create_figure(df, column_x, column_y, country))
}
)

app$run_server()
"""


def test_rpmc001_pattern_matching_all(dashr):
dashr.start_server(all_app)
dashr.find_element("#add-filter").click()
Expand DownExpand Up@@ -370,3 +484,16 @@ def test_rpmc004_pattern_matching_todo(dashr):
dashr.find_element("#add").click()
dashr.find_element('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"done\\"\\}').click()
assert dashr.wait_for_text_to_equal("#totals", "1 of 1 items completed - 100%")


def test_rpmc005_pattern_matching_graphs(dashr):
dashr.start_server(graphs_app)
dashr.select_dcc_dropdown("#country", "Cameroon")
dashr.wait_for_text_to_equal("#output-delay", "0")
dashr.find_element("#add-chart").click()
dashr.wait_for_text_to_equal("#output-delay", "1")
dashr.find_element('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"dynamic-output\\"\\}')
dashr.select_dcc_dropdown('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"dynamic-dropdown-x\\"\\}', "year")
dashr.select_dcc_dropdown('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"dynamic-dropdown-y\\"\\}', "pop")
dashr.percy_snapshot("r-pmc-graphs")
dashr.wait_for_element('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"dynamic-output\\"\\}')
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
e5b0cfe
contribute test script
Aug 3, 2020
a242d49
remove version updating in DESCRIPTION
Aug 3, 2020
f1b81d6
fix EOL
rpkyle Aug 4, 2020
4d234cb
Merge pull request #222 from plotly/212-untangle-dashr-build
rpkyle Aug 4, 2020
4e4ccb1
Add support for user-defined server routes (#225)
rpkyle Aug 28, 2020
5bd1bbb
Provide support for script and stylesheet attributes (#226)
rpkyle Sep 4, 2020
3f862f9
Authenticate on pulls from Docker Hub (#231)
rpkyle Oct 6, 2020
3a3ee2f
Add support for callback graph improvements and timing (#224)
rpkyle Oct 9, 2020
766e3a8
Update CHANGELOG.md
rpkyle Oct 12, 2020
3b54773
189 - Add Pattern Matching Callbacks for Dash R (#228)
HammadTheOne Oct 21, 2020
03ed383
Fixing Null error with glue::glue interpolation (#233)
HammadTheOne Oct 21, 2020
5b31534
Update CHANGELOG.md
rpkyle Oct 26, 2020
2fdd157
Update dash-renderer to v1.8.2 (#234)
rpkyle Oct 26, 2020
bb9fc6a
bump package version to v0.8.0
Oct 26, 2020
314ced8
Update R/dash.R
rpkyle Oct 27, 2020
3f9f9f1
Update tests/testthat/test-wildcards.R
rpkyle Oct 27, 2020
e093463
Update DESCRIPTION
rpkyle Oct 27, 2020
6ee2702
Merge branch 'master' into dev
rpkyle Oct 27, 2020
b477fe0
add PMC example
Oct 27, 2020
6fffb44
update documentation
Oct 27, 2020
b4ca5f9
update CHANGELOG release date
Oct 27, 2020
24b491a
Merge branch 'dev' of github.com:plotly/dashR into dev
Oct 27, 2020
c120ab2
:hammer: PMC docs refactor
Oct 27, 2020
56d1dc0
Update tests/integration/callbacks/test_pattern_matching.py
rpkyle Oct 27, 2020
226f949
Update tests/integration/callbacks/test_pattern_matching.py
rpkyle Oct 27, 2020
fd5f3da
Update tests/integration/callbacks/test_pattern_matching.py
rpkyle Oct 28, 2020
c3a34b6
add import of glue
Oct 28, 2020
877f463
add glue to imports.R
Oct 28, 2020
b238a57
fix line length issue
Oct 28, 2020
ff858ac
Fix setCallbackContext for wildcard and ordinary inputs (#237)
HammadTheOne Oct 30, 2020
7a23405
Merge branch 'master' into dev
rpkyle Oct 31, 2020
aac1db5
bump dependency versions
Oct 31, 2020
b7b1cfa
update CHANGELOG
Oct 31, 2020
4326e08
update dash-renderer to v1.8.3
Oct 31, 2020
ed022c8
update CHANGELOG
Oct 31, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,6 +2,18 @@
All notable changes to `dash` will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).

## [0.9.0] - 2020-10-31

### Fixed
- Fixes a minor bug in `setCallbackContext` (described in [#236](https://github.com/plotly/dashR/issues/236)) which prevented pattern-matching callbacks from working properly if one or more `input` statements did not include a selector. [#237](https://github.com/plotly/dashR/pull/237)

### Changed

- Dash for R now depends on v1.1.1 of `dashHtmlComponents`
- Dash for R now depends on v1.13.0 of `dashCoreComponents`
- Dash for R now depends on v4.11.0 of `dashTable`
- `dash-renderer` version is now v1.8.3

## [0.8.0] - 2020-10-27
### Fixed
- Usage of `glue` has been corrected to address [#232](https://github.com/plotly/dashR/issues/232) via [#233](https://github.com/plotly/dashR/pull/233).
Expand Down
14 changes: 7 additions & 7 deletions DESCRIPTION
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
Package: dash
Title: An Interface to the Dash Ecosystem for Authoring Reactive Web Applications
Version: 0.8.0
Version: 0.9.0
Authors@R: c(person("Chris", "Parmer", role = c("aut"), email = "chris@plotly.com"), person("Ryan Patrick", "Kyle", role = c("aut", "cre"), comment = c(ORCID = "0000-0001-5829-9867"), email = "ryan@plotly.com"), person("Carson", "Sievert", role = c("aut"), comment = c(ORCID = "0000-0002-4958-2844")), person("Hammad", "Khan", role = c("aut"), comment = c(ORCID = "0000-0003-2479-9841"), email = "hammadkhan@plotly.com"), person(family = "Plotly Technologies", role = "cph"))
Description: A framework for building analytical web applications, Dash offers a pleasant and productive development experience. No JavaScript required.
Depends:
R (>= 3.0.2)
Imports:
dashHtmlComponents (== 1.0.3),
dashCoreComponents (== 1.10.2),
dashTable (== 4.9.0),
dashHtmlComponents (== 1.1.1),
dashCoreComponents (== 1.13.0),
dashTable (== 4.11.0),
R6,
fiery (> 1.0.0),
routr (> 0.2.0),
Expand All@@ -33,9 +33,9 @@ Collate:
'imports.R'
'print.R'
'internal.R'
Remotes: plotly/dash-html-components@e63acfa,
plotly/dash-core-components@0770afb,
plotly/dash-table@75ac3d9
Remotes: plotly/dash-html-components@7209e0a,
plotly/dash-core-components@91a424e,
plotly/dash-table@aa519b7
License: MIT + file LICENSE
Encoding: UTF-8
LazyData: true
Expand Down
24 changes: 12 additions & 12 deletions R/internal.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -36,9 +36,9 @@
all_files = FALSE),
class = "html_dependency"),
`dash-renderer-dev` = structure(list(name = "dash-renderer",
version = "1.8.2",
src = list(href = "https://unpkg.com/dash-renderer@1.8.2",
file = "lib/dash-renderer@1.8.2"),
version = "1.8.3",
src = list(href = "https://unpkg.com/dash-renderer@1.8.3",
file = "lib/dash-renderer@1.8.3"),
meta = NULL,
script = "dash-renderer/dash_renderer.dev.js",
stylesheet = NULL,
Expand All@@ -48,9 +48,9 @@
all_files = FALSE),
class = "html_dependency"),
`dash-renderer-map-dev` = structure(list(name = "dash-renderer",
version = "1.8.2",
src = list(href = "https://unpkg.com/dash-renderer@1.8.2",
file = "lib/dash-renderer@1.8.2"),
version = "1.8.3",
src = list(href = "https://unpkg.com/dash-renderer@1.8.3",
file = "lib/dash-renderer@1.8.3"),
meta = NULL,
script = "dash-renderer/dash_renderer.dev.js.map",
stylesheet = NULL,
Expand All@@ -60,9 +60,9 @@
all_files = FALSE),
class = "html_dependency"),
`dash-renderer-prod` = structure(list(name = "dash-renderer",
version = "1.8.2",
src = list(href = "https://unpkg.com/dash-renderer@1.8.2",
file = "lib/dash-renderer@1.8.2"),
version = "1.8.3",
src = list(href = "https://unpkg.com/dash-renderer@1.8.3",
file = "lib/dash-renderer@1.8.3"),
meta = NULL,
script = "dash-renderer/dash_renderer.min.js",
stylesheet = NULL,
Expand All@@ -72,9 +72,9 @@
all_files = FALSE),
class = "html_dependency"),
`dash-renderer-map-prod` = structure(list(name = "dash-renderer",
version = "1.8.2",
src = list(href = "https://unpkg.com/dash-renderer@1.8.2",
file = "lib/dash-renderer@1.8.2"),
version = "1.8.3",
src = list(href = "https://unpkg.com/dash-renderer@1.8.3",
file = "lib/dash-renderer@1.8.3"),
meta = NULL,
script = "dash-renderer/dash_renderer.min.js.map",
stylesheet = NULL,
Expand Down
14 changes: 9 additions & 5 deletions R/utils.R
Original file line numberDiff line numberDiff line change
Expand Up@@ -1054,26 +1054,30 @@ setCallbackContext <- function(callback_elements) {
function(x) {
input_id <- splitIdProp(x)[1]
prop <- splitIdProp(x)[2]

# The following conditionals check whether the callback is a pattern-matching callback and if it has been triggered.
if (startsWith(input_id, "{")){
id_match <- vapply(callback_elements$inputs, function(x) {
x <- unlist(x)
any(x[grepl("id.", names(x))] %in% jsonlite::fromJSON(input_id)[[1]])
}, logical(1))[[1]]
} else {
id_match <- vapply(callback_elements$inputs, function(x) x$id %in% input_id, logical(1))
id_match <- vapply(callback_elements$inputs, function(x) {
unlist(x)
any(x$id %in% input_id)}, logical(1))
}

if (startsWith(input_id, "{")){
prop_match <- vapply(callback_elements$inputs, function(x) {
x <- unlist(x)
any(x[names(x) == "property"] %in% prop)
}, logical(1))[[1]]
} else {
prop_match <- vapply(callback_elements$inputs, function(x) x$property %in% prop, logical(1))
prop_match <- vapply(callback_elements$inputs, function(x) {
unlist(x)
any(x$property %in% prop)}, logical(1))
}

if (startsWith(input_id, "{")){
if (length(callback_elements$inputs) == 1 || !is.null(unlist(callback_elements$inputs, recursive = F)$value)) {
value <- sapply(callback_elements$inputs[id_match & prop_match], `[[`, "value")
Expand Down
127 changes: 127 additions & 0 deletions tests/integration/callbacks/test_pattern_matching.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -318,6 +318,120 @@
"""


graphs_app = """
library(dash)
library(dashHtmlComponents)
library(dashCoreComponents)
library(plotly)

df <- read.csv(
file = "https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv",
stringsAsFactor=FALSE,
check.names=FALSE
)

app <- Dash$new()

app$layout(
htmlDiv(
list(
htmlDiv(
list(
dccDropdown(options = lapply(unique(df[,"country"]), function(x) {
list(label = x, value = x)
}),
value = "Canada",
id = "country",
style = list(display = "inline-block",
width = 200)
),
htmlButton(
"add Chart",
id = "add-chart",
n_clicks = 0,
style = list(display = "inline-block")
)
)
),
htmlDiv(id = "container", children=list()),
htmlDiv(id = "output-delay")
)
)
)

create_figure <- function(df, column_x, column_y, country) {
df <- df[which(df[, "country"] == country),]
if (column_x == "year") {
fig <- plot_ly(df, x = df[,column_x], y = df[,column_y], name = column_x, type = "scatter", mode = "lines")
} else {
fig <- plot_ly(df, x = df[,column_x], y = df[,column_y], name = column_x, type = "scatter", mode = "markers")
}
fig <- plotly::layout(fig, plot_bgcolor="lightblue", xaxis = list(title=""),
yaxis = list(title=""), title=list(text=paste(country, column_y, "vs", column_x),
xanchor="right", margin_l=10, margin_r=0, margin_b=30))
return(fig)
}

app$callback(
output = list(
output(id = "container", property = "children"),
output(id = "output-delay", property = "children")
),
params = list(
input(id = "add-chart", property = "n_clicks"),
state(id = "country", property = "value"),
state(id = "container", property = "children")
),
function(n_clicks, country, children) {
default_column_x <- "year"
default_column_y <- "gdpPercap"

new_element <- htmlDiv(
style = list(width = "23%", display = "inline-block", outline = "thin lightgrey solid", padding = 10),
children = list(
dccGraph(
id = list(type = "dynamic-output", index = n_clicks),
style = list(height = 300),
figure = create_figure(df, default_column_x, default_column_y, country)
),
dccDropdown(
id = list(type = "dynamic-dropdown-x", index = n_clicks),
options = lapply(colnames(df), function(x) {
list(label = x, value = x)
}),
value = default_column_x
),
dccDropdown(
id = list(type = "dynamic-dropdown-y", index = n_clicks),
options = lapply(colnames(df), function(x) {
list(label = x, value = x)
}),
value = default_column_y
)
)
)

children <- c(children, list(new_element))
return(list(children, n_clicks))
}
)

app$callback(
output(id = list("index" = MATCH, "type" = "dynamic-output"), property = "figure"),
params = list(
input(id = list("index" = MATCH, "type" = "dynamic-dropdown-x"), property = "value"),
input(id = list("index" = MATCH, "type" = "dynamic-dropdown-y"), property = "value"),
input(id = "country", property = "value")
),
function(column_x, column_y, country) {
return(create_figure(df, column_x, column_y, country))
}
)

app$run_server()
"""


def test_rpmc001_pattern_matching_all(dashr):
dashr.start_server(all_app)
dashr.find_element("#add-filter").click()
Expand DownExpand Up@@ -370,3 +484,16 @@ def test_rpmc004_pattern_matching_todo(dashr):
dashr.find_element("#add").click()
dashr.find_element('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"done\\"\\}').click()
assert dashr.wait_for_text_to_equal("#totals", "1 of 1 items completed - 100%")


def test_rpmc005_pattern_matching_graphs(dashr):
dashr.start_server(graphs_app)
dashr.select_dcc_dropdown("#country", "Cameroon")
dashr.wait_for_text_to_equal("#output-delay", "0")
dashr.find_element("#add-chart").click()
dashr.wait_for_text_to_equal("#output-delay", "1")
dashr.find_element('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"dynamic-output\\"\\}')
dashr.select_dcc_dropdown('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"dynamic-dropdown-x\\"\\}', "year")
dashr.select_dcc_dropdown('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"dynamic-dropdown-y\\"\\}', "pop")
dashr.percy_snapshot("r-pmc-graphs")
dashr.wait_for_element('#\\{\\"index\\"\\:1\\,\\"type\\"\\:\\"dynamic-output\\"\\}')