Narrow down DT using plotly_click in Rmarkdown - r

Plot plotly heatmap on Rmarkdown. I want to display the DT of the clicked data by clicking the heatmap. It was possible with Shiny. Is it possible to reproduce this function with Rmarkdown? Thank you
rmarkdown.Rmd
```{r}
library(plotly); library(DT); library(shiny)
p <- plot_ly(data=iris, x=~Sepal.Length, y=~Sepal.Width, z=~Petal.Length, type="heatmap", source = "heat")
p
observeEvent(event_data("plotly_click", source = "heat"),{
x <- event_data("plotly_click", source = "heat")$x
iris_ <- filter(iris, Sepal.Length == x)
dt <- datatable(iris_)
})
dt
``` 

This is the only way I could get it to work, but hoping you can convert this into a heatmap. For me, the heatmap wasn't rendering properly. This example uses the crosstalk function and utilizes brushing and will auto render the DT table of the selected table.
```{r}
library(ggplot2)
library(plotly)
library(DT)
m<-highlight_key(iris)
p<-ggplot(m,aes(Sepal.Length,Sepal.Width))+geom_point(aes(color = Species))
gg<-highlight(ggplotly(p),"plotly_selected")
crosstalk::bscols(gg,DT::datatable(m))
```

Related

Why does ggplotly does not work in rmarkdown the same way ggplot does

I would like to use ggplotly for it's side effect the same way ggplot does or even graphics does. By this I mean when I knitr::knit or rmarkdown::render a Rmd document I expect print(obj) where obj is a ggplotly objcet to be in the report and that's not the case.
Can anyone explain what is going on?
Can anyone tell me how I can achieve want I want to do. I want to be able to plot a ggplotly graph into a function without returning the object (I want to return the underlying data of the graph) and I'd like the code to work for both ggplot and ggplotly (i.e. use the same code for a ggplot or ggplotly)
question.R file
#+ libs, echo = FALSE
suppressMessages({
library(ggplot2)
library(plotly)
library(rmarkdown)
})
#+ functions decl, echo = FALSE
df <- data.frame(x = 1:5, y = 1:5)
f_0 <- function(df) {
p <- ggplot(df, aes(x, y)) + geom_line()
# p or plot(p) or print(p) works
print(p)
return(df)
}
f_1 <- function(df) {
p <- ggplot(df, aes(x, y)) + geom_line()
p <- ggplotly(p)
# plot(p) crashes
# print p does not print in report
print(p)
# p standalone does not work either
p
return(df)
}
#' # plots
#' plot 0
#+ plot_0
res_0 <- f_0(df)
#' plot 1
#+ plot_1
res_1 <- f_1(df)
Render this file
rmarkdown::render("question.R")
The output
Editorial comment: As a point of style, it's usually a good idea to separate computation and plotting into distinct functions, because it increases modularity, makes code easier to maintain, and allows for finer control without parameter creep. The output of individual functions can then be easily mapped to separate knitr chunks.
Best solution: I know that you are specifically asking about not returning the plot object, but I just want to point out that returning it alongside the results provides the cleanest and most elegant solution:
---
output: html_document
---
```{r include=FALSE}
library( tidyverse )
df <- data_frame( x=1:5, y=1:5 )
```
```{r}
f <- function(df) {
gg <- ggplot(df, aes(x,y)) + geom_point()
list( result=df, plot=plotly::ggplotly(gg) )
}
res <- f(df)
res$plot
```
However, if you absolutely cannot return a plotly object from a function, you have some alternatives.
Option 1: Store the plotly object to the parent frame, providing access to it from the knitr chunk.
```{r}
f1 <- function(df) {
gg <- ggplot(df, aes(x,y)) + geom_point()
assign("ggp", plotly::ggplotly(gg), envir=parent.frame())
df # NOT returning a plot
}
res1 <- f1(df)
ggp # Let knitr handle the rendering naturally
```
Option 2: Render the plot to a temporary .html and then import it as an iframe
```{r, results='asis'} # <-- note the "asis" chunk option
f2 <- function(df)
{
gg <- ggplot(df, aes(x,y)) + geom_point()
htmlwidgets::saveWidget( plotly::ggplotly(gg), "temp.html")
print( htmltools::tags$iframe(src="temp.html", width=640, height=480) )
df # NOT returning a plot
}
res2 <- f2(df)
```
Explanation: Yihui can correct me if I'm wrong, but knitr basically does "Option 2" behind the scenes. It renders htmlwidgets, such as plotly objects, into temporary .html files and then combines those temporaries to produce the final document. The reason it fails inside a function is because the temporary file gets deleted when execution leaves the function scope. (You can replicate this yourself by using tempfile() instead of the persistent "temp.html"; the iframe object will display a "file not found" error in the final document.) There's probably a way to modify knitr hooks to retain the temporary files, but it's beyond my knowledge. Lastly, the reason you don't have this issue with basic ggplot objects is because their output goes to the plotting device, which persists across calling frames.

