Is there any quick and easy way to create a simple carousel in an Rmarkdown doc?
What I know so far
I found slickr but run into errors setting options and knitting (the errors could be specific to me / mac - I am not sure at this point).
I believe it would be possible to hard code html/javascript into the RMarkdown doc i.e. the same way a carousel would be done in any other (regular) html document (i.e. using the html code here)- but I wonder if there's a native (R) way?
Example use
In my particular use case, I'm trying to display multiple complicated ggplots which are each sufficiently complex to make them require their own space (i.e. not faceted or grid.arrange as the size of each plot will get too small to read
Notes
Here is the slickr code I tried
library(texPreview)
library(slickR)
objpath <- file.path(getwd(),"slickr_files/figure-html")
if(!dir.exists(objpath)) { dir.create(objpath,recursive = TRUE) }
tex_opts$set(
fileDir = objpath, # path to save output
returnType = 'html', # return images ready for html
imgFormat = 'png' # return png images
)
knitr::kable(mtcars,'latex') %>%
texPreview::tex_preview(stem = 'kable-1')
# ! LaTeX Error: File `standalone.cls' not found.
A side note, if there's a better way of providing many (e.g. > 3) large, detailed plots that doesn't involve faceting, grid.arrange, or (my current preferred option) tabbing, please give a suggestion as a comment
The example works fine for me. Be sure to save your plots in the folder slickr_files/figure-html.
Then run:
```{r}
slickR::slickR(
list.files(objpath,full.names = TRUE,pattern = 'png'),
height = 200,
width = '95%')
```
Related
I have 3 R plots saved as pdf files (upper_left.pdf, upper_right.pdf, lower.pdf) as vector graphic and want to make a one-page pdf file and arrange them on it as follows:
What I have tried already
I have tried reading the pdf's using magick::image_read_pdf and appending them using magick::image_append. More specifically,
library(magick)
panel.ul <- image_read_pdf("upper_left.pdf")
panel.ur <- image_read_pdf("upper_right.pdf")
panel.l <- image_read_pdf("lower.pdf")
whole <- c(panel.ul, panel.ur) %>%
image_append() %>%
c(panel.l) %>%
image_append(stack = TRUE)
The first issue is magick::image_read_pdf imports the plot as png (if I'm right, not vector graphic though).
magick::image_append also 'works' and gives me what I want in viewer pane (in RStudio, next to Help).
I then try to save them using export::graph2pdf(whole), but it gives me a blank page.
So, if I am to use magick, there are two issues that need to be solved:
importing plots as vector graphic objects (do not know the technical term in R)
Exporting the stacked plot to a vector pdf file.
How can I solve it? thanks in advance.
You're basically done. You only need to add
plot(whole) # plot the external object generated in ImageMagick to R's plotting device
savePlot(type = "pdf") # saves the current plotting device to a pdf file.
You will find your plot in your workoing directory called "Rplot.pdf".
savePlot has many options to customize your pdf output. Make sure to check ?savePlot.
To recreate your scheme from above youll need to temporarily save the upper panel as a separate pdf before you paste it to on top of the lower panel:
whole2 <- image_append(c(panel.ul, panel.ur))
plot(whole2)
savePlot("whole2.pdf", type = "pdf")
If the upper and lower panel do not look proportionate you can use the heght and width parameters of savePlot to adjust the size of the first pdf.
panel.upr <- image_read_pdf("whole2.pdf")
final <- image_append(c(image_append(panel.upr),panel.l), stack = TRUE)
plot(final)
savePlot("final.pdf", type = "pdf")
I am using blogdown to to create a blogpost that has a series of tables. Creating a single table using the kable function works fine. If you do
blogdown::new_site()
blogdown::new_post("test", ext = ".rmd")
A new rmd file will be created within the content/post directory of the project. If you open that file and create a single table by doing
```{r test1}
library(knitr)
library(magrittr)
library(shiny)
data.frame(a= c(1,2,3)) %>% kable(caption = 'test',format = 'html')
```
A correctly formatted table will be generated. The caption will read "
Table 1: test" If you look at the code of the generated site, the caption will look like this.
<caption>
<span id="tab:test1">Table 1: </span>test
</caption>
Ideally I don't have any desire to label the table as Table 1 in the first place but that is another question. If formatting of captions by kable can be disabled entirely, I'd also be happy.
However if I use lapply to generate 2 tables instead
```{r test2}
lapply(1:2,function(x){
data.frame(a= c(1,2,3)) %>% kable(caption = 'test2',format = 'html') %>% HTML()
}) -> tables
tables[[1]]
tables[[2]]
```
The captions will have the prefix \#tab:test2. If you look at the caption of these tables, you'll see
<caption>(\#tab:test2)test2</caption>
The question is, why kable behaves differently when its called from a lapply compared to its behaviour outside? Note that both of these behaviours are different that its behaviour when simply knitting the file as an html_document.
I did some digging into the kable's code and found that the caption link is created by the knitr:::create_label function. Looking into this function, I saw the part that is responsible for the wrong behaviour seen with the multiple tables.
if (isTRUE(opts_knit$get("bookdown.internal.label"))) {
lab1 = "(\\#"
lab2 = ")"
}
I could not find the code, responsible for the "correct" behaviour with the single table but it seems like knitr internal options are responsible.
Ultimately the behaviour that I want is simply
<caption>test</caption>
which is the behaviour when simply knitting an html document. But I am yet to find a way to set the relevant knitr options and why are they different within the same document.
Edit: Further examination suggests that the issue isn't lapply specific. It can be replicated using a for loop or even { by itself. A complete post with all the problematic examples can be acquired from this issue on knitr's github page. This github repo includes the basic blogdown site that replicates the issue
Turns out the responsible party is not the lapply call but the HTML call at the end. It seems like the regular process by knitr in blogdown and bookdown is to have a temporary marker for the table references in the form of (\#tab:label) and replace it with the appropriate syntax later in the processing.
I was using the HTML call to be able to use the tags object in shiny/htmltools to bind the tables together. This approach seems to make the process of replacing the temporary marker impossible for reasons outside my understanding. For my own purposes I was able to remove the temporary marker all together to get rid of both malformed captions and the working-as-intended table numbers by doing
remove_table_numbers = function(table){
old_attributes = attributes(table)
table %<>% as.character() %>% gsub("\\(\\\\#tab:.*?\\)","",.)
attributes(table) = old_attributes
return(table)
}
data.frame(a= c(1,2,3)) %>% kable(caption = 'test',format = 'html') %>% remove_table_numbers
This question still would benefit from a proper explanation of the reference link placement process and if its possible to apply it to tables in HTML calls as well. But for know this solves my issue. I'll gladly switch the accepted answer if a more complete explanation appears
I have an RMarkdown document where I use data.tree and DiagrammeR to generate models. I then display these using a set-up similar to the one used in How to include DiagrammeR/mermaid flowchart in a Rmarkdown file
For example:
```{r fig.cap="Structureel model bij enkelvoudige regressie.", fig.with=4, fig.height=1}
drawStructuralModel <- function(covariates, criterion) {
### Create tree
res <- Node$new(criterion);
for (covariate in covariates) {
res$AddChild(covariate);
}
### Set display settings
SetEdgeStyle(res, dir='back');
res <- ToDiagrammeRGraph(res, direction = "descend");
res <- add_global_graph_attrs(res, "layout", "dot", "graph");
res <- add_global_graph_attrs(res, "rankdir", "RL", "graph");
### Draw and return tree
render_graph(res);
}
drawStructuralModel("X", "Y");
```
So far so good. The caption text is added, which is what you'd expect.
Except :-)
Above, in the 'setup' knitr chunk, I used setFigCapNumbering from userfriendlyscience (see https://github.com/Matherion/userfriendlyscience/blob/master/R/setFigCapNumbering.R). This function uses knit_hooks$set to set a hook for plots, so that the captions are automatically numbered.
But this numbering isn't applied to the DiagrammeR output.
I guess that makes sense, since it's not actually a plot, rather an HTML widget or some SVG or so. I would still like it to be numbered as a figure, though.
But how do I find out which hook knitr invokes when DiagrammeR output is generated?
I could always resort to using the more generic 'automatic caption' function setCaptionNumbering (https://github.com/Matherion/userfriendlyscience/blob/master/R/setCaptionNumbering.R), and tell it to use the same counter option as the figure caption thingy uses. That would sidestep the issue, but I'd prefer to modify the appropriate knitr hook.
And since this problem (figuring out which hook knitr uses for output produced by a given function) probably occurs more often, I thought it would be worth opening an SA question.
Does anybody know how you can find this out?
knitr calls knit_print on the output produced by a given chunk. This then calls the appropriate method based on the class of the output. You can find out what methods are available by running methods("knit_print"), then see if any of those match the class of the output from DiagrammeR.
Looking at your example, I'm guessing the class of your output is "DiagrammeR" "htmlwidget", so knitr is calling knit_print.htmlwidget.
Digging into that source code, it calls htmltools::knit_print.html, which wraps the tags and then outputs asis. So to answer your question, it uses the default hooks for asis output in whatever output format you're using.
I am using R Markdown with knitr in R Studio to create and update a simple project website to keep my colleagues up to speed with a data analysis model I am building. There are some plots on the page, which (for smaller plots) so far has worked nicely, they can see the code and the results in the same place.
However, some plots have grown very large (and must remain large to allow quick side-by-side comparison of models), and don't fit on the page very well. I've used separately uploaded pdfs (with a link on the page) for some of them. It would be nicer if there was a simple way of generating thumbnails of some of these plots, so that the user can view a small plot image, click on it and then inspect the much larger image in detail. However, if it takes a lot of manual scripting for each plot instance, I'd rather not waste time on it and just upload the couple of pdfs. A similar question here talks about package, knitrbootsrap, but I don't want to thumbnail all my plots, just a select few. The package seems to use Magnific popup, but integrating it myself in a Markdown page seems like a hassle(?). I didn't find anything in the R Markdown reference guide. Of course a one way would be to generate two plots, one tiny, which is shown, and link it to another, larger plot image/pdf that is uploaded separately - but a simpler, more automatic way would be desireable.
Hence the question - is there a simpler way to generate clickable plot thumbnails in R Markdown?
So, this is what I came up with. Add a plot hook, so that you generate a full-resolution pdf image before generating a small image in the chunk:
allow_thumbnails <- function(x, options) {
if (!is.null(options$thumb)) {
filename <- sprintf("%s.full.pdf", strsplit(basename(x), "\\.")[[1]][1])
absolute_path <- file.path(dirname(x), filename)
# generate the full resolution pdf
pdf(absolute_path, width = options$thumb$width, height = options$thumb$height)
eval(parse(text = options$code))
dev.off()
# add an html link to the low resolution png
options$fig.link = absolute_path
}
knitr:::hook_plot_md_base(x, options)
}
And then in the Rmd file, I define the size of the full-resolution image using the thumb argument:
```{r init}
knit_hooks$set(plot = allow_thumbnails)
```
```{r my_large_plot, fig.width = 15, fig.height = 15, thumb = list(width = 45, height = 45)}
my_large_plot()
```
This generates an html file with a clickable png that takes you to the pdf.
I do a lot of data exploration in R and I would like to keep every plot I generate (from the interactive R console). I am thinking of a directory where everything I plot is automatically saved as a time-stamped PDF. I also do not want this to interfere with the normal display of plots.
Is there something that I can add to my ~/.Rprofile that will do this?
The general idea is to write a script generating the plot in order to regenerate it. The ESS documentation (in a README) says it well under 'Philosophies for using ESS':
The source code is real. The objects are realizations of the
source code. Source for EVERY user modified object is placed in a
particular directory or directories, for later editing and
retrieval.
With any editor allows stepwise (or regionwise) execution of commands you can keep track of your work this way.
The best approach is to use a script file (or sweave or knitr file) so that you can just recreate all the graphs when you need them (into a pdf file or other).
But here is the start of an approach that does the basics of what you asked:
savegraphs <- local({i <- 1;
function(){
if(dev.cur()>1){
filename <- sprintf('graphs/SavedPlot%03d.pdf', i)
dev.copy2pdf( file=filename )
i <<- i + 1
}
}
})
setHook('before.plot.new', savegraphs )
setHook('before.grid.newpage', savegraphs )
Now just before you create a new graph the current one will be saved into the graphs folder of the current working folder (make sure that it exists). This means that if you add to a plot (lines, points, abline, etc.) then the annotations will be included. However you will need to run plot.new in order for the last plot to be saved (and if you close the current graphics device without running another plot.new then that last plot will not be saved).
This version will overwrite plots saved from a previous R session in the same working directory. It will also fail if you use something other than base or grid graphics (and maybe even with some complicated plots then). I would not be surprised if there are some extra plots on occasion that show up (when internally a plot is created to get some parameters, then immediatly replaced with the one of interest). There are probably other things that I have overlooked as well, but this might get you started.
you could write your own wrapper functions for your commonly used plot functions. This wrapper function would call both the on-screen display and a timestamped pdf version. You could source() this function in your ~/.Rprofile so that it's available every time you run R.
For latice's xyplot, using the windows device for the on-screen display:
library(lattice)
my.xyplot <- function(...){
dir.create(file.path("~","RPlots"))
my.chart <- xyplot(...)
trellis.device(device="windows",height = 8, width = 8)
print(my.chart)
trellis.device(device = "pdf",
file = file.path("~", "RPlots",
paste("xyplot",format(Sys.time(),"_%Y%m%d_%H-%M-%S"),
".pdf", sep = "")),
paper = "letter", width = 8, height = 8)
print(my.chart)
dev.off()
}
my.data <- data.frame(x=-100:100)
my.data$y <- my.data$x^2
my.xyplot(y~x,data=my.data)
As others have said, you should probably get in the habit of working from an R script, rather than working exclusively from the interactive terminal. If you save your scripts, everything is reproducible and modifiable in the future. Nonetheless, a "log of plots" is an interesting idea.