R great tables package - how to draw custom horizontal lines - r

I would like to be able to draw custom horizontal lines at certain rows using R's gt package. I've worked out the remove the default horizontal lines but the code I'm trying (see the last two lines below), which gives no errors does not seem to draw any lines. Help appreciated.
require(gt)
gt(iris) %>%
tab_spanner(label = "Sepal", columns = c(Sepal.Length, Sepal.Width)) %>%
tab_spanner(label = "Petal", columns = c(Petal.Length, Petal.Width)) %>%
cols_label(Sepal.Length = "Length", Sepal.Width = "Width") %>%
tab_options(table_body.hlines.color = "transparent") %>%
tab_style(style = cell_borders(sides = c("bottom"), weight = px(0.5)),
locations = cells_body(rows = c(3, 4, 7)))
I would also be interested in how to draw a horizontal line across say only he first three columns for a given row but will post that as a separate question, should that be out of scope for one question.

In fact, your code draws horizontal lines on the requested rows (3, 4, and 7). I just ran it and it works. Is this result what you expect?
Tested with R 4.2.1, gt package version 0.8.0 using Rstudio 2022.12.0

Related

ggSave group_by df list of ggarrange'd ggplot objects

I've used group_by, do, and ggplot - twice - to create two simple dfs of Date (the group) and a list of the ggplot outputs, thanks hugely to help from examples on this site. Simplified example:
p1 <- df_i %>% group_by(Date) %>% do(
plots = ggplot(data = .) +
geom_line() #etc, hugely long and detailed ggplot call omitted for brevity, but it works fine
) # close do
I can then join those dfs,
p1 <- cbind(p1, p2[,2])
names(p1) <- c("Date", "Temp", "Light") #Temp & Light were both "plots" from above
And loop through the rows, saving the outputs in a 1-row (top & bottom object) ggarranged png:
for (j in 1:nrow(p1)) {
ggsave(file = paste0(p1$Date[j], ".png"),
plot = arrangeGrob(p1$Temp[[j]], p1$Light[[j]]),
device="png",scale=1.75,width=6.32,height=4,units="in",dpi=300,limitsize=TRUE)
}
So far, so good. But nature abhors a for-loop, so I was trying to do the ggsaving in a group_by, using the same ggsave parameter options, changing only what's needed given the difference in for-loop indexing vs (what I understand of) group_by subsetting:
p1 %>% group_by(Date) %>%
ggsave(file = paste0(.$Date, ".png"),
plot = arrangeGrob(Temp, Light),...) #other params hidden here for brevity
Error in grDevices::png(..., res = dpi, units = "in"): invalid
'pointsize' argument
If I add pointsize=10 it says "invalid bg value"; add bg = "white":
Error in check.options(new, name.opt = ".X11.Options", envir =
.X11env) : invalid arguments in 'grDevices::png(..., res = dpi,
units = "in")' (need named args)
(I also tried lowering dpi to no effect). Possibly I'm going about this the wrong way, e.g. swapping %>% for %$% in Vlad's suggestion from magrittr:
Error in gList(list(list(data = list(DateTimeUTCmin5 = c(915213660, 915213780, :
only 'grobs' allowed in "gList"
This gives the same error with Date and .$Date in the ggsave call. Trying to recreate the do framework:
p1 %>% group_by(Date) %>%
do(ggsave(file = paste0(.$Date, ".png"),"_", .$Date, ".png"),
plot = arrangeGrob(Temp, Light), #etc
Error in arrangeGrob(Temp, Light) : object 'Temp' not found
p1 %>% group_by(Date) %>%
do(ggsave(file = paste0(.$Date, ".png"),"_", .$Date, ".png"),
plot = arrangeGrob(.$Temp, .$Light), #etc
Error in gList(list(list(data = list(DateTimeUTCmin5 = c(915213660,
915213780, : only 'grobs' allowed in "gList"
Which gives the same error if I use %$%.
Does anyone have the connected stack of understanding of these tools such that they can see what I'm doing wrong here? It seems like I should be close, but I'm increasingly groping around in the dark. Any pointers very much appreciated. Thanks in advance!
Equally if folks recommend a different approach I'm interested too. It strikes me that I could use an lapply (or parSapply) instead of the for-loop on the p1 df. Do operations on grouped dfs outperform apply operations?
[Edit: desired final output: ggsave dumps 1 image (with 2 plots on it) per Date, into the specified folder. Essentially if I can get ggsave to work within the grouped_df, that should be that]

R multiple lines plotly chart with customized line types

I have probably a simple R plotly question but I spent about one hour reading questions in stackoverflow and I really can't find what I need. I have a dataframe (I will share a screenshot) with different columns used to create a multiple lines plotly chart.
This is the code I use to create the plot:
plot_ly(data = df_final, x=~TENOR, y=~RATE) %>% add_trace(type='scatter',mode='lines', color=~LINE_NAME, colors = ~LINE_COL) %>%
layout(title=paste0("Market data"),
xaxis=list(title='Term (years)'),
yaxis=list(title='Yield'))
it works amazing but I would like to have the option to choose if some lines will have to be dashed, dots, or solid lines as well as their width.
I would need / want to specify this information inside the dataframe and choose the dataframe column that has such information (i.e. see the column "LINE_STYLE_FACTOR" in my attached dataframe).
I checked Multiple line chart using plotly r and Plotly r, line style by variable but I can't find how to do what I need.
The solution has to use plotly and not other charting solutions.
Thanks
At least for the line types (dash vs line), you can you 'linetype':
library(dplyr)
library(plotly)
df = data.frame(xVals = rep(1:10,2),
yVals = c(1:10, 2:11),
myColor = c(rep('Red', 10), rep('Blue', 10)),
myType = c(rep('solid', 10), rep('dot', 10)),
myName = c(rep('FirstName', 10), rep('SecondName', 10)))
plot_ly(df,
x = ~xVals,
y = ~yVals,
color = ~I(myColor),
name = ~myName,
type = 'scatter',
mode = 'lines',
linetype = ~I(myType)
)

Plotting tanglegrams subplots in R using dendextend

I am plotting Tanglegrams in R using dendextend. I am wondering if it is possible to plot multiple subplots using par(mfrow = c(2,2))?
I can't seem to figure it out.
Thanks
library(dendextend)
dend15 <- c(1:5) %>% dist %>% hclust(method = "average") %>% as.dendrogram
dend15 <- dend15 %>% set("labels_to_char")
dend51 <- dend15 %>% set("labels", as.character(5:1)) %>% match_order_by_labels(dend15)
dends_15_51 <- dendlist(dend15, dend51)
par(mfrow = c(2,2))
tanglegram(dends_15_51)
tanglegram(dends_15_51)
tanglegram(dends_15_51)
tanglegram(dends_15_51)
tl;dr: It is not possible to use par(mfrow=...) with the function tanglegram, but it is possible using layout.
Explanation: If you look closer at function tanglegram, you'll see (methods(tanglegram)) that, underneath, there are several methods, among which, dendextend:::tanglegram.dendrogram which is called to draw the tanglegram (as can be seen inside dendextend:::tanglegram.dendlist function).
Inside this function, there is a call to layout:
layout(matrix(1:3, nrow = 1), widths = columns_width)
This "erases" your previous setting of par(mfrow=c(2, 2)) and changes it to c(1, 3) (just for the "time" of the function though because at the end of the function, the value is reset...).
Indeed, in the help page of layout, it says:
These functions are totally incompatible with the other mechanisms for arranging plots on a device: par(mfrow), par(mfcol) and split.screen.
Conclusion: If you want to plot several tanglegrams in the same "window" you'll need to use the layout call (with 12 subparts: 2 rows and 6 columns) ahead of the calls to tanglegram and suppress the layout call inside tanglegram using the argument just_one=FALSE.
Example of drawing several tanglegrams:
Using the code below, you can then obtain the desired plot (I put the function's default widths for the layout):
layout(matrix(1:12, nrow=2, byrow=TRUE), widths=rep(c(5, 3, 5), 2))
tanglegram.dendlist_mod(dends_15_51, just_one=FALSE)
tanglegram.dendlist_mod(dends_15_51, just_one=FALSE)
tanglegram.dendlist_mod(dends_15_51, just_one=FALSE)
tanglegram.dendlist_mod(dends_15_51, just_one=FALSE)
This was done by updating the dendextend package in which: I modified the 2 functions tanglegram.dendrogram and tanglegram.dendlist to add a just_one parameter, which defaults to TRUE and changed the line of the layout in tanglegram.dendrogram to:
if (just_one) layout(matrix(1:3, nrow = 1), widths = columns_width)
I also suppressed the reset of par parameters and of course changed the call in tanglegram.dendlist (now called tanglegram.dendlist_mod) so it calls the new modified function, incorporates the just_one parameter and passes it to the modified tanglegram.dendrogram function.
Rather than creating a combined plot in a single graphical device, you could create multiple plots and arrange them when you put them in a document. The knitr package makes it easy to do this, by using fig.show = "hold" to hold on to multiple plots produced in a single R chunk and specifying a relevant out.width, e.g. 50% to have two plots in a row, for when the plots are placed in the document.
For example, in an R markdown (.Rmd) file you might have
```{r, fig.show = "hold", out.width = "50%", echo = FALSE}
suppressPackageStartupMessages(library(dendextend))
dend15 <- c(1:5) %>% dist %>% hclust(method = "average") %>% as.dendrogram
dend15 <- dend15 %>% set("labels_to_char")
dend51 <- dend15 %>% set("labels", as.character(5:1)) %>% match_order_by_labels(dend15)
dends_15_51 <- dendlist(dend15, dend51)
tanglegram(dends_15_51, margin_outer = 1)
plot.new()
tanglegram(dends_15_51, margin_outer = 1)
plot.new()
tanglegram(dends_15_51, margin_outer = 1)
plot.new()
tanglegram(dends_15_51, margin_outer = 1)
```
which when knitted to HTML, would look like the following:
There a few modifications I made to the code:
Suppressed package startup messages from dendextend.
Increased default margin_outer to avoid overlapping x axis labels from neighbouring plots.
Added plot.new() in between calls to tanglegram, otherwise the next plot would be drawn on top of the previous one (this is a result of tanglegram using layout and is not needed in general when producing multiple plots).
The same approach can be used in .Rnw files. If you are compiling to PDF (via LaTeX) you can add a figure caption and subcaptions, see knitr demo #067 - Graphics Options for more detail.

Plot Pretty and aligned Colored Dendrograms in R

I am using the Sparcl package (https://cran.r-project.org/web/packages/sparcl/sparcl.pdf) to plot dendrograms in R. In my specific problem, I am clustering the groups according to one criterion, and I want to visualize by coloring based on another criterion (the point of this is to show that the cluster coincides (or does not), with another characteristic. I have been able to do this with the Sparcl package, to highlight the nodes that I want to emphasize:
df <- read.delim("the_data_matrix.txt");
d <- dist(as.matrix(df))
hc = hclust(d)
y[]='black'
y[list_of_nodes$V1]='red' # This will allow me to color only certain branches red, leaving the others black
If I plot with the standard plotting function, I can control various parameters, such as labels and text size with hang and cex (but cannot color any branches) (In the picture this is "Dendrogram 1"):
plot(hc,hang=-10,cex=.1)
On the other hand, if I plot using the ColorDendrogram function within Sparcl, I can get a colored dendrogram, but lose formatting options (In the picture this is "Dendrogram 2"):
ColorDendrogram(hc, y = y, branchlength = 4)
ColorDendrogram gave me errors when I used hang and cex to control text size and placement.
My Question
Does anyone know how to fix this, either within the Sparcl package or another one? I would like to have flexibility of color that ColorDendrogram has, but not lose formatting capabilities.
Try the package dendextend (vignette), which should give you all flexibility:
library(dendextend)
d1 <- mtcars %>% dist %>% hclust %>% as.dendrogram
d2 <- mtcars %>% dist(method="minkowski") %>% hclust(method="single") %>% as.dendrogram
vals <- grep("Merc", rownames(mtcars), val=T) # highlight branches leading to "Merc..."
par(mfrow=c(2, 1))
d1 %>% set("by_labels_branches_col", value = vals) %>% set("hang_leaves", -10) %>% set("labels_cex", .1) %>% plot
d2 %>% set("by_labels_branches_col", value = vals) %>% plot

Dynamic title and sliders using manipulate package in Rstudio

Using the package manipulate in Rstudio, I'm trying to create a scatterplot in which I can select among several data frames using a picker and then using sliders I control the columns I'd like to plot for each axis. For example, using these two datasets: mtcars and iris.
library(manipulate)
manipulate(
plot(dataset[, xaxis] ~ dataset[, yaxis],
dataset,
xlab = colnames(dataset)[xaxis],
ylab = colnames(dataset)[yaxis],
main = title),
xaxis = slider(1, 10),
yaxis = slider(1, 10),
dataset = picker("mtcars" = mtcars, "iris" = iris),
title = picker("mtcars", "iris")
)
It works ok, however, I'm struggling with two questions:
How to change dynamically the title of the plot based on the selected dataset (mtcars or iris) instead of manually using another picker as I do in the example above. I'm unable to get the name of the selected data frame and pass it as a character title.
How can I determine dynamically the max argument of the sliders, instead of hardcoding in the sliders from 1 to 10. For example mtcars has 11 columns and iris 5. Or better still, select the columns for each axis by name. I've tried many different ways but I think the problem is that I can't pass variables used in a control (dataset) to others (sliders). For example, this generates an error:
xaxis = slider(1,as.numeric(dim(dataset)[2]))
I took a different approach, after reading an example included in Learning RStudio for R Statistical Computing by Mark P. J. Van der Loo. I wrote a function that solves my problems:
library(manipulate)
scatterplot <- function(dataset){
vars <- as.list(names(dataset))
name <- sys.call()[[2]]
manipulate(
plot(dataset[, xaxis] ~ dataset[, yaxis],
xlab = colnames(dataset)[xaxis],
ylab = colnames(dataset)[yaxis],
main = as.character(name)),
xaxis = slider(1, as.numeric(dim(dataset)[2]), initial = 1),
yaxis = slider(1, as.numeric(dim(dataset)[2]), initial = 2)
)
}
scatterplot(mtcars)

Resources