I am trying to convert ggplot code which is repetitive into function; I have done almost but only concern is I need to pass the application as a variable.
Here is the plot code where I used column called Application inside the summarise and mutate. The challenge is same column has been used for y axis
ggplot_common_function <- function(data,x,y,z) {
Removestring(ggplotly(
data %>%
group_by(m_year,status) %>%
summarise(Applications = sum(Applications)) %>%
mutate(total_sum = sum(Applications)) %>%
ggplot(mapping = aes({{x}},{{y}},text = paste(total_sum))) +
geom_col(aes(fill = {{z}})) +
theme_classic() +
theme(axis.line.y = element_blank(),
axis.ticks = element_blank(),
legend.position = "bottom") +
labs(x = "", y = "Agreements Values (In Lakhs)", fill = "") +
theme(axis.title.y = element_text(size = 8)) +
scale_fill_manual(values = c("#1F7A3F", "#70B821")) +
scale_y_continuous(labels = function(x) format(x, scientific = FALSE),
expand = expansion(mult = c(0,.3)),
breaks = integer_breaks()),
tooltip = c("text")) %>%
layout(legend = list(orientation = "h", x = 0.1, y = -0.2,
font = list( family = 'Arial', size = 10, color = 'black')),
xaxis = x_labels, yaxis = y_labels) %>%
config(displaylogo = FALSE, modeBarButtonsToRemove = list(
'sendDataToCloud', 'autoScale2d', 'resetScale2d',
'toggleSpikelines', 'hoverClosestCartesian', 'hoverCompareCartesian',
'zoom2d', 'pan2d', 'select2d',
'lasso2d', 'zoomIn2d', 'zoomOut2d'))
)
}
ggplot_common_function(data,m_year,Applications,status)
To run the above code there is some pre function
integer_breaks <- function(n = 5, ...) {
fxn <- function(x) {
breaks <- floor(pretty(x, n, ...))
names(breaks) <- attr(breaks, "labels")
breaks
}
return(fxn)
}
Removestring = function(d){
for (i in 1:length(d$x$data)){
if (!is.null(d$x$data[[i]]$name)){
d$x$data[[i]]$name = gsub("\\(","",str_split(d$x$data[[i]]$name,",")[[1]][1])
}
}
return(d)
}
Plan <- "#288D55"
multicolor = c("#135391","#0098DB","#828388","#231F20","#C41330","#698714","#162FBF","#F36717","#BD00FF")
x_labels = list(tickangle = -45,tickfont = list(family = "Arial",size = 10,color = "black",face="bold"))
y_labels = list(tickfont = list(family = "Arial",size = 10,color = "black",face="bold"))
Any suggestions would be appreciated
This is basically a question related to programming in dplyr. To achieve your desired result and get rid of hardcoding the column names in your function and use x, y, z instead you could make use of the {{ curly-curly operator as you did in the ggplot code and the special assignment operator :=. Additionally instead of wrapping all your code inside ggplotly you proceed in steps. Do the data wrangling, make your ggplot and finally pass it to ggplotly:
library(plotly)
library(dplyr)
library(stringr)
ggplot_common_function <- function(data, x, y, z) {
data <- data %>%
group_by({{ x }}, {{ z }}) %>%
summarise({{ y }} := sum({{ y }})) %>%
mutate(total_sum = sum({{ y }}))
p <- ggplot(data, mapping = aes({{ x }}, {{ y }}, text = paste(total_sum))) +
geom_col(aes(fill = {{ z }})) +
theme_classic() +
theme(axis.line.y = element_blank(), axis.ticks = element_blank(), legend.position = "bottom") +
labs(x = "", y = "Agreements Values (In Lakhs)", fill = "") +
theme(axis.title.y = element_text(size = 8)) +
scale_fill_manual(values = c("#1F7A3F", "#70B821")) +
scale_y_continuous(labels = function(x) format(x, scientific = FALSE), expand = expansion(mult = c(0, .3)), breaks = integer_breaks())
ggp <- ggplotly(p, tooltip = c("text")) %>%
layout(legend = list(orientation = "h", x = 0.1, y = -0.2, font = list(family = "Arial", size = 10, color = "black")), xaxis = x_labels, yaxis = y_labels) %>%
config(displaylogo = FALSE, modeBarButtonsToRemove = list("sendDataToCloud", "autoScale2d", "resetScale2d", "toggleSpikelines", "hoverClosestCartesian", "hoverCompareCartesian", "zoom2d", "pan2d", "select2d", "lasso2d", "zoomIn2d", "zoomOut2d"))
Removestring(ggp)
}
ggplot_common_function(data, m_year, Applications, status)
#> `summarise()` has grouped output by 'm_year'. You can override using the
#> `.groups` argument.
Related
This question builds on from here:
Drawing a polar heatmap
> dput(names.d)
c("0050773", "0050774", "0050775", "0050776", "0050777", "0050778",
"0050779", "0050780", "0050781", "0050782", "0050783", "0050784",
"0050785", "0050786", "0050787", "0050788", "0050789", "0050790",
"0050808", "0050809", "0050810", "0050811", "0050812", "0050813",
"0050814", "0050818", "0050819", "0050820", "0050821", "0050822"
)
Based on this, I have come up with the following code:
set.seed(20220913)
arr <- matrix(runif(15*30), nrow = 30)
dff <- as.data.frame(arr)
names(dff) <- paste(sample(letters, replace = F), sample(letters, replace = F), sep = " ")[1:15]
library(tidyverse)
dff %>%
mutate(Site = seq(nrow(.))) %>%
pivot_longer(-Site, names_to = 'Species', values_to = 'Abundance') %>%
mutate(yval = match(Species, colnames(dff))) %>%
ggplot(aes(Site, yval, fill = Abundance)) +
geom_tile(color = "black") +
geom_text(aes(label = colnames(dff)), hjust = 1.1, size = 3,
data = data.frame(Site = 31.5, yval = 1:15, Abundance = 1)) +
coord_polar() +
scale_y_continuous(limits = c(-5, 15.5)) +
scale_x_continuous(limits = c(0.5, 31.5), breaks = 1:30, labels = names.d,
name = 'Breeding site') +
scale_fill_gradientn(colors = colorRampPalette(RColorBrewer::brewer.pal(name = "YlOrRd", n = 9))(25), values = 0:1, labels = scales::percent)+
theme_void(base_size = 16) +
theme(axis.text.x = element_text(size = 12),
axis.title.x = element_text())
which gives me the following figure:
Which is great, but I would like the labels on the rim of the figure to radiate out (or be tangent, for that matter). So, I wrote the angles as:
ang <- 1:30/31.5*360
However, I can not see where to pass this argument. Looking around, it would normally be in the aes function, but there the labels are for the y-axis in the figure (before being changed to the polar coordinates), and what I am wanting rotated should be in the x-axis. So, how do I do this? Thanks for any suggestions!
You can add this in the axis.text.x = element_text() :
ang <- 90 - (1:30/31.5*360)
dff %>%
mutate(Site = seq(nrow(.))) %>%
pivot_longer(-Site, names_to = 'Species', values_to = 'Abundance') %>%
mutate(yval = match(Species, colnames(dff))) %>%
ggplot(aes(Site, yval, fill = Abundance)) +
geom_tile(color = "black") +
geom_text(aes(label = colnames(dff)), hjust = 1.1, size = 3,
data = data.frame(Site = 31.5, yval = 1:15, Abundance = 1)) +
coord_polar() +
scale_y_continuous(limits = c(-5, 15.5)) +
scale_x_continuous(limits = c(0.5, 31.5), breaks = 1:30, labels = names.d,
name = 'Breeding site') +
scale_fill_gradientn(colors = colorRampPalette(RColorBrewer::brewer.pal(name = "YlOrRd", n = 9))(25), values = 0:1, labels = scales::percent)+
theme_void(base_size = 16) +
theme(axis.text.x = element_text(size = 12, angle = ang),
axis.title.x = element_text())
I have some visualizations plotted in a flexdashboard, but, sometimes when I choose a parameter (for instance "customer group") and it's empty (no records), the visualization will throw an error. I need something like the trycatch() function in order to show a message when the code returns an error, or at least something similar.
Following is the piece of code that corresponds to the graph that throws the error, where should my trycatch() go and with what other parameters?
### {data-width=498}
```{r}
## Serie de tiempo
timeseries88 <- reactive(selected_80() %>%
dplyr::group_by(Year, FECHAFACTURA, dia_año)%>%
dplyr::summarise(VALORNETO = sum(VALORNETO)) %>%
mutate(text = paste("Año: ", Year,
"\nVenta Neta: $", round(VALORNETO/1000000, 4), " M",
"\nFecha: ", format(FECHAFACTURA, format = "%d/%m/%Y"), sep = "") ,
fechames = format(FECHAFACTURA, "%d-%m"))%>%
arrange(FECHAFACTURA)
)
renderPlotly({
ggplotly(ggplot(timeseries88(), aes(x = FECHAFACTURA,
y = VALORNETO,
group = Year,
text = text))+
geom_point(size = 0.75, color = color_periodo_unico)+
geom_line(size = 0.3, color = color_periodo_unico)+
labs(
x = "", y = "")+
theme(
axis.text.x = element_text(angle = 60, hjust = 1),
legend.text = element_text(size = 8.5),
text = element_text(size = 8.5),
axis.ticks.x = element_blank(),
panel.background = element_blank() ) +
scale_y_continuous(labels = unit_format(unit = "M", scale = 1e-6)),
tooltip = "text") %>%
layout(xaxis = list(autorange = TRUE),
yaxis = list(autorange = TRUE),
showlegend = F,
title = list(text = 'Venta de Período', x = 0.05)
) %>% config(displayModeBar = F)
})
```
I am using ggVennDiagram to creat a venn diagram. I would like to set the color of categories manually. Here is what I am trying, however the color of border line of the circles is not changed.
x <- list(A=1:5,B=2:7,C=3:6,D=4:9)
ggVennDiagram(x, label = "count", label_alpha = 0,
color = c("A" = "yellow","B" ="steelblue",'C' = 'red', 'D' = 'black') ,
set_color = c("A" = "yellow","B" ="steelblue", 'C' = 'red', 'D' = 'black')) +
scale_fill_gradient(low = "#F4FAFE", high = "#4981BF")
Any Idea how I can match the colors of circle lines with the name of categories?
Thanks
From ggVennDiagram documentation it looks as if you have to build up the venn diagram rather than use the ggVennDiagram function. Maybe this adaptation from the documentation example gives you enough to work on...
Updated to include OP's comment for percentage count.
library(ggplot2)
library(ggVennDiagram)
x <- list(A=1:5,B=2:7,C=3:6,D=4:9)
venn <- Venn(x)
data <- process_data(venn)
ggplot() +
# 1. region count layer
geom_sf(aes(fill = count), data = venn_region(data)) +
# 2. set edge layer
geom_sf(aes(color = name), data = venn_setedge(data), show.legend = TRUE, size = 2) +
# 3. set label layer
geom_sf_text(aes(label = name), data = venn_setlabel(data)) +
# 4. region label layer
geom_sf_label(aes(label = paste0(count, " (", scales::percent(count/sum(count), accuracy = 2), ")")),
data = venn_region(data),
size = 3) +
scale_fill_gradient(low = "#F4FAFE", high = "#4981BF")+
scale_color_manual(values = c("A" = "yellow","B" ="steelblue",'C' = 'red', 'D' = 'black'),
labels = c('D' = 'D = bdiv_human'))+
theme_void()
Created on 2021-12-04 by the reprex package (v2.0.1)
The ggVennDiagram command calls the ggVennDiagram::plot_venn function for plotting colored areas. You can modify this function according to your needs.
See below my suggestion.
plot_venn <- function (x, show_intersect, set_color, set_size, label, label_geom,
label_alpha, label_color, label_size, label_percent_digit,
label_txtWidth, edge_lty, edge_size, ...) {
venn <- Venn(x)
data <- process_data(venn)
p <- ggplot() + geom_sf(aes_string(fill = "count"), data = data#region) +
geom_sf(aes_string(color = "name"), data = data#setEdge,
show.legend = F, lty = edge_lty, size = edge_size, color = set_color) +
geom_sf_text(aes_string(label = "name"), data = data#setLabel,
size = set_size, color = set_color) + theme_void()
if (label != "none" & show_intersect == FALSE) {
region_label <- data#region %>% dplyr::filter(.data$component ==
"region") %>% dplyr::mutate(percent = paste(round(.data$count *
100/sum(.data$count), digits = label_percent_digit),
"%", sep = "")) %>% dplyr::mutate(both = paste(.data$count,
paste0("(", .data$percent, ")"), sep = "\n"))
if (label_geom == "label") {
p <- p + geom_sf_label(aes_string(label = label),
data = region_label, alpha = label_alpha, color = label_color,
size = label_size, lineheight = 0.85, label.size = NA)
}
if (label_geom == "text") {
p <- p + geom_sf_text(aes_string(label = label),
data = region_label, alpha = label_alpha, color = label_color,
size = label_size, lineheight = 0.85)
}
}
if (show_intersect == TRUE) {
items <- data#region %>% dplyr::rowwise() %>% dplyr::mutate(text = stringr::str_wrap(paste0(.data$item,
collapse = " "), width = label_txtWidth)) %>% sf::st_as_sf()
label_coord = sf::st_centroid(items$geometry) %>% sf::st_coordinates()
p <- ggplot(items) + geom_sf(aes_string(fill = "count")) +
geom_sf_text(aes_string(label = "name"), data = data#setLabel,
inherit.aes = F) + geom_text(aes_string(label = "count",
text = "text"), x = label_coord[, 1], y = label_coord[,
2], show.legend = FALSE) + theme_void()
ax <- list(showline = FALSE)
p <- plotly::ggplotly(p, tooltip = c("text")) %>% plotly::layout(xaxis = ax,
yaxis = ax)
}
p
}
Then, you can run the code:
library(ggVennDiagram)
library(ggplot2)
# Replace the plot_venn function with the modified version
assignInNamespace(x="plot_venn", value=plot_venn, ns="ggVennDiagram")
x <- list(A=1:5,B=2:7,C=3:6,D=4:9)
ggVennDiagram(x, label = "count", label_alpha = 0,
color = c("A" = "yellow","B" ="steelblue",'C' = 'red', 'bdiv_human' = 'black') ,
set_color = c("A" = "yellow","B" ="steelblue", 'C' = 'red', 'bdiv_human' = 'black')) +
scale_fill_gradient(low = "#F4FAFE", high = "#4981BF") +
scale_color_gradient(low = "#F4FAFE", high = "#4981BF")
I'm trying draw multiple density plots in one plot for comparison porpuses. I wanted them to have their confidence interval of 95% like in the following figure. I'm working with ggplot2 and my df is a long df of observations for a certain location that I would like to compare for different time intervals.
I've done some experimentation following this example but I don't have the coding knowledge to achieve what I want.
What i managed to do so far:
library(magrittr)
library(ggplot2)
library(dplyr)
build_object <- ggplot_build(
ggplot(data=ex_long, aes(x=val)) + geom_density())
plot_credible_interval <- function(
gg_density, # ggplot object that has geom_density
bound_left,
bound_right
) {
build_object <- ggplot_build(gg_density)
x_dens <- build_object$data[[1]]$x
y_dens <- build_object$data[[1]]$y
index_left <- min(which(x_dens >= bound_left))
index_right <- max(which(x_dens <= bound_right))
gg_density + geom_area(
data=data.frame(
x=x_dens[index_left:index_right],
y=y_dens[index_left:index_right]),
aes(x=x,y=y),
fill="grey",
alpha=0.6)
}
gg_density <- ggplot(data=ex_long, aes(x=val)) +
geom_density()
gg_density %>% plot_credible_interval(tab$q2.5[[40]], tab$q97.5[[40]])
Help would be much apreaciated.
This is obviously on a different set of data, but this is roughly that plot with data from 2 t distributions. I've included the data generation in case it is of use.
library(tidyverse)
x1 <- seq(-5, 5, by = 0.1)
t_dist1 <- data.frame(x = x1,
y = dt(x1, df = 3),
dist = "dist1")
x2 <- seq(-5, 5, by = 0.1)
t_dist2 <- data.frame(x = x2,
y = dt(x2, df = 3),
dist = "dist2")
t_data = rbind(t_dist1, t_dist2) %>%
mutate(x = case_when(
dist == "dist2" ~ x + 1,
TRUE ~ x
))
p <- ggplot(data = t_data,
aes(x = x,
y = y )) +
geom_line(aes(color = dist))
plot_data <- as.data.frame(ggplot_build(p)$data)
bottom <- data.frame(plot_data) %>%
mutate(dist = case_when(
group == 1 ~ "dist1",
group == 2 ~ "dist2"
)) %>%
group_by(dist) %>%
slice_head(n = ceiling(nrow(.) * 0.1)) %>%
ungroup()
top <- data.frame(plot_data) %>%
mutate(dist = case_when(
group == 1 ~ "dist1",
group == 2 ~ "dist2"
)) %>%
group_by(dist) %>%
slice_tail(n = ceiling(nrow(.) * 0.1)) %>%
ungroup()
segments <- t_data %>%
group_by(dist) %>%
summarise(x = mean(x),
y = max(y))
p + geom_area(data = bottom,
aes(x = x,
y = y,
fill = dist),
alpha = 0.25,
position = "identity") +
geom_area(data = top,
aes(x = x,
y = y,
fill = dist),
alpha = 0.25,
position = "identity") +
geom_segment(data = segments,
aes(x = x,
y = 0,
xend = x,
yend = y,
color = dist,
linetype = dist)) +
scale_color_manual(values = c("red", "blue")) +
scale_linetype_manual(values = c("dashed", "dashed"),
labels = NULL) +
ylab("Density") +
xlab("\U03B2 for AQIv") +
guides(color = guide_legend(title = "p.d.f \U03B2",
title.position = "right",
labels = NULL),
linetype = guide_legend(title = "Mean \U03B2",
title.position = "right",
labels = NULL,
override.aes = list(color = c("red", "blue"))),
fill = guide_legend(title = "Rej. area \U03B1 = 0.05",
title.position = "right",
labels = NULL)) +
annotate(geom = "text",
x = c(-4.75, -4),
y = 0.35,
label = c("RK", "OK")) +
theme(panel.background = element_blank(),
panel.border = element_rect(fill = NA,
color = "black"),
legend.position = c(0.2, 0.7),
legend.key = element_blank(),
legend.direction = "horizontal",
legend.text = element_blank(),
legend.title = element_text(size = 8))
I am using the ggerrorplot () function of the ggpubr package to create the graph below. My question is whether there is any way to change the colors of the dots without changing the color of the point that represents the mean and standard deviation? Observe the image:
My code:
# loading packages
library(ggpubr)
# Create data frame
GROUP <- c()
TEST <- c()
VALUE <- c()
for (i in 0:100) {
gp <- c('Group1','Group2','Group1 and Group2')
ts <- c('Test1','Test2')
GROUP <- append(GROUP, sample(gp, 1))
TEST <- append(TEST, sample(ts, 1))
VALUE <- append(VALUE, sample(1:200, 1))
}
df <- data.frame(GROUP, TEST, VALUE)
# Seed
set.seed(123)
# Plot
ggerrorplot(df, x = "GROUP", y = "VALUE",
desc_stat = "mean_sd",
add = c("jitter"),
color = "TEST",
palette = "jco",
add.params = list(size = 0.2),
order = c('Group1','Group2','Group1 and Group2')
) +
labs(x = '', y = 'Values\n') +
theme(legend.title = element_blank())
Can you accomplish this by simply passing in color to add.params?
# loading packages
library(ggpubr)
#> Loading required package: ggplot2
# Create data frame
GROUP <- c()
TEST <- c()
VALUE <- c()
for (i in 0:100) {
gp <- c('Group1','Group2','Group1 and Group2')
ts <- c('Test1','Test2')
GROUP <- append(GROUP, sample(gp, 1))
TEST <- append(TEST, sample(ts, 1))
VALUE <- append(VALUE, sample(1:200, 1))
}
df <- data.frame(GROUP, TEST, VALUE)
# Seed
set.seed(123)
# Plot
ggerrorplot(df, x = "GROUP", y = "VALUE",
desc_stat = "mean_sd",
add = c("jitter"),
color = "TEST",
palette = "jco",
add.params = list(size = 0.2, color = "red"),
order = c('Group1','Group2','Group1 and Group2')
) +
labs(x = '', y = 'Values\n') +
theme(legend.title = element_blank())
Created on 2021-03-10 by the reprex package (v0.3.0)
Another potential workaround - replicate the plot using ggplot() and geom_linerange(), e.g.
library(ggpubr)
library(ggsci)
library(cowplot)
# Create data frame
GROUP <- c()
TEST <- c()
VALUE <- c()
for (i in 0:100) {
gp <- c('Group1','Group2','Group1 and Group2')
ts <- c('Test1','Test2')
GROUP <- append(GROUP, sample(gp, 1))
TEST <- append(TEST, sample(ts, 1))
VALUE <- append(VALUE, sample(1:200, 1))
}
df <- data.frame(GROUP, TEST, VALUE)
# Seed
set.seed(123)
data_summary <- function(data, varname, groupnames){
require(plyr)
summary_func <- function(x, col){
c(mean = mean(x[[col]], na.rm=TRUE),
sd = sd(x[[col]], na.rm=TRUE))
}
data_sum<-ddply(data, groupnames, .fun=summary_func,
varname)
data_sum <- rename(data_sum, c("mean" = varname))
return(data_sum)
}
df2 <- data_summary(df, varname = "VALUE", groupnames = c("TEST", "GROUP"))
# Plot
p1 <- ggplot(df, aes(x = factor(GROUP, levels = c('Group1','Group2','Group1 and Group2')),
y = VALUE, color = TEST)) +
geom_jitter(shape = 21, fill = "black", stroke = 0,
position = position_jitterdodge(jitter.width = 0.2)) +
geom_linerange(data = df2, aes(ymin=VALUE-sd, ymax=VALUE+sd),
position=position_dodge(width = .75)) +
geom_point(data = df2, aes(y = VALUE), size = 3,
position = position_dodge(width = 0.75)) +
scale_color_jco() +
labs(x = '', y = 'Values\n') +
theme_classic(base_size = 14) +
theme(legend.title = element_blank(),
legend.position = "top")
p2 <- ggerrorplot(df, x = "GROUP", y = "VALUE",
desc_stat = "mean_sd",
add = c("jitter"),
color = "TEST",
palette = "jco",
add.params = list(size = 0.2),
order = c('Group1','Group2','Group1 and Group2')
) +
labs(x = '', y = 'Values\n') +
theme(legend.title = element_blank())
cowplot::plot_grid(p1, p2, nrow = 1, ncol = 2, labels = "AUTO")
When you plot them side-by-side you can see that they aren't exactly the same, but this might work for you nonetheless.
Edit
An advantage of this approach is that you can adjust the 'fill' scale separately if you don't want all the dots to be the same colour, but you do want them to be different to the lines, e.g.
p1 <- ggplot(df, aes(x = factor(GROUP, levels = c('Group1','Group2','Group1 and Group2')),
y = VALUE, color = TEST)) +
geom_jitter(aes(fill = TEST), shape = 21, stroke = 0,
position = position_jitterdodge(jitter.width = 0.2)) +
geom_linerange(data = df2, aes(ymin=VALUE-sd, ymax=VALUE+sd),
position=position_dodge(width = .75)) +
geom_point(data = df2, aes(y = VALUE), size = 3,
position = position_dodge(width = 0.75)) +
scale_color_jco() +
scale_fill_npg() +
labs(x = '', y = 'Values\n') +
theme_classic(base_size = 14) +
theme(legend.title = element_blank(),
legend.position = "top")
p2 <- ggerrorplot(df, x = "GROUP", y = "VALUE",
desc_stat = "mean_sd",
add = c("jitter"),
color = "TEST",
palette = "jco",
add.params = list(size = 0.2),
order = c('Group1','Group2','Group1 and Group2')
) +
labs(x = '', y = 'Values\n') +
theme(legend.title = element_blank())
cowplot::plot_grid(p1, p2, nrow = 1, ncol = 2, labels = "AUTO")