Happy Easter!
I wonder if there is any smart programming for looping value boxes (or even better: whole r-markdown-code) in R-flexdashboards using R-shiny.
My problem is:
I have data, which is updated every day.
Every day I can display several keyfigueres.
I do this with value-boxes, becaus it is very easy to add special colors for different treshholds.
I want to show the data of the last week (7-days), see image, widch show the data for 4 days:
Is there a possibility to loop my code day by day?
My executable code example is only for two days an the valuebox for date (1st column in the image):
---
title: "Test for Loop value boxes"
author: StatistiVolker
output:
flexdashboard::flex_dashboard:
orientation: rows
vertical_layout: fill
runtime: shiny
---
```{r setup, include=FALSE}
require(shiny)
require(flexdashboard)
require(tidyverse)
```
<!-- C19J_Summary.Rmd -->
Testcode
=======================================================================
Sidebar {.sidebar}
-----------------------------------------------------------------------
### Settings
```{r}
sliderInput("sliderSumDate",
"Datum",
min = as.Date("2020-03-01"), #min(C19JKInz()$datI),
max = Sys.Date()-1,
value = Sys.Date()-1,
animate = TRUE)
```
```{r}
# Date
selSumDate <- reactive({
input$sliderSumDate
})
```
<!-- Is it possible to loop this Code? -->
Row
-----------------------------------------------------------------------
<!-- actual day -->
### {.value-box}
```{r}
# Emit the download count
renderValueBox({
valueBox(format(as.Date(selSumDate()-0),"%d.%m.%Y (%a)"),
caption = "Datum",
# icon = "fa-calendar",
color = "cornflowerblue")
})
```
<!-- Next Code is almost the same as above, except one day earlier -->
<!-- Is it possible to loop this Code? -->
Row
-----------------------------------------------------------------------
<!-- day before -->
### {.value-box}
```{r}
# Emit the download count
renderValueBox({
valueBox(format(as.Date(selSumDate()-1),"%d.%m.%Y (%a)"),
caption = "Datum",
# icon = "fa-calendar",
color = "cornflowerblue")
})
```
Thank you for any idea to solve my problem.
PS: This was not useful, because it is not possible to control the colors for different treshholds
you have found an Easter egg:
---
title: "Test for Loop value boxes"
author: StatistiVolker
output:
flexdashboard::flex_dashboard:
orientation: rows
vertical_layout: fill
runtime: shiny
---
```{r setup, include=FALSE}
require(shiny)
require(flexdashboard)
require(tidyverse)
```
<!-- C19J_Summary.Rmd -->
# Sidebar {.sidebar data-width=350}
### Settings
```{r}
sliderInput("sliderSumDate",
"Datum",
min = as.Date("2020-03-01"), #min(C19JKInz()$datI),
max = Sys.Date()-1,
value = Sys.Date()-1,
animate = TRUE)
```
```{r}
# Date
selSumDate <- reactive({
input$sliderSumDate
})
```
<!-- Is it possible to loop this Code? -->
```{r}
myValueBox <- function(title, caption="", color="cornflowerblue", myicon="", fontsize="25px"){
div(
class = "value-box level3",
style = glue::glue(
'
background-color: #{color}#;
height: 106px;
width: 18%;
display: inline-block;
overflow: hidden;
word-break: keep-all;
text-overflow: ellipsis;
', .open = '#{', .close = '}#'
),
div(
class = "inner",
p(class = "value", title, style = glue::glue("font-size:{fontsize}")),
p(class = "caption", caption)
),
div(class = "icon", myicon)
)
}
```
Testcode
=======================================================================
<!-- actual day -->
```{r}
uiOutput("el")
```
```{r}
# Emit the download count
colors = c("#8b0000", "#000000", "#228b22", "#ffd700")
output$el <- renderUI({
lapply(0:-6, function(x) {
div(
myValueBox(format(as.Date(selSumDate()-x),"%d.%m.%Y (%a)"), "Datum", myicon = icon("calendar")),
myValueBox(sample(1000, 1), "Infizierte", color = sample(colors, 1)),
myValueBox(sample(1000, 1), "Aktiv erkrankt", color = sample(colors, 1)),
myValueBox(sample(1000, 1), "Genesene", color = sample(colors, 1)),
myValueBox(sample(1000, 1), "Verstorbene", color = sample(colors, 1))
)
})
})
```
Impossible to create what you want with original {flexdashboard} package, no way to control row/column layout automatically. However, we can create our own value box.
Works the best on bigger screens (> 1000px width), also works on mobile (<670px), different styles will apply on small screens. Medium screens (670-1000) may have some problems, try to change width: 18%; to a number you want.
overflow text due to screen size issues are trimmed off. Change the
fontsize argument may also help.
Bigger screen
Mobile
Related
I wrote a loop that made 10 graphs in R:
library(plotly)
for (i in 1:10)
{
d_i = data.frame(x = rnorm(100,100,100), y = rnorm(100,100,100))
title_i = paste0("title_",i)
p_i = plot_ly(data = d_i, x = ~x, y = ~y) %>% layout(title = title_i)
htmlwidgets::saveWidget(as_widget(p_i), paste0("plot_",i, ".html"))
}
I have this code (Input menu contents do not overflow row box in flexdashboard) that makes a dashboard in R:
---
title: "Test Dashboard"
output:
flexdashboard::flex_dashboard:
orientation: rows
vertical_layout: fill
runtime: shiny
---
```{r setup, include=FALSE}
library(flexdashboard)
library(shiny)
```
Column {data-width=100}
-----------------------------------------------------------------------
### Window 1
```{r}
selectInput("project", label = NULL, choices = c("A","B","C","D"))
```
Column {data-width=400}
-----------------------------------------------------------------------
### Chart B
```{r}
renderPlot({
plot(rnorm(1000), type = "l", main = paste("Project:",input$project, " Data:", input$data))
})
```
I would like to adapt this code so that the drop down menu allows the user to load the previously created graph/html file (e.g. from "My Documents") that is being searched for. For example, if the user searches for "plot_7", then plot_7 is displayed.
I tried the following code:
---
title: "Test Dashboard"
output:
flexdashboard::flex_dashboard:
orientation: rows
vertical_layout: fill
runtime: shiny
---
```{r setup, include=FALSE}
library(flexdashboard)
library(shiny)
```
Column {data-width=100}
-----------------------------------------------------------------------
### Window 1
```{r}
plots = rep("plot", 10)
i = seq(1:100)
choice = paste0(plots, "_",i)
selectInput("project", label = NULL, choices = choice)
```
Column {data-width=400}
-----------------------------------------------------------------------
### Chart B
```{r}
renderPlot({
<object class="one" type="text/html" data="plot_i.html"></object>
})
```
But this returns the following error:
Error: <text<:2:1 unexpected '<'
1: renderPlot({
2:<
^
Can someone please show me how I can fix this? And is it possible to do this WITHOUT shiny? (i.e. only in flexdashboard)
Thank you!
This answers your next question:
Just a question: In the first answer you provided, you were able to "type in" which plot you wanted to see. In the second answer, you can only "scroll". Is there a way to add the "type in" which plot you want to see for the second answer?
Short answer: yes
... and how to do that?
I actually tried to use selectize.js in an ironic full circle of sorts, but it didn't work out...violence was considered...but it's an inanimate object...so...ya, I lost by default
This uses the JS library/package (whatever they call it for that language) select2.
flexdashboard is SUPER FUN! It really didn't want me to add this library with JS (that would have been too easy, ya know? So this puppy had to get added to the YAML.
The YAML to make this work.
---
title: "Test Dashboard"
output:
flexdashboard::flex_dashboard:
orientation: rows
vertical_layout: fill
extra_dependencies: !expr list(htmltools::htmlDependency('select2.min.js', '1.0', src = list(href = 'https://cdn.jsdelivr.net/npm/select2#4.1.0-rc.0/dist'), script='js/select2.min.js', all_files = FALSE, style = 'css/select2.min.css'))
---
By default, it will look like this.
I figured your very next question would be about appearance... so I jumped the gun.
As far as I understand it, (I'm new to select2), when widening the search box, you have to move the dropdown arrow, which accounts for the first 3 of the entries in this CSS.
The next two are for highlighting when you mouse over in the dropdown. By default, the previous selection is highlighted grey, and the currently hovered-over is highlighted light blue. I added these so that you could change the colors if you wanted to.
The final call in CSS is setting the font family. I chose the default family in Plotly (so they matched).
```{css}
.select2-container--default .select2-selection--single{
min-height: 40px;
padding: 6px 6px;
width: 175px;
position: relative;
}
.select2-container--default .select2-selection--single .select2-selection__arrow {
right: 0px;
width: 20px;
min-height: 34px; /* parent min-height, minus top padding 40 - 6 */
position: absolute;
}
.select2-dropdown { /* the chunk requires 'important' */
width: 175px !important; /* so they're the same width */
top: 50%;
padding: 6px; 12px;
}
.select2-container--default .select2-results__option--highlighted[aria-selected] {
background-color: #F5F0E3;
color: black; /* in dropdown, item hovered on bg and text */
} /* default is background-color: #5897fb; default blue */
.select2-container--default .select2-results__option--selected {
background-color: #fbfaf5;
color: black; /* in dropdown, PREVIOUS selection bg and text */
} /* default background-color: #ddd; yucky grey */
option {
font-family: verdana; /* to match plotly */
}
```
Creating the plot list, the dropdown, and rendering the plots in R code didn't change.
The JS didn't change that much.
/* doesn't catch that the first plot is default; set manually */
setTimeout(function(){
$('select').select2(); /* connect to the select2 library */
plt = document.querySelectorAll('div.plotly.html-widget');
for(i = 0; i < plt.length; i++) {
if(i === 0) {
plt[i].style.display = 'block';
} else {
plt[i].style.display = 'none';
}
}
}, 200) /* run once; allow for loading*/
/* goes with the dropdown; this shows/hides plots based on dropdown */
function getPlot(opt) {
plt = document.querySelectorAll('div.plotly.html-widget');
for(i = 0; i < plt.length; i++) { /* switched to plt from opt here */
opti = opt.options[i];
if(opti.selected) {
plt[i].style.display = 'block';
} else {
plt[i].style.display = 'none'
}
}
}
That all gives you this.
All the code altogether.
---
title: "Test Dashboard"
output:
flexdashboard::flex_dashboard:
orientation: rows
vertical_layout: fill
extra_dependencies: !expr list(htmltools::htmlDependency('select2.min.js', '1.0', src = list(href = 'https://cdn.jsdelivr.net/npm/select2#4.1.0-rc.0/dist'), script='js/select2.min.js', all_files = FALSE, style = 'css/select2.min.css'))
---
```{r setup, include=FALSE}
library(flexdashboard)
library(plotly)
library(tidyverse)
library(htmltools)
library(shinyRPG) # devtools::install_github("RinteRface/shinyRPG")
plts <- vector(mode = "list") # store plot list
for (i in 1:10) {
d_i = data.frame(x = rnorm(100,100,100), y = rnorm(100,100,100))
title_i = paste0("title_",i)
plts[[i]] <- plot_ly( # make a list of objects; no .html
data = d_i, x = ~x, y = ~y, height = 400,
mode = "markers", type = "scatter") %>%
layout(title = title_i)
}
```
```{css}
.select2-container--default .select2-selection--single{ /* outer container of dropdown */
min-height: 40px;
padding: 6px 6px;
width: 175px;
position: relative;
}
.select2-container--default .select2-selection--single .select2-selection__arrow {
right: 0px;
width: 20px;
min-height: 34px; /* parent min-height, minus top padding 40 - 6 */
position: absolute;
}
.select2-dropdown { /* the chunk requires 'important' */
width: 175px !important; /* so they're the same width */
top: 50%;
padding: 6px; 12px;
}
.select2-container--default .select2-results__option--highlighted[aria-selected] {
background-color: #F5F0E3;
color: black; /* in dropdown, item hovered on bg and text */
} /* default is background-color: #5897fb; default blue */
.select2-container--default .select2-results__option--selected {
background-color: #fbfaf5;
color: black; /* in dropdown, PREVIOUS selection bg and text */
} /* default background-color: #ddd; yucky grey */
option {
font-family: verdana; /* to match plotly */
}
```
Column {data-width=100}
-----------------------------------------------------------------------
### Window 1 {data-height=500}
```{r makeGoodChoices}
opts <- choice <- paste0("plot_", 1:100) # this line replaces last 3 lines
namedChoices = setNames(opts, choice)
newInput <- rpgSelect( # <----- I'm new; the dropdown
"selectBox",
NULL,
namedChoices,
multiple = F)
newInput$children[[2]]$attribs$onchange <- "getPlot(this)"
newInput # add dropdown to webpage
```
<!--- make space between dropdown and plot --->
<div id="plots" style="margin-top:3rem; margin-bottom:3rem;">
```{r dynoPlots,results='asis'}
tagList(plts) # print every plot (so they're all in the HTML)
```
</div>
```{r giveItUp,results='asis',engine='js'}
/* doesn't catch that the first plot is default, set manually */
setTimeout(function(){
$('select').select2(); /* connect to the select2 library */
plt = document.querySelectorAll('div.plotly.html-widget');
for(i = 0; i < plt.length; i++) {
if(i === 0) {
plt[i].style.display = 'block';
} else {
plt[i].style.display = 'none';
}
}
}, 200) /* run once; allow for loading*/
/* goes with the dropdown; this shows/hides plots based on dropdown */
function getPlot(opt) {
plt = document.querySelectorAll('div.plotly.html-widget');
for(i = 0; i < plt.length; i++) { /* switched to plt from opt here */
opti = opt.options[i];
if(opti.selected) {
plt[i].style.display = 'block';
} else {
plt[i].style.display = 'none'
}
}
}
```
This isn't exactly what you're looking for. This doesn't import the file. I'm still going to try to figure that part out.
I'm still trying to make the external file call work. Right now, it just wasn't to give me the literal HTML. I've tried a few approaches. I'm sure it's being a pain because this is probably not a good way to do this. For example, each plot will bring in the full HTML, which means that if there were 100 plots, you've got the entire plotly.js 100 times. (Whoa!)
If you're set on using external files and planning on rendering them in RMD, especially when using Shiny, you may want to consider an approach that keeps them R objects, like Rda or RData. That will use a LOT less memory.
In this version, I've only created the plots as objects (not saved, external files).
This is modified from your question. It creates an object for each for iteration.
---
title: "Test Dashboard"
output:
flexdashboard::flex_dashboard:
orientation: rows
vertical_layout: fill
runtime: shiny
---
```{r setup, include=FALSE}
library(flexdashboard)
library(shiny)
library(plotly)
library(tidyverse)
library(htmltools)
for (i in 1:10) {
d_i = data.frame(x = rnorm(100,100,100), y = rnorm(100,100,100))
title_i = paste0("title_",i)
# p_i = plot_ly(data = d_i, x = ~x, y = ~y) %>% layout(title = title_i)
assign(paste0("plot_", i, ".html"), # name them plot_1.html, plot_2.html and so on
plot_ly(data = d_i, x = ~x, y = ~y, height = 400) %>%
layout(title = title_i))
# not using right now!
# htmlwidgets::saveWidget(as_widget(p_i), paste0("plot_",i, ".html"))
}
# htmlwidgets::saveWidget(as_widget(plot_1.html), "plot_1.html") # created for testing
```
I've modified your called to selectInput, as well. I made this a named vector, so that you would have plot_1.html called when the user picked plot_1.
I've kept your code in there, so you can see what's changed.
```{r makeGoodChoices}
# plots = rep("plot", 10)
# i = seq(1:100)
# choice = paste0(plots, "_",i)
choice = paste0("plot_", 1:100) # this line replaces last 3 lines
opts <- paste0(choice, ".html")
namedChoices = setNames(opts, choice)
# selectInput("project", label = NULL, choices = choice) # originally
selectInput("project", label = NULL, choices = namedChoices)
```
Since this is an R object (not an external file), this is how you would call the plots from the dropdown.
```{r dynoPlots}
renderPlotly(get(input$project)) # show me!
```
The RMarkdown altogether
---
title: "Test Dashboard"
output:
flexdashboard::flex_dashboard:
orientation: rows
vertical_layout: fill
runtime: shiny
---
```{r setup, include=FALSE}
library(flexdashboard)
library(shiny)
library(plotly)
library(tidyverse)
library(htmltools)
for (i in 1:10) {
d_i = data.frame(x = rnorm(100,100,100), y = rnorm(100,100,100))
title_i = paste0("title_",i)
# p_i = plot_ly(data = d_i, x = ~x, y = ~y) %>% layout(title = title_i)
assign(paste0("plot_", i, ".html"), # name them plot_1.html, plot_2.html and so on
plot_ly(data = d_i, x = ~x, y = ~y, height = 400) %>%
layout(title = title_i))
# not using right now!
# htmlwidgets::saveWidget(as_widget(p_i), paste0("plot_",i, ".html"))
}
# htmlwidgets::saveWidget(as_widget(plot_1.html), "plot_1.html") # created for testing
```
Column {data-width=100}
-----------------------------------------------------------------------
### Window 1 {data-height=500}
```{r makeGoodChoices}
# plots = rep("plot", 10)
# i = seq(1:100)
# choice = paste0(plots, "_",i)
choice = paste0("plot_", 1:100) # this line replaces last 3 lines
opts <- paste0(choice, ".html")
namedChoices = setNames(opts, choice)
# selectInput("project", label = NULL, choices = choice) # originally
selectInput("project", label = NULL, choices = namedChoices)
```
```{r dynoPlots}
renderPlotly(get(input$project)) # show me!
```
I decided to make this an entirely different answer because it really is a different question.
This is based on the assumption that you won't import external files. This does not use Shiny runtime, but does the same thing as above.
BTW, I didn't check if selectInput would work, I went with shinyRPG because I knew it would work.
Here's a summary of changes from the answer to your original question:
dropped shiny: runtime from YAML
dropped library(shiny)
added library(shinyRPG)
dropped plot names (they're in a list now)
added list to store plots; sent plots to list when created
dropped .html from dropdown option names (they can be anything you want now)
rpgSelect replaced selectInput
added JS to connect plots to the dropdown
Here's what the bare bones looks like (almost exactly the same)
All of the code to make this happen with notes in the code for explanation. If anything is unclear, let me know.
---
title: "Test Dashboard"
output:
flexdashboard::flex_dashboard:
orientation: rows
vertical_layout: fill
---
```{r setup, include=FALSE}
library(flexdashboard)
library(plotly)
library(tidyverse)
library(htmltools)
library(shinyRPG) # devtools::install_github("RinteRface/shinyRPG")
plts <- vector(mode = "list") # stores plots
for (i in 1:10) {
d_i = data.frame(x = rnorm(100,100,100), y = rnorm(100,100,100))
title_i = paste0("title_",i)
plts[[i]] <- plot_ly( # make a list of objects
data = d_i, x = ~x, y = ~y, height = 400,
mode = "markers", type = "scatter") %>%
layout(title = title_i)
}
```
Column {data-width=100}
-----------------------------------------------------------------------
### Window 1 {data-height=500}
```{r makeGoodChoices}
opts <- choice <- paste0("plot_", 1:100) # this line replaces last 3 lines
namedChoices = setNames(opts, choice)
newInput <- rpgSelect( # <----- I'm new; the drop down (used same args)
"selectBox",
NULL,
namedChoices,
multiple = F)
newInput$children[[2]]$attribs$onchange <- "getPlot(this)"
newInput # add dropdown to webpage
```
<!--- make space between dropdown and plot --->
<div id="plots" style="margin-top:3rem; margin-bottom:3rem;">
```{r dynoPlots,results='asis'}
tagList(plts) # print every plot (so they're all in the HTML)
```
</div>
```{r giveItUp,results='asis',engine='js'}
/* doesn't catch that the first plot is default, set manually */
setTimeout(function(){
plt = document.querySelectorAll('div.plotly.html-widget');
for(i = 0; i < plt.length; i++) {
if(i === 0) {
plt[i].style.display = 'block';
} else {
plt[i].style.display = 'none';
}
}
}, 200) /* run once; allow for loading*/
/* goes with the drop down; this shows/hides plots based on drop down */
function getPlot(opt) {
plt = document.querySelectorAll('div.plotly.html-widget');
for(i = 0; i < opt.length; i++) {
opti = opt.options[i];
if(opti.selected) {
plt[i].style.display = 'block';
} else {
plt[i].style.display = 'none'
}
}
}
```
I use the excelent crosstalk r package to make filters for my reactable htmlwidget. I show the reactable in flexdashboard. When using the groupBy feature of reactable, I noticed that there was no scroll bar when I make the table larger than the area where it has been put in.
Here is an example Tha helps making the issue clear:
---
title: "Focal Chart (Top)"
output:
flexdashboard::flex_dashboard:
orientation: rows
---
Row {data-height=500}
-------------------------------------
### Chart 1
```{r}
library(crosstalk)
library(reactable)
```
Row {data-height=500}
-------------------------------------
### With crosstalk filtering
```{r}
cars <- MASS::Cars93[1:20, c("Manufacturer", "Model", "Type", "Price")]
data <- SharedData$new(cars)
bscols(
widths = c(3, 9),
list(
filter_checkbox("type", "Type", data, ~Type),
filter_slider("price", "Price", data, ~Price, width = "100%"),
filter_select("mfr", "Manufacturer", data, ~Manufacturer)
),
reactable(data,groupBy = "Manufacturer")
)
```
### Without crosstalk
```{r}
reactable(data,groupBy = "Manufacturer")
```
Two tables are shown. When decollapsing e.g. Chevrolet in both tables, in the right one (the one without crosstalk filtering) a scroll bar will appear. In the left however, no scroll bar appears.
How can I make my crosstalk/reactable scrollable? Is this issue solvable? Many thanks in advance!
I don't think this is a complete answer but it might get you closer. I exaggerated the minWidth so you could see the effect.
sticky_style <- list(position = "sticky", left = 0, background = "#fff", zIndex = 1,
borderRight = "1px solid #eee")
crosstalk::bscols(
widths = c(3, 9),
list(
filter_checkbox("type", "Type", data, ~Type),
filter_slider("price", "Price", data, ~Price, width = "100%"),
filter_select("mfr", "Manufacturer", data, ~Manufacturer)
),
reactable(data,columns = list(
Manufacturer = colDef(
style = sticky_style,
headerStyle = sticky_style
)
), defaultColDef = colDef(minWidth = 300))
)
By the way, #DanielJachetta, I had the same problem so updated both crosstalk and reactable packages and the problem went away. Good luck.
I am quit new to R and trying to develop an dashboard with Flexdashboard based on this example:
https://matt-dray.github.io/earl18-crosstalk/04_leaflet-flexdash-dt-crosstalk.html
I get it to work, but what I am trying to accomplish is that I don't want all my points to show on at the start.
When a user selects a filter I want to add a marker to the map and zoom to this point. I am not using the datatables element
The code I have so far
---
title: "Leaflet + Flexdashboard + DT + Crosstalk"
author: "Matt Dray"
output:
flexdashboard::flex_dashboard:
theme: paper
favicon: img/ios7-location-outline.png
source_code: embed
---
```{r setup, include=FALSE}
# prep workspace
library(dplyr) # tidy data manipulation
library(leaflet) # interative mapping
library(DT) # interactive tables
library(crosstalk) # inter-widget interactivity
library(varhandle) # change column type
sch <- readRDS("data/gias_sample.RDS")
#sch <- readRDS("data/grafinformatie.rds")
#sch <- as.data.frame(sch)
#sch <- unfactor(sch) # change column type
sd <- SharedData$new(sch)
```
Interactives {data-icon="ion-stats-bars"}
=====================================
Column {data-width=400}
-------------------------------------
### Filters
```{r filters}
filter_select(
id = "geo_la",
label = "NAME",
sharedData = sd,
group = ~geo_la
)
```
Column {data-width=600}
-------------------------------------
### Interactive map
```{r map}
sd %>%
leaflet::leaflet() %>%
leaflet::addProviderTiles(providers$OpenStreetMap)
# leaflet::addAwesomeMarkers(
# icon = awesomeIcons(
# library = "ion",
# iconColor = "white"
# )
# ) %>% # end addAwesomeMarkers()
#leaflet::addMeasure()
```
$(document).ready(function () {
FlexDashboard.init({
theme: "paper",
fillPage: true,
orientation: "columns",
storyboard: false,
defaultFigWidth: 576,
defaultFigHeight: 460,
defaultFigWidthMobile: 360,
defaultFigHeightMobile: 460
});
});
Hope someone can help! Thanks
Easy question: How do I create a flexdashboard with 4 (or more) charts in chart stack in one column.
Documentation alludes that it should be possible.
I thought it would be as simple as:
---
title: "Dygraphs Linked Time Series"
output:
flexdashboard::flex_dashboard:
orientation: columns
social: menu
source_code: embed
---
```{r setup, include=FALSE}
library(dygraphs)
library(quantmod)
library(flexdashboard)
getSymbols(c("MSFT", "HPQ", "INTC"), from = "2014-01-01", auto.assign=TRUE)
```
### Microsoft
```{r}
dygraph(MSFT[,2:4], group = "stocks") %>%
dySeries(c("MSFT.Low", "MSFT.Close", "MSFT.High"), label = "MSFT")
```
### HP
```{r}
dygraph(HPQ[,2:4], group = "stocks") %>%
dySeries(c("HPQ.Low", "HPQ.Close", "HPQ.High"), label = "HPQ")
```
### Intel
```{r}
dygraph(INTC[,2:4], group = "stocks") %>%
dySeries(c("INTC.Low", "INTC.Close", "INTC.High"), label = "INTC")
```
### Fourth Row
```{r}
dygraph(INTC[,2:4], group = "stocks") %>%
dySeries(c("INTC.Low", "INTC.Close", "INTC.High"), label = "INTC")
```
All you have to do is insert a paragraph between
instead of
```
### Fourth Row
use
```
### Fourth Row
What I would like to be able to do is to update the plot based on the output from the (DT-)table after filtering in the html.
For example - here is a screenshot of the table filtered for maz in the html:
I would like the scatter plot to update to only show the values shown in the filtered table.
Is this possible? I know I could achieve something like this using a shiny web app, but is it possible to embed some shiny code into the html to achieve this? (I have very limited experience using shiny/html so would be grateful for any pointers/ideas).
I am using R-markdown (and here is a link to the html produced):
---
title: "Filter interative plots from table results"
date: "`r format(Sys.time(), '%B %e, %Y')`"
output:
html_notebook:
theme: flatly
toc: yes
toc_float: yes
number_sections: true
df_print: paged
html_document:
theme: flatly
toc: yes
toc_float: yes
number_sections: true
df_print: paged
---
```{r setup, include=FALSE, cache=TRUE}
library(DT)
library(plotly)
library(stringr)
data(mtcars)
```
# Clean data
## Car names and models are now a string: "brand_model" in column 'car'
```{r include=FALSE}
mtcars$car <- rownames(mtcars)
mtcars$car <- stringr::str_replace(mtcars$car, ' ', '_')
rownames(mtcars) <- NULL
```
# Interactive table using DT
```{r rows.print=10}
DT::datatable(mtcars,
filter = list(position = "top"),
selection="none", #turn off row selection
options = list(columnDefs = list(list(visible=FALSE, targets=2)),
searchHighlight=TRUE,
pagingType= "simple",
pageLength = 10, #default length of the above options
server = TRUE, #enable server side processing for better performance
processing = FALSE)) %>%
formatStyle(columns = 'qsec',
background = styleColorBar(range(mtcars$qsec), 'lightblue'),
backgroundSize = '98% 88%',
backgroundRepeat = 'no-repeat',
backgroundPosition = 'center')
```
# Plot disp against mpg using plotly
```{r fig.width=8, fig.height=8}
p <- plot_ly(data = mtcars,
x = ~disp,
y = ~mpg,
type = 'scatter',
mode = 'markers',
text = ~paste("Car: ", car, "\n",
"Mpg: ", mpg, "\n"),
color = ~mpg,
colors = "Spectral",
size = ~-disp
)
p
```
Contrary to my first assessment, it is actually possible. There are multiple additions to your code. I will go through them chronologically:
You need to add runtime: shiny in the yaml-header to start shiny in any R-markdown file
Optional: I added some css style in case you need to adjust your shiny application to fit into certain screen sizes
Shiny-documents contain an UI-part, where you configure the user interface. Usually you just use a fluidPage function for that
The next part is the server.r-part where the interesting stuff happens:
We assign, i.e., your DT::datatable to an output-object (usually a list)
For each assignment we need to set a shinyID which we configure in ui.r and then add, i.e, output$mytable
I added an element which shows which rows are selected for debugging
The heart of all the changes is input$mytable_rows_all. All the controls we set up in the ui.r can be called inside the render-functions. In this particular case mytable refers to the shinyID I set for the DT::datatable in the UI-part and rows_all tells shiny to take all the rownumbers inside the shown table.
That way we just subset the data using mtcars[input$mytable_rows_all,]
To learn shiny I recommend Rstudio's tutorial. After learning and forgetting everything again I advise you to use the wonderful cheatsheet provided by Rstudio
The whole modified code looks like this:
---
title: "Filter interative plots from table results"
date: "`r format(Sys.time(), '%B %e, %Y')`"
runtime: shiny
output:
html_document:
theme: flatly
toc: yes
toc_float: yes
number_sections: true
df_print: paged
html_notebook:
theme: flatly
toc: yes
toc_float: yes
number_sections: true
df_print: paged
---
<style>
body .main-container {
max-width: 1600px !important;
margin-left: auto;
margin-right: auto;
}
</style>
```{r setup, include=FALSE, cache=TRUE}
library(stringr)
data(mtcars)
```
# Clean data
## Car names and models are now a string: "brand_model" in column 'car'
```{r include=FALSE}
mtcars$car <- rownames(mtcars)
mtcars$car <- stringr::str_replace(mtcars$car, ' ', '_')
rownames(mtcars) <- NULL
```
# Plot disp against mpg using plotly
```{r}
library(plotly)
library(DT)
## ui.r
motor_attributes=c('Cylinder( shape): V4','Cylinder( shape): V6','Cylinder( shape): V8','Cylinder( shape): 4,Straight Line','Cylinder( shape): 6,Straight Line','Cylinder( shape): 8,Straight Line','Transmission: manual','Transmission: automatic')
fluidPage(# selectizeInput('cyl','Motor characteristics:',motor_attributes,multiple=TRUE,width='600px'),
downloadLink('downloadData', 'Download'),
DT::dataTableOutput('mytable'),
plotlyOutput("myscatter"),
htmlOutput('Selected_ids'))
### server.r
output$mytable<-DT::renderDataTable({
DT::datatable(mtcars,
filter = list(position = "top"),
selection='none', #list(target='row',selected=1:nrow(mtcars)), #turn off row selection
options = list(columnDefs = list(list(visible=FALSE, targets=2)),
searchHighlight=TRUE,
pagingType= "simple",
pageLength = 10, #default length of the above options
server = TRUE, #enable server side processing for better performance
processing = FALSE)) %>%
formatStyle(columns = 'qsec',
background = styleColorBar(range(mtcars$qsec), 'lightblue'),
backgroundSize = '98% 88%',
backgroundRepeat = 'no-repeat',
backgroundPosition = 'center')
})
output$Selected_ids<-renderText({
if(length(input$mytable_rows_all)<1){
return()
}
selected_rows<-as.numeric(input$mytable_rows_all)
paste('<b> #Cars Selected: </b>',length(selected_rows),'</br> <b> Cars Selected: </b>',
paste(paste('<li>',rownames(mtcars)[selected_rows],'</li>'),collapse = ' '))
})
output$myscatter<-renderPlotly({
selected_rows<-as.numeric(input$mytable_rows_all)
subdata<-mtcars[selected_rows,]
p <- plot_ly(data = subdata,
x = ~disp,
y = ~mpg,
type = 'scatter',
mode = 'markers',
text = ~paste("Car: ", car, "\n",
"Mpg: ", mpg, "\n"),
color = ~mpg,
colors = "Spectral",
size = ~-disp
)
p
})
```