Save and Load a ggplot plot

I am working on a large shinydashboard and was keeping my code for modeling in a separate file from the main app.R. The problem is that I need to plot my data. This requires that I save my ggplots from one file and load them in my main app.R file. How can I save my ggplots and load them.
As a simple example lets say I have the following
#make plot
> p <- mtcars %>%
ggplot(aes(x = mpg, y = cyl))+geom_point()
#save plot
> save(file=here::here("plots/a_plot.Rdata"),p)
#load plot
> p <- load(file=here::here("plots/trans_arima.Rdata"))
> p
[1] "p"
How can I load my ggplot?
You can save your plot as a png file and then load it back into youyr file
you have several option for saving your plot. you could use ggplot2s' ggsave()
function or you could use the save_plot() from the cowplot package. save_plot() is said to
give you more flexibility when it comes file adjusting hence my pick.
You can explore both.
refer to https://rdrr.io/cran/cowplot/man/save_plot.html to read more about save_plot.
tmp = data.frame(first = c('a','b','c','d','e','f','g','h','i','j','k','l','m','n'),
second = c(2,3,4,5,2,3,4,5,6,3,4,4,6, 7))
plot_tmp = ggplot(tmp, aes(first, second)) + geom_bar(stat = 'identity')
dev.new()
if("png" %in% installed.packages()){
library(png)
}else{
install.packages("png")
library(png)
}
save_plot("~/plot_tmp.png", plot_tmp, base_height = NULL, base_aspect_ratio = 1.618,
base_width = 6)
Use the following steps to load files into your shiny using by using the
#read plot
library(OpenImageR)
img<-OpenImageR::readImage("~/plot_tmp.png")
imageShow(img)
Hopefully this helps. To read more about OpenImageR and how you can use it in shiny please go to https://cran.r-project.org/web/packages/OpenImageR/vignettes/The_OpenImageR_package.html
have fun!!!

Shiny Parallel Coordinates with Brushing and Linking

