rmarkdown parameters conditional on another parameter value? - r-markdown

I'm creating a parametized report using rmarkdown with two selection boxes. I would like the values in the second selection box to be conditional on the value selected in the first selection box. Is this possible? If so, how?
Assuming that test.csv is a simple dataset where the first column is a key and the next columns are different lookup values for each key, here's is example code that demonstrates what I would like to be able to do. The first selectionbox is used to select the look-up column, and with the second selection box I would like to select values from the selected column:
---
params:
areagroup:
label: "Area group:"
value: wards
input: select
choices: !r x <- read.csv("test.csv"); names(x)
selected area:
label: "Selected area:"
value: 1
input: select
choices: !r x <- read.csv("test.csv"); this_col <- which(names(x) == params$areagroup); x[, this_col]
---
```{r}
print(params$`areagroup`)
print(params$`selected area`)
```

Related

Adding a letter to all table numbers in RMarkdown

I'm using RMarkdown to create Supplementary documents for a paper. These supplements contain many tables. Let's call these documents Supplement A and Supplement B. I want the table numbering to reflect the supplement letter, that is, Table A1 or Table 1A for the first table in Supplement A and so on for all tables.
How can I modify the table numbering to add a letter into the table numbering schema?
Here's an example that will produce a table with normal numbering:
---
title: "Supplement A"
output: pdf_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE)
library(knitr)
library(kableExtra)
```
```{r cars}
kable(mtcars[1:5, ], booktabs=TRUE, caption="MTCars") %>%
kable_styling(latex_options="hold_position", position="left")
```
An inelegant solution using the captioner package (details provided here: https://datascienceplus.com/r-markdown-how-to-number-and-reference-tables/) can create captions and insert them manually just before the code chunk. Combining this with the Latex package caption makes it possible to remove the automatic table naming and numbering if the caption is generated within the code chunk (How to suppress automatic table name and number in an .Rmd file using xtable or knitr::kable?). I've done this in the YAML with \captionsetup[table]{labelformat=empty}, but it can be done in the document body also. Either way, the caption can then be generated within the code chunk, which was important in my case.
This solution stops bookdown referencing from working (because labelformat cannot be empty), but a workaround for table referencing was provided in the link for using the captioner package (and is included below).
---
title: "Supplement A"
header-includes:
- \usepackage{caption}
\captionsetup[table]{labelformat=empty}
output: pdf_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE)
library(knitr)
library(kableExtra)
library(captioner)
library(stringr)
```
```{r captions}
# Create the caption(s)
caption <- captioner("Table A", FALSE)
tab_1_cap <- caption("Tab_1", "MTCars")
# Create a function for referring to the tables in text
ref <- function(x) str_extract(x, "[^:]*")
```
The following table is `r ref(tab_1_cap)`.
```{r cars}
kable(mtcars[1:5, ], booktabs=TRUE, caption=tab_1_cap) %>%
kable_styling(latex_options="hold_position", position="left")
```
An alternative solution is avaiable via LaTeX. Add the following somewhere in the body of the document to change the default figure and table names to include the letter.
\def\figurename{Figure A}
\def\tablename{Table A}
To reference a table or figure in text use, e.g., Table A\#ref(tab:label), after defining the table label as normal.
This alone will leave a space in the table/figure caption (e.g., 'Table A 1' instead of 'Table A1'). This can be solved by adding the following to the YAML:
header-includes:
- \usepackage{caption}
- \DeclareCaptionLabelFormat{nospace}{#1#2}
- \captionsetup[figure]{labelformat=nospace}
- \captionsetup[table]{labelformat=nospace}
The \DeclareCaptionLabelFormat creates a function (here labeled nospace), which overrides the default caption label when called. #1 represents the label assigned to refer to tables or figures (e.g., 'Table A') and #2 represents the number of the table or figure. The captionsetup lines change the label format for all tables and figures to the format defined by 'nospace'.
Thus, the code produces, e.g., 'Table A1: Table name' as the caption. If instead you wanted, e.g., 'Table A-1: Table name', the code in \DeclareCaptionLabelFormat should be changed to {#1-#2}.
---
title: "Supplement A"
output: bookdown::pdf_document2
toc: false
header-includes:
- \usepackage{caption}
- \DeclareCaptionLabelFormat{nospace}{#1#2}
- \captionsetup[figure]{labelformat=nospace}
- \captionsetup[table]{labelformat=nospace}
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE)
library(knitr)
library(kableExtra)
library(bookdown)
```
\def\figurename{Figure A}
\def\tablename{Table A}
See Table A\#ref(tab:cars) for something about cars.
(ref:cars) Table caption
```{r cars}
kable(mtcars[1:5, ], booktabs=TRUE, caption="(ref:cars)") %>%
kable_styling(latex_options="hold_position", position="left")
```
Answer inspired by: Figure name in caption using RMarkdown
Caption latex package documentation: https://ctan.org/pkg/caption

Caption numbering not in sequential order when citing the captions with captioner in Rmarkdown

I am using captioner (https://cran.r-project.org/web/packages/captioner/vignettes/using_captioner.html) to create table captions in Rmarkdown - the main reason is because I am using huxtable for conditional formatting and exporting to word. This is the only I have found to have numbered captions.
I was trying to reference the captions but the caption number is not in sequential order when citing the captions but only if the table_nums(..., display="cite") is before the tables. I was trying to give the range of table numbers and it changed the number of the last table. I The number isn't changed if the r table_nums('third_cars_table',display = "cite") is put after the captions. Is there a way to make sure that table numbers remain in sequential order? I'd also be happy with a better solution for numbered captions.
Reproducible example:
---
title: "Untitled"
output: bookdown::word_document2
---
```{r setup, include=FALSE}
library(captioner)
library(huxtable)
library(knitr)
library(pander)
table_nums <- captioner(prefix = "Table")
fig_nums <- captioner(prefix = "Figure")
knitr::opts_chunk$set(echo = TRUE)
```
## Description of tables
I am trying to put a description of tables
and say that these results are shown table numbers ranging
from the first table (`r table_nums('first_cars_table',display = "cite")`)
to the last table (`r table_nums('third_cars_table',display = "cite")`)
```{r, results='asis',echo=FALSE,eval.after=TRUE}
tablecap1=cat(table_nums(name="first_cars_table",caption='First car table'))
kable((cars[1:5,]))
tablecap2=cat(table_nums(name="second_cars_table",caption='second car table'))
kable(cars[6:10,])
tablecap3=cat(table_nums(name="third_cars_table",caption='third car table'))
kable(cars[10:15,])
```
The results:
A (terrible) workaround is to manually give the number ordering using display = FALSE. For example, inserting the following at the start of the document will ensure t1-t5 are sequentially numbered, no matter where the tables or first citations appear:
`r table_nums('t1', display = FALSE)`
`r table_nums('t2', display = FALSE)`
`r table_nums('t3', display = FALSE)`
`r table_nums('t4', display = FALSE)`
`r table_nums('t5', display = FALSE)`
I have not examined the captioner code but I expect that the document is read from top to bottom once and hence the numbering is stored in a first come, first served basis. Thus, I am not sure there are any other ways to get around this as it would involve some kind of pre-processing stage.

Updating Shiny UI Element doesn't invalidate its associated input value

I am developing a simple web app using the Interactive Document approach with R_Markdown and Shiny. I have a series of input UI objects that get the user options, each of these modifies the next in a chain, and the final one triggers the output (a chart). So I have
A map, which when clicked defines the
Seasons of data available, when one is selected it gives the
Soil types in the data, when one or more are selected it gives the
Elevation classes in the data, when one is selected we then calculate and draw the
Output chart of the selected data.
So for example there are drop down lists to choose the season and soil(s):
output$season_selector <- renderUI({
cat(file=stderr(), paste("render season selector"), "\n")
selectInput("season", h4("Season?"), my$season_here, selected=my$season_sel)
})
output$soil_selector <- renderUI({
cat(file=stderr(), paste("render soil selector"), "\n")
selectInput("soil", h4("Soils?"), my$soil_here, selected=my$soil_sel,
selectize=FALSE, multiple=TRUE)
})
I observe input$season, and this triggers an update of the "soil" UI element.
observeEvent(input$season, {
...
# reset soil list and default soil selected
my$soil_sel <- my$soil_here
updateSelectInput(session, "soil", choices=my$soil_here, selected=my$soil_sel)
})
However, this does invalidate input$soil (although the UI element options and selection have changed, the user has not made a selection), and so the next step in the cascade doesn't trigger:
observeEvent(input$soil, {
...
# reset elev list and default elev selected
my$soil_sel <- my$soil_here
updateSelectInput(session, "soil", choices=my$soil_here, selected=my$soil_sel)
})
How do I achieve a cascade of reactive UI elements like this? Each reaction needs to trigger either when the UI options and selection changes or when the user makes a different selection. Thanks.
Ok, I think I've fixed it. I needed to use the following pattern, which resets variables further down the chain, and doesn't respond to user inputs unless the value has changed. This avoids duplicate or missing events.
# reset selections
my$soil_default <- my$soil_here
my$soil <- my$soil_default
my$elev <- list(NA)
}) # end reaction to season changing
observeEvent(input$soil, {
req(input$soil, input$soil!="NA")
if (any(my$soil != input$soil)) {
my$soil <- input$soil
my$elev <- list(NA)
}
})
#### react to change of soil ####
observeEvent(my$soil, {
cat(file=stderr(), "\n")
cat(file=stderr(), paste("change of my$soil = "))
cat(file=stderr(), paste(my$soil), "\n")
req(my$soil, my$soil!="NA")

R: xml2, extracting datasource names

I just installed the package XML2, and I manage to extract the aimed information. The next step is to 'visualize' the extracted information, e.g. with RShiny. Alas I fail to do "string parsing" correctly ...
For example: the extracted datasources
xmlfile <- read_xml("~ /Sample.xml")
ds <- xml_find_all(xmlfile , ".//datasource")
listds <- unique(unlist(ds, use.names = FALSE))
Datasources are (in this example) two excel files. Hence the outcome is a list with the names of the two excelfiles and the sheets of the respective excelfiels
"Customers (Sample)" "Orders (Sample - Sales (Excel))"
Note: I cannot say why one data source inlcudes "(Excel)" while the other does not.
Anyways, the desired outcome (= visualisation) would be
Datasource: Sample Sheet Name: Customer
Datasource: Sample - Sales Sheet Name: Orders
Question: how to tell R to "find name within () i.e. "Sample" or "Sample - Sales" and to paste this .... then to find the string within " " but outside of (), i.e. "Customer" or "Orders "?
Thanks a million for any thoughts and advice!
list the ds object. use xml_attr to get the content.
Also post the actual file.

Shiny: passing reactive values to xtable options in renderTable

I am having a problem with a format of a table.
Let's say I want to control the number of digits of a table with a numeric input. It seems that the options of the table are rendered when I launch the application but not with reactive values. is this true??
---
title: "Untitled"
runtime: shiny
output: html_document
---
```{r, echo=FALSE}
inputPanel(
numericInput("n_digits", label = "Number of digits:",
min = 0, max = 5, value = 1)
)
renderTable({
a<-rep(1.1,3)
b<-rep(2.22,3)
c<-rep(3.333,3)
cbind(a,b,c)
}, digits=c(0,rep(input$n_digits,3)))
```
This could also be helpful to passing other options when the number of columns is not fixed and depends on a variable