Skip to content

Commit c85485d

Browse files
committed
initial stab at crossfiltering with dbplot & spark
1 parent 38c03e4 commit c85485d

File tree

1 file changed

+96
-0
lines changed
  • inst/examples/shiny/crossfilter_dbplot

1 file changed

+96
-0
lines changed
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
library(shiny)
2+
library(plotly)
3+
library(dplyr)
4+
library(sparklyr)
5+
library(dbplot)
6+
sc <- spark_connect(master = "local", version = "2.1.0")
7+
spark_flights <- copy_to(sc, nycflights13::flights, "flights")
8+
9+
# Collect numeric variables to be shown as histograms in the crossfilter
10+
d <- select(
11+
spark_flights,
12+
arr_time,
13+
dep_time,
14+
arr_delay,
15+
dep_delay,
16+
air_time,
17+
distance
18+
)
19+
20+
# Generate an output container per variable
21+
ui <- fluidPage(
22+
lapply(colnames(d), function(nm) plotlyOutput(nm, height = 200, width = "49%", inline = TRUE))
23+
)
24+
25+
server <- function(input, output, session) {
26+
27+
# These reactive values track the set of active brushes
28+
# Each reactive value corresponds to a different variable
29+
brush_ranges <- reactiveValues()
30+
31+
# Filter the dataset based on every active brush range except for one (var)
32+
# TODO: instead of filtering the entire dataset,
33+
# consider filtering a pre-binned dataset based on pixel resolution
34+
# (perhaps using dbplot::bin_plot)
35+
d_filter <- function(d, var = "arr_time") {
36+
for (nm in setdiff(names(d), var)) {
37+
rng <- brush_ranges[[nm]]
38+
if (is.null(rng)) next
39+
d <- filter(d, between(d[[nm]], min(rng), max(rng)))
40+
}
41+
d
42+
}
43+
44+
# Implement same render logic for each variable
45+
lapply(colnames(d), function(nm) {
46+
47+
sym <- as.symbol(nm)
48+
counts_full <- db_compute_bins(spark_flights, !!sym)
49+
50+
output[[nm]] <- renderPlotly({
51+
52+
plot_ly(source = nm) %>%
53+
add_bars(x = counts_full[[nm]], y = ~counts_full$count) %>%
54+
layout(
55+
dragmode = "select",
56+
selectdirection = "h",
57+
xaxis = list(
58+
title = nm,
59+
range = range(counts_full[[nm]], na.rm = TRUE)
60+
),
61+
yaxis = list(title = "")
62+
)
63+
})
64+
65+
observeEvent(event_data("plotly_brushing", source = nm), ignoreNULL = FALSE, {
66+
67+
# inform the world about the new brush range
68+
brush_ranges[[nm]] <- event_data("plotly_brushing", source = nm)$x
69+
70+
if (all(sapply(brush_ranges, function(x) length(x) == 0))) return()
71+
72+
# update the bar heights of every view (except for the one being brushed)
73+
for (var in setdiff(names(d), nm)) {
74+
# views respect every brush except for their own
75+
d_filtered <- d_filter(d, var)
76+
77+
# bin the filtered data based on the global binning definition
78+
sym <- as.symbol(nm)
79+
counts_filter <- db_compute_bins(
80+
d_filtered, !!sym,
81+
binwidth = diff(counts_full[[nm]][1:2])
82+
)
83+
84+
print(counts_filter)
85+
# finally, update the bar heights
86+
plotlyProxy(var, session) %>%
87+
plotlyProxyInvoke("restyle", "y", list(counts_filter$count), 0)
88+
}
89+
})
90+
91+
})
92+
93+
}
94+
95+
shinyApp(ui, server)
96+

0 commit comments

Comments
 (0)