I'm creating a flexdashboard / Shiny app in R using Rstudio and am trying to create a dashboard with two components: a parallel coordinates graph on top and a table below the graph.
I'm trying to use Brushing and Linking to select specific axis in the parallel coordinate graph to affect and filter data in the table.
Below is my code (adapted from https://jjallaire.shinyapps.io/shiny-ggplot2-brushing/):
---
title: "ggplot2 Brushing"
output:
flexdashboard::flex_dashboard:
orientation: columns
social: menu
source_code: embed
runtime: shiny
---
```{r global, include=FALSE}
# load data in 'global' chunk so it can be shared by all users of the dashboard
library(datasets)
mtcars2 <- mtcars[, c("mpg", "cyl", "wt")]
```
```{r}
# Reactive that returns the whole dataset if there is no brush
selectedData <- reactive({
data <- brushedPoints(mtcars2, input$plot1_brush)
if (nrow(data) == 0)
data <- mtcars2
data
})
```
Column {data-width=650}
-----------------------------------------------------------------------
### Miles Per Gallon vs. Weight {data-width=600}
```{r}
library(ggplot2)
library(GGally)
plotOutput("plot1", brush = brushOpts(id = "plot1_brush"))
output$plot1 <- renderPlot({
ggparcoord(mtcars2) + geom_line()
})
```
### Car Details {data-width=400}
```{r}
renderTable({
selectedData()
}, rownames = TRUE)
```
As you can see, brushing and linking are not working. What am I missing here? I've read a few questions about the topic and particularly around XY variables and only working for scatterplots, etc. But certainly there is a way around this and I can't seem to find a solution. Does anybody have an idea on how to make brushing and linking work with parallel coordinates in Shiny?
I have tried to find solution to Your problem but actually it is not possible at this moment to retrieve the data using brush from any parallel coordinates plot (neither plotly or ggplot2). You can easily use the brush in plotly, but You will not be able to get the data out of it (in Your case it is selectedData()). Maybe You should try another plot type.

Visualizing faceted data using interactive plotting in shiny

I'm having some trouble creating interactive plots in shiny that facet my data.
Here's some code that shows what I want, but it uses ggplot2 which is not interactive.
library(shiny)
library(data.table)
library(ggplot2)
x <- 1:10000
dt <- data.frame(a = 1:100, b = sample(x,100,replace=T), c = sample(x,100,replace=T), d = sample(x,100,replace=T))
dt.molten <- melt(dt,id.vars="a")
ui <- fluidPage(
plotOutput("gplot")
)
server = function(input, output) {
output$gplot <- renderPlot({
ggplot(y.molten,aes(x = value)) +
geom_histogram(binwidth = 100000) +
facet_wrap( ~ variable,ncol = 1)
})
}
shinyApp(ui = ui, server = server)
In my actual app, the amount of facets varies, so I can't simply hard code in 3 separate plots using highcharter, ggvis,or plotly.
Ideally I'd like it to look something like this:
require(highcharter)
x <- stl(log(AirPassengers), "per")
hchart(x)
Except with histograms instead of time-series data.
The main issue is that the data i'm plotting stretches over like -3,000,000 to +3,000,000 with a high concentration around 0. This makes it hard to see the bars at the edges, so I'd like for users to be able to zoom into certain ranges of the plot without having to select it via some ui element.
I'm open to suggestions using any plotting method in R, although i'd like to stay away from rCharts.
EDIT: I did discover that using plotly::ggplotly almost achieved what I'm looking for, however it isn't very clean. I did g <- ggplot(*plot code*) then ggplotly(g). Works decent, but it'll take quite a bit of work to clean up I think.

Removing the X,Y in nearPoints() Output

I want to use the functionality of nearPoints() to print out summary statistics for a specific point without printing the x, y associated with that point. I have been able to use this function printing the data frame and variations of the data frame. Is there anyway to suppress those columns
to customize the output? nearPoints comes from the latest version of shiny 0.12.1 but I believe may have been introduced a little earlier.
I know the documentation says this:
Note that these functions are only appropriate if the x and y variables are present in the data frame, without any transformation. If, for example, you have a plot where a the x position is calculated from a column of data, then these functions won’t work. In such a case, it may be useful to first calculate a new column and store it in the data frame.
but wanted to know if there was any kind of work around.
Here is the app that illustrates this problem, note that I'm using all of those libraries in my bigger app:
library(shiny)
library(ggplot2)
library(Cairo)
library(plyr)
library(dplyr)
library(shinydashboard)
library(grid)
library(gridExtra) # also loads grid
library(grDevices)
library(ggmap)
library(sqldf)
cars <- mtcars
ui <- basicPage(
plotOutput("plot1", click = "plot_click"),
dataTableOutput("info")
)
server <- function(input, output) {
output$plot1 <- renderPlot({
ggplot(cars, aes(x=cyl, y=carb)) + geom_point()
})
output$info <- renderDataTable({
summary_cars <- ddply(cars, .(gear, cyl, carb),
function(dd){as.data.frame(cbind(Mean_hp = mean(dd$hp),
Mean_wt = mean(dd$wt))
)
})
#This works-------------------------------------------------------
# nearPoints(summary_cars, input$plot_click, threshold = 10,
# addDist = TRUE)
#Removing the columns does not work ---------
nearPoints(select(summary_cars,-cyl,-carb), input$plot_click, threshold = 10,
addDist = F)
})
}
shinyApp(ui, server)

Resources