I'm trying to present two pie plots, one beside another, in HTML report that I create using Rmarkdown.
The problem is, that the labels are being cut in the HTML file.
I know how to solve it when I save the ggarange object into file, but not here...
I also tried to use plot_grid instead, it didn't solve it.
Thank you!
My code:
piePlot <- function(table,title)
{
colnames(table) <- c("group","numOfSamples")
table <- table %>% mutate(per = percent(numOfSamples / sum(Info$numOfSamples)))
ggpie(table, "numOfSamples", fill = "group", color = "group",legend='none',
label = paste(table$group,table$per,"\n","(",table$numOfSamples,")"),
label.size=0.05,
palette = rainbow(length(table$group), s = 0.4)) + coord_polar(theta = "y", clip = "off") +
ggtitle(title) + theme(plot.title = element_text(hjust = 0.5))
}
fruits <- data.frame(c("Apples","Bannana","Orange","Grapes", "lemon", "cherry"),c(12,34,67,23,54,36))
vegetables <- data.frame(c("Onion","Garlic","Tomato","Potato","Carrot", "cucumber"),c(6,3,51,12,16,9))
fruitsPlot <- piePlot(fruits, "fruits")
vegPlot <- piePlot(vegetables, "vegetables")
final <- ggarrange(fruitsPlot, vegPlot)
rmarkdown::render(
input = "RMD_input.Rmd",
output_file = stringr::str_glue("htmloutput.html"),
output_format = "html_document",
params = list(final = final))
rmarkdown file:
---
title: "test0_analysis_run"
author: "Gil"
date: "6/19/2022"
params:
final: "no graph"
output: pdf_document
---
<style type="text/css">
.main-container {
max-width: 1800px;
margin-left: auto;
margin-right: auto;
}
</style>
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)```
## R Markdown
```{r echo=FALSE}
plot(final)```
And my results: (as you can see, the cherry label is being cut)
Related
Running R4.1.2 and Windows 10:
I'm trying to knit a document that has a flextable with a ggplot image that was created via ggsave. When I run the code chunk in RMarkdown, it works fine, but when I attempt to knit a word document, I get the following error. If I don't include the image, knitr works fine.
Quitting from lines 350-376 (RPOPS_Draft_Test2.0.Rmd)
Error in read_xml.raw(charToRaw(enc2utf8(x)), "UTF-8", ..., as_html = as_html, :
xmlParseEntityRef: no name [68]
Calls: <Anonymous> ... as_xml_document -> as_xml_document.character -> read_xml.raw
Execution halted
Below are the yaml headers. I am using officedown, as I know this package is required to have images in flextables be rendered in Word.
---
title: "something: `r params$program`"
output:
officedown::rdocx_document:
reference_docx: P:/Reference_doc
params:
program: "something"
---
And here is the code chunk causing the issue.
```{r overall1_flextable}
# chart creation
plot_overall1 <- f_overall_cht(overall_chart1)
plot_overall1_img_out <- ggsave(filename = "plotoverall1img.png", plot = plot_overall1, width = 3.05, height = 0.37, dpi = 600, device = "png")
plot_overall1_in <- file.path(getwd(), "plotoverall1img.png")
example_tibble <- tibble(
col_name = "chart to the right",
chart = ""
)
ft <- flextable(example_tibble)
ft <- compose(ft, i=1, j=2,
value = as_paragraph(
as_image(src = plot_overall1_in, width = 3.05, height = 0.37),
as_chunk(chart)),
part = "body"
)
autofit(ft)
```
I haven't been able to find much on this issue, so any help would be appreciated.
I could not reproduce your error. Below the code to produce your table. There are two solutions, my recommended solution (documented here: https://ardata-fr.github.io/flextable-book/cell-content-1.html#base-plots-and-ggplot-objects) and something closer to what you wrote.
---
title: "test"
output: officedown::rdocx_document
---
```{r setup, include=FALSE}
library(officedown)
library(officer)
library(flextable)
library(ggplot2)
library(tibble)
# chart creation
plot_overall1 <- ggplot(iris, aes(Sepal.Length, Petal.Length)) +
geom_point()+
theme_void()
```
## Recommanded
The solution below is corresponding to the recommanded way.
```{r}
example_tibble <- tibble(
col_name = "chart to the right",
chart = list(plot_overall1)
)
ft <- flextable(example_tibble)
ft <- compose(ft,
j = "chart",
value = as_paragraph(
gg_chunk(value = chart, width = 3.05, height = 0.37, unit = "in")
),
part = "body"
)
autofit(ft)
```
## From scratch
The solution below is corresponding to the way you tried.
```{r}
png_file <- tempfile(fileext = ".png")
plot_overall1_img_out <- ggsave(
filename = png_file,
plot = plot_overall1,
width = 3.05, height = 0.37,
dpi = 600, device = "png")
example_tibble <- tibble(
col_name = "chart to the right"
)
ft <- flextable(example_tibble,
col_keys = c("col_name", "chart"))
ft <- compose(ft,
i = 1, j = "chart",
value = as_paragraph(
as_image(src = png_file, width = 3.05, height = 0.37, unit = "in")
),
part = "body"
)
autofit(ft)
```
I've been willing to dynamically create tab contents in rmarkdown.
I've created an in_tabs that seems to work for everything but ggplot plots.
The way it works is that it creates the Rmd code necessary to display nested lists in tabs.
The following reproducible example shows the issue:
---
title: "test"
output: html_document
---
```{r setup, include = FALSE}
library(ggplot2)
library(plotly)
l1 <- list(p1 = data.frame(x=1:10, y=1:10))
l2 <- list(p2 = data.frame(x=100:110, y=100:110))
gplot <- function(data) {
p <- ggplot(data) + aes(x=x, y=y) + geom_point() + geom_line()
return(p)
}
gplotly <- function(data) {
p <- ggplot(data) + aes(x=x, y=y) + geom_point() + geom_line()
return(ggplotly(p))
}
```
```{r, code, include = FALSE}
in_tabs <- function(l, labels = names(l), level, knit = TRUE, close_tabset = FALSE) {
if(is.null(labels)) {
stop("labels are NULL, it is required not to be so that the tabs have proper names")
}
names(l) <- labels
rmd_code <- lapply(seq_along(l), FUN = function(i) obj_to_rmd(l[[i]], name = names(l)[i], level = level + 1L))
if(isTRUE(getOption("knitr.in.progress"))) {
res <- knitr::knit(text = unlist(rmd_code), quiet = TRUE)
cat(res)
} else {
if(!knit) {
cat(unlist(rmd_code))
} else {
return(l)
}
}
if(close_tabset) {
cat(paste(get_section(level), "{.unlisted .unnumbered .toc-ignore .tabset}", "\n"))
}
}
get_section <- function(level) {
paste(rep("#", times = level), collapse = "")
}
get_tabset <- function(obj) {
ifelse(inherits(obj, "list"), "{.tabset}", "")
}
obj_to_rmd <- function(obj, parent_name = "l", name, level) {
section_code <- sprintf("%s %s %s\n", get_section(level), name, get_tabset(obj))
if(!inherits(obj, "list")) {
rmd_code <- c("```{r, echo = FALSE}\n",
sprintf("%s$`%s`\n", parent_name, name),
"```\n",
"\n")
} else {
rmd_code <- c("\n",
lapply(X = seq_along(obj),
FUN = function(i) obj_to_rmd(obj[[i]], sprintf("%s$`%s`", parent_name, name), names(obj)[i], level + 1L)))
}
return(c(section_code, rmd_code))
}
```
# plot 1 {.tabset}
```{r, plot-01, results = "asis"}
in_tabs(lapply(l1, FUN = gplot), labels = names(l1), level = 1L)
```
# plot 2 {.tabset}
```{r, plot-02, results = "asis"}
in_tabs(lapply(l2, FUN = gplot), labels = names(l2), level = 1L)
```
# plot 3 {.tabset}
```{r, plot-03, results = "asis"}
in_tabs(lapply(l1, FUN = gplotly), labels = names(l1), level = 1L)
```
# plot 4 {.tabset}
```{r, plot-04, results = "asis"}
in_tabs(lapply(l2, FUN = gplotly), labels = names(l2), level = 1L)
```
The output I get is:
You can see the issue that the first plot is actually identical the the second plot while it should not !!!
When using plotly (or anything else I have tested) it works as expected as shown on plots 3 and 4
Could you help me fix it, I am happy with testing for the class of the object obj_to_rmd receives.
PS: rmd code in_tabs generates can be seen by running in_tabs(..., knit = FALSE). For instance
in_tabs(lapply(l1, FUN = gplot), labels = names(l1), level = 1L, knit = FALSE)
## p1
```{r, echo = FALSE}
plot(l$`p1`)
```
As stefan mentioned, the issue is with the ggplot's id, since they somehow have the same code chunk, even though you named the chunks differently.I don't know the reason for this behaviour, but you can bypass it by setting
```{r, include=FALSE}
options(knitr.duplicate.label = "allow")
```
at the beginning of your document. That should do the trick. It will give different chunk names to each of your plots. You can verify that by removing results = "asis"from your ggplots to see that they no longer have the same id.
## ## p1
##
## <img src="test_files/figure-html/unnamed-chunk-2-1.png" width="672" />
## ## p2
##
## <img src="test_files/figure-html/unnamed-chunk-1-2-1.png" width="672" />
You can read more about allowing duplicated chunks at bookdown.org
I'm not 100% sure about all the details so you have to keep in mind that may answer involves some guessing.
When knitting the document knitr runs the ggplot2 code and saves the resulting plot as a png where the filename is the name of the chunk.
As far as I got it from inspecting the md file generated by knitr (by adding keep_md: true to the YAML) the issue with your code is, that "all" plots are saved under the same filename unnamed-chunk-1-1.png, i.e. both of your ggplot chunks look like this in the final md:
![](bar1_files/figure-html/unnamed-chunk-1-1.png)<!-- -->
This could also be seen by having a look the the figure-html folder which includes only one png.
Put differently your code basically works fine, but you are permanently overwriting the pngs so you end up with a document where only the last saved plot shows up. That's also the reason why your code works for ggplotly as in that case the HTML/JS code necessary to render the chart is directly added to the md file.
Under normal circumstances knitr ensures that all plots are saved under unique filenames. I can only guess why this fails in your case. My guess is that the issue is that you knit each chunk separately when calling knitr::knit(text = unlist(rmd_code), quiet = TRUE), i.e. each unnamed chunk gets the same name and each is ggplot is accordingly saved under the same filename.
Having said that, to achieve your desired result you could add a unique name to each of the dynamic code chunks so that each plot is saved under a unique filename.
As a quick solution I added an id argument to your in_tabs and obj_to_rmd functions. In case of in_tabs the id is simple the identifier of the chunk in your main document, while in case of obj_to_rmd I additionally add an identifier for the list element via id = paste(id, i, sep = "-"):
---
title: "test"
output:
html_document:
keep_md: true
---
```{r setup, include = FALSE}
library(ggplot2)
library(plotly)
d1 <- data.frame(x = 1:10, y = 1:10)
d2 <- data.frame(x = 100:110, y = 100:110)
l1 <- list(p1 = d1)
l2 <- list(p1 = d2, p2 = d1)
gplot <- function(data) {
ggplot(data) +
aes(x = x, y = y) +
geom_point() +
geom_line()
}
```
```{r, code, include = FALSE}
in_tabs <- function(l, labels = names(l), level, knit = TRUE, close_tabset = FALSE, id) {
if (is.null(labels)) {
stop("labels are NULL, it is required not to be so that the tabs have proper names")
}
names(l) <- labels
rmd_code <- lapply(seq_along(l), FUN = function(i) obj_to_rmd(l[[i]], name = names(l)[i], level = level + 1L, id = paste(id, i, sep = "-")))
if (isTRUE(getOption("knitr.in.progress"))) {
res <- knitr::knit(text = unlist(rmd_code), quiet = TRUE)
cat(res)
} else {
if (!knit) {
cat(unlist(rmd_code))
} else {
return(l)
}
}
if (close_tabset) {
cat(paste(get_section(level), "{.unlisted .unnumbered .toc-ignore .tabset}", "\n"))
}
}
get_section <- function(level) {
paste(rep("#", times = level), collapse = "")
}
get_tabset <- function(obj) {
if (inherits(obj, "list")) "{.tabset}" else ""
}
obj_to_rmd <- function(obj, parent_name = "l", name, level, id) {
section_code <- sprintf("%s %s %s\n", get_section(level), name, get_tabset(obj))
if (!inherits(obj, "list")) {
rmd_code <- c(
sprintf("```{r plot-%s, echo = FALSE}\n", id),
sprintf("%s$`%s`\n", parent_name, name),
"```\n",
"\n"
)
} else {
rmd_code <- c(
"\n",
lapply(
X = seq_along(obj),
FUN = function(i) obj_to_rmd(obj[[i]], sprintf("%s$`%s`", parent_name, name), names(obj)[i], level + 1L)
)
)
}
return(c(section_code, rmd_code))
}
```
# plot 1 {.tabset}
```{r, plot-01, results = "asis"}
p1 <- lapply(l1, FUN = gplot)
in_tabs(p1, labels = names(l1), level = 1L, id = 1)
```
# plot 2 {.tabset}
```{r, plot-02, results = "asis"}
p2 <- lapply(l2, FUN = gplot)
in_tabs(p2, labels = names(l2), level = 1L, id = 2)
```
I have an rmarkdownfile with a chunck that has a loop that creates many pages. Below is a toy example. See the "loop_chunk" code chunk. The "loop_chunk" has fig.width=9, fig.height=6, results="asis" and I am running into a problem where i need to reduce the size of a plot inside loop_chunk. All plots are 9x6 but I need to adjust one plot. I found the codee below: http://michaeljw.com/blog/post/subchunkify/
and I tried using it below but when you run the code you can see that there are 2 plots on pages 3 and 5 and there should not be. it is somehow not keeping the \newpages. There should be 1 plot on pages 2,3,4 and 5. There should only be 5 pages.
Any idea how to fix this?
---
title: "Untitled"
output: pdf_document
toc: yes
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE , comment = NA, message= FALSE, warning = TRUE)
subchunkify <- function(g, fig_height=7, fig_width=5) {
g_deparsed <- paste0(deparse(
function() {g}
), collapse = '')
sub_chunk <- paste0("
`","``{r sub_chunk_", floor(runif(1) * 10000), ", fig.height=", fig_height, ", fig.width=", fig_width, ", echo=FALSE}",
"\n(",
g_deparsed
, ")()",
"\n`","``
")
cat(knitr::knit(text = knitr::knit_expand(text = sub_chunk), quiet = TRUE))
}
data = data.frame(group= c("A","A"), value = c(1,3))
```
```{r loop_chunk, fig.width=9, fig.height=6, results="asis", message= FALSE, warning = FALSE}
for(i in 1:nrow(data)){
cat(paste0("\\newpage\n # Page ", i ," \n"))
plot(data$value[i])
cat("\n\n")
cat(paste0("\\newpage\n ## page with smaller plot \n\n"))
cat("Here is some text on this page for the smaller plot.")
cat("\n\n")
data2 = data.frame(x = 7, y = 900)
library(ggplot2)
myplot = ggplot(data2, aes(x = x, y = y ))+geom_point()
subchunkify(myplot , 4,4 )
# print(myplot) -> IS there a way to just reduce the height and width with print()?
cat("\n\n")
}
```
Using your subchunkify() function for the graphics::plot call outputs those plots to the intended pages. Replacing plot(data$value[i]) in your second chunk with
subchunkify(plot(data$value[i]), 5, 5)
outputs the 5 pages with plots as intended (where height & width are set to 5/can be edited to conditionally set dimensions for a specific plot).
I'm generating GIFs using the gganimate package within an RMarkdown file. When using output = github_document in the front matter, the GIF appears as expected in the output (github-document-output). However, when using output = html_document, the GIF generates with alt text, which defaults to the chunk name (html-document-output).
Is there a way to suppress this automatic caption? I've tried setting my own caption using the fig.cap chunk option, but that was unsuccessful.
RMarkdown code
---
output:
html_document: default
github_document: default
---
```{r}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
fig.path = "output/test-fig-",
cache.path = "output/test-cache-"
)
```
```{r cache = FALSE}
library(knitr)
library(animation)
ani.options(autobrowse = FALSE, interval = 1)
opts_knit$set(animation.fun = function(x, options, format = "gif") {
x = c(knitr:::sans_ext(x), knitr:::file_ext(x))
fig.num = options$fig.num
format = sub("^[.]", "", format)
fig.fname = paste0(sub(paste0(fig.num, "$"), "*", x[1]),
".", x[2])
mov.fname = paste0(sub(paste0(fig.num, "$"), "", x[1]), ".",
format)
# order correctly
figs <- Sys.glob(fig.fname)
figs <- figs[order(as.numeric(stringr::str_match(figs, paste0("(\\d+)\\.", x[2]))[, 2]))]
animation::im.convert(figs, output = mov.fname)
sprintf("![%s](%s)", options$label, paste0(opts_knit$get("base.url"), mov.fname))
})
opts_chunk$set(cache = TRUE, message = FALSE, warning = FALSE, fig.show = "animate")
```
```{r pkgs, cache = FALSE}
library(gapminder)
library(ggplot2)
theme_set(theme_bw())
```
```{r setup}
p <- ggplot(gapminder, aes(gdpPercap, lifeExp, size = pop, color = continent, frame = year)) +
geom_point() +
scale_x_log10()
```
```{r dependson = "setup"}
library(gganimate)
gg_animate(p)
```
The problem here is that you include the resulting animation with markdown syntax. This introduces some iiritations I guess.
Taking a look at hook_plot_html we can simulate the default output for standard plots:
sprintf(paste0('<div class="figure %s">',
'<img src="%s">',
'<p class="caption">%s</p>',
'</div>'), options$fig.align, mov.fname, options$fig.cap)
I want to display two charts with the rCharts package, one next to the other, more or less like the two pies are displayed in this link:
http://nvd3.org/examples/pie.html
I have a partial solution using <iframe>, but the solution has three problems:
It is too case specific
Including controls becomes a complicated task
It does not look too nice
Minimum working example:
---
title: "Example"
output: html_document
---
```{r rcht, message=FALSE, echo=FALSE, results='asis'}
library(rCharts)
df<-data.frame(label=c("One","Two","Three"),valuea=c(1,2,3),othera=c(10,11,12),
valueb=c(4,5,6),otherb=c(10,11,12),stringsAsFactors = FALSE)
p1 <- nPlot(valuea~ label, data = df, type = 'pieChart',height = 225, width = 300)
p2<- nPlot(valueb~ label, data = df, type = 'pieChart',height = 225, width = 300)
p1$show('inline', include_assets = TRUE, cdn = F)
p2$show('inline', include_assets = TRUE, cdn = F)
```
```{r message=FALSE, echo=FALSE}
p1$save("pie1.html", standalone = TRUE)
p2$save("pie2.html", standalone = TRUE)
```
<div align="center">
<font size="10" color="black" face="sans-serif">Both Pies</font><br>
<p>
<iframe src="pie1.html" height="400" width="400"></iframe>
<iframe src="pie2.html" height="400" width="400"></iframe>
</p>
<div>
I know pie charts should not be used and that I could use a multi-bar chart. However, I want to use this type of layout with other kinds of charts in the rCharts package.
Additionally, I would like to include controls in the charts whilst they are shown next to each other. Including the following code before the $save() function adds the controls:
```{r message=FALSE, echo=FALSE}
p1$addControls('y','valuea',values=c('valuea','othera'))
p2$addControls('y','valueb',values=c('valueb','otherb'))
```
This issue is less relevant to me, but if someone has a solution (preferably with only one control for both charts), it would be great.
I understand all this might be too much to handle from R. Any help/advice is appreciated.
Not elegant, but functional (I did not try it with controls):
---
title: "Example"
output: html_document
---
```{r rcht, message=FALSE, echo=FALSE, results='asis'}
library(rCharts)
library(htmltools)
df <- data.frame(label=c("One","Two","Three"),valuea=c(1,2,3),othera=c(10,11,12),
valueb=c(4,5,6),otherb=c(10,11,12),stringsAsFactors = FALSE)
p1 <- nPlot(valuea~ label, data = df, type = 'pieChart',height = 225, width = 300)
p2 <- nPlot(valueb~ label, data = df, type = 'pieChart',height = 225, width = 300)
```
```{r echo=FALSE, results="asis"}
cat("<table width='100%'><tr style='width:100%'><td width='50%'>")
```
```{r echo=FALSE, results="asis"}
p1$show('inline', include_assets = TRUE, cdn = FALSE)
```
```{r echo=FALSE, results="asis"}
cat("</td><td>")
```
```{r echo=FALSE, results="asis"}
p2$show('inline', include_assets = TRUE, cdn = FALSE)
```
```{r echo=FALSE, results="asis"}
cat("</td></tr></table>")
```
Hi I am having the same problem with controls it looks that in the viewer of R-studio everything works fine but not when I compile with Rmarkdown it doesn't show the plot at all.
```{r results = 'asis', comment = NA}
require(rCharts)
require(datasets)
p2 <- nPlot(mpg ~ cyl, group = 'wt',
data = mtcars, type = 'scatterChart')
p2$xAxis(axisLabel = 'Log2')
p2$yAxis(axisLabel = 'Log2')
p2$chart(tooltipContent = "#! function(key, x, y, e){
return '<b>Name:</b> ' + e.point.GeneID
} !#")
p2$chart(color = c('red', 'green'))
p2$addControls("x", value = 'mpg', values = names(mtcars))
p2$addControls("y", value = 'cyl', values = names(mtcars))
cat('<style>.nvd3{height: 400px;}</style>')
p2$print('chart2', include_assets = TRUE)
```
The code above is the addControls are removed actually works also in the rmarkdown.
Also, if you try to run the code above in Rstudio console (just from p2<-nPlot to cat command) and then calling p2 I can actually see the controls.