ggplot bar chart does not show correctly on Shiny - r

When I create bar chart below in R, there was no problem but when I convert these code to shiny function, the problem is occur, could you help ?
Bar chart in normal R code:
path <- "WA_Fn-UseC_-HR-Employee-Attrition.csv (job attrition)"
data <-fread(path)
# bar chart function function
Categorical_vs_categorical_plot_2 <- function(data,group_col,fill_col){
data %>%
ggplot(aes_(x = fill_col, group = group_col)) +
geom_bar(aes(y = ..prop.., fill = factor(..x..)),
stat="count",
alpha = 0.7) +
geom_text(aes(label = scales::percent(..prop..), y = ..prop.. ),
stat= "count",
vjust = 2) +
labs(y = "Percentage", fill= "Education") +
facet_grid(~Attrition) +
theme_minimal()+
theme(legend.position = "none", plot.title = element_text(hjust = 0.5)) +
ggtitle("Attrition")
}
Categorical_vs_categorical_plot_2(data,~Attrition,~BusinessTravel)
Normal bar chart
Bar chart convert to shiny code [error occur, not show facet_grid and text value like normal bar chart above] :
output$cat_vs_cat_chart2 <- renderPlot({
data() %>%
#ggplot(aes_(x = input$cat_compare, group = ~Attrition)) +
ggplot(aes_(x = 'BusinessTravel', group = ~Attrition)) +
geom_bar(aes(y = ..prop.., fill = factor(..x..)),
stat="count",
alpha = 0.7) +
geom_text(aes(label = scales::percent(..prop..), y = ..prop.. ),
stat= "count",
vjust = 2) +
#labs(y = "Percentage", fill= "Education") +
facet_grid(~Attrition) +
theme_minimal()+
theme(legend.position = "none", plot.title = element_text(hjust = 0.5)) +
ggtitle("Attrition")
})
Error bar chart

[Update] I got answers by myself:
[version 1] If input column feature directly to bar chart: need to add ~ to each column feature:
output$cat_vs_cat_chart2 <- renderPlot({
data() %>%
ggplot(aes_(x = ~BusinessTravel, group = ~Attrition)) +
geom_bar(aes(y = ..prop.., fill = factor(..x..)),
stat="count",
alpha = 0.7) +
geom_text(aes(label = scales::percent(..prop..), y = ..prop.. ),
stat= "count",
vjust = 2) +
#labs(y = "Percentage", fill= "Education") +
facet_grid(~Attrition) +
theme_minimal()+
theme(legend.position = "none", plot.title = element_text(hjust = 0.5)) +
ggtitle("Attrition")
})
[version 2] If input column feature from input$ in shiny ui : need to use aes_string instead aes_:
output$cat_vs_cat_chart2 <- renderPlot({
data() %>%
ggplot(aes_string(x = input$cat_compare, group = "Attrition")) +
geom_bar(aes(y = ..prop.., fill = factor(..x..)),
stat="count",
alpha = 0.7) +
geom_text(aes(label = scales::percent(..prop..), y = ..prop.. ),
stat= "count",
vjust = 2) +
#labs(y = "Percentage", fill= "Education") +
facet_grid(~Attrition) +
theme_minimal()+
theme(legend.position = "none", plot.title = element_text(hjust = 0.5)) +
ggtitle("Attrition")
})

Related

How to make different patterns and colors in different category of data using ggplot in R?

I would like to make my data have different colors for species and different patterns for sex. However, I can only set to make it different colors according to the sex. Here is my data,
data
This is how I run my script,
#making bar plot
library(readr)
library(ggplot2)
# loading and checking the data
data_summary <- read_csv("trial.csv")
print(data_summary)
# coloured barplot
ggplot(data_summary, aes(x = factor(species), y = mean, fill = sex)) +
geom_bar(stat = "identity", position = "dodge", show.legend = FALSE) +
geom_errorbar(aes(ymin=mean-sd, ymax=mean+sd), position = position_dodge(0.9), width = 0.2, show.legend = FALSE) +
labs(x="", y="") + theme_bw() +
theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank()) +
theme(legend.position = c(0.1, 0.75)) + ylim(0, 80) +
scale_fill_manual(values=c("#870A30","#D3D3D3"))
This can be done using fill = interaction(..,..):
library(ggplot2)
ggplot(data_summary, aes(x = factor(species), y = mean, fill = interaction(species,sex))) +
geom_bar(stat = "identity", position = "dodge", show.legend = FALSE) +
geom_errorbar(aes(ymin=mean-sd, ymax=mean+sd), position = position_dodge(0.9), width = 0.2, show.legend = FALSE) +
labs(x="", y="") +
theme_bw() +
theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank()) +
theme(legend.position = c(0.1, 0.75)) + ylim(0, 80) +
scale_fill_manual(values= c("#870A30", '#009E73', '#CC79A7', "#D3D3D3"))
An option could be using ggplot_build and add a vector of four colors (you change this to what you want) to the fill column of the bars layer like this:
library(ggplot2)
p <- ggplot(data_summary, aes(x = factor(species), y = mean, fill = sex)) +
geom_bar(stat = "identity", position = "dodge", show.legend = FALSE) +
geom_errorbar(aes(ymin=mean-sd, ymax=mean+sd), position = position_dodge(0.9), width = 0.2, show.legend = FALSE) +
labs(x="", y="") + theme_bw() +
theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank()) +
theme(legend.position = c(0.1, 0.75)) + ylim(0, 80) +
scale_fill_manual(values=c("#870A30","#D3D3D3"))
q <- ggplot_build(p)
q$data[[1]]$fill <- c("#870A30","#D3D3D3", '#009E73', '#CC79A7')
q <- ggplot_gtable(q)
plot(q)
Created on 2023-01-02 with reprex v2.0.2
You can use ggpattern to get different patterns per sex and different colors per species:
library(ggplot2)
library(ggpattern)
ggplot(data_summary, aes(x = species, y = mean, fill = species, group = sex)) +
geom_col_pattern(position = "dodge", aes(pattern = sex),
pattern_fill = "white", pattern_color = "white",
pattern_angle = 45, show.legend = FALSE) +
geom_errorbar(aes(ymin=mean-sd, ymax=mean+sd), position = position_dodge(0.9),
width = 0.2, show.legend = FALSE) +
labs(x = NULL, y = NULL) +
theme_classic() +
theme(panel.border = element_rect(linewidth = 0.5, fill = NA)) +
ylim(0, 80) +
scale_fill_manual(values = c("#870A30" ,"#D3D3D3"))
There is a nice package called ggpattern which offers hatching for geoms. Unfortunately it is not available for the R version I am using.
But I would like to offer different alpha values for the fill color.
The alpha itself can defined like scale_alpha_manual(values = c(.5,1)).
library(ggplot2)
data_summary <- read.table(text = "
species,sex,mean,sd,tukey
species_a,female,67,4.17,a
species_b,male,62.2,4.8,a
species_b,female,61.3,6.43,a
species_a,male,49.7,16.2,a
", header = T, sep = ','
)
# coloured barplot
ggplot(data_summary, aes(x = factor(species), y = mean, fill = sex, alpha = species)) +
geom_bar(stat = "identity", position = "dodge", show.legend = FALSE) +
geom_errorbar(aes(ymin=mean-sd, ymax=mean+sd), position = position_dodge(0.9), width = 0.2, show.legend = FALSE) +
labs(x="", y="") + theme_bw() +
theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank()) +
theme(legend.position = c(0.1, 0.75)) + ylim(0, 80) +
scale_fill_manual(values=c("#870A30","#D3D3D3")) +
scale_alpha_manual(values = c(.5,1))

How to change y axis from count to prop?

With ggplot2 and GGally, I created this bar chart with proportions:
ggplot(mtcars, aes(x = factor(cyl), by = 1)) +
geom_bar(fill = "steelblue", stat = "prop") +
geom_text(aes(label = scales::percent(after_stat(prop), accuracy = 1)), stat = "prop", nudge_y = 0.5) +
theme_minimal() +
theme(aspect.ratio = 1.5)
However, on the y axis, I would like to change that to reflect the percentages on the bars. I would like to avoid hard coding the values like ylim = "40", but let it use the values in the chart.
Try this:
ggplot(mtcars, aes(x = cyl)) +
geom_bar(aes(y = ..prop..), fill = "steelblue", stat = "count") +
geom_text(aes(label = scales::percent(..prop..), y = ..prop.. ), stat= "count", vjust = -.5) +
ylim(0, 0.5) +
ylab("") +
theme_minimal() +
theme(aspect.ratio = 1.5)
Edit: if you want a factor on x axis try
ggplot(mtcars, aes(x = factor(cyl))) +
geom_bar(aes(y = (..count..)/sum(..count..)), fill = "steelblue", stat = "count") +
geom_text(aes(label = scales::percent(round((..count..)/sum(..count..), 2)),
y = ((..count..)/sum(..count..))), stat = "count", vjust = -.25) +
ylim(0, 0.5) +
ylab("") +
theme_minimal() +
theme(aspect.ratio = 1.5)
Edit2: with the GGally package you can use:
ggplot(mtcars, aes(x = factor(cyl), by = 1)) +
geom_bar(aes(y = ..prop..), fill = "steelblue", stat = "prop") +
geom_text(aes(label = scales::percent(..prop..), y = ..prop.. ), stat = "prop", vjust = -.5) +
ylim(0, 0.5) +
ylab("") +
theme_minimal() +
theme(aspect.ratio = 1.5)

Automatically select a more distinctive color pallet for ggplot2

I use the following code to generate a series of plots which include both geom_boxplot and geom_point. I want the points to have more distinctive colors without me defining what they are every time:
for (i in 1:length(Girder.Plot)) {
Plot.Girder <- ggplot(data = subset(Girder.Plot[[i]], Names == "Sample"),
aes(x = Type, y = Moment, fill = factor(Spacing,levels = c("9","12","15")))) +
geom_boxplot(outlier.shape = NA, position = position_dodge(width = 0.75)) +
stat_summary(fun = mean, geom="point", shape=23, size=2,
position = position_dodge(width = 0.75)) +
stat_boxplot(geom='errorbar', linetype=1, width=0.5,
position = position_dodge(width = 0.75)) +
geom_point(data = subset(Girder.Plot[[i]], Names == "No Factor"),
aes(colour = Names), position = position_dodge(width = 0.75)) +
geom_point(data = subset(Girder.Plot[[i]], Names == "Factor 1"),
aes(colour = Names), position = position_dodge(width = 0.75)) +
geom_point(data = subset(Girder.Plot[[i]], Names == "Factor 2"),
aes(colour = Names), position = position_dodge(width = 0.75)) +
geom_point(data = subset(Girder.Plot[[i]], Names == "Factor 3"),
aes(colour = Names), position = position_dodge(width = 0.75)) +
labs(x = element_blank(), y = element_blank(),
title = paste0("Moment Live Load Distribution Factors \n Along the Roadway Width for \n Ultra-Girder Section: UG-"
,str_extract(names(Girder.Plot)[i],"\\d+")),
fill = "Girder Spacing (ft):", colour = element_blank()) +
theme_classic() + ylim(0.4, 1.1) +
theme(plot.title = element_text(hjust = 0.5, margin = margin(45,0,20,0),
face = "bold", size = 18),
legend.title.align = 0.5, legend.position = "bottom",
legend.box.background = element_rect(colour = "black", size = 0.5),
legend.box.margin = margin(0,0,0,0))
print(Plot.Girder)
}
Use scale_fill_brewer/scale_color_brewer.
library(ggplot2)
ggplot(iris, aes(Species, Sepal.Length, fill = Species)) +
geom_boxplot() +
theme_minimal() +
scale_fill_brewer(palette = "Set1")
To see available palettes.
RColorBrewer::display.brewer.all()

Fix Plotly legend position and disable Plotly panel for Shiny in RMarkdown

I am working on RMarkdown report with Shiny elements, using ggplot2 and transforming its charts, using ggplotly.
In a regular RMarkdown report everything works perfect.
ggplotly does not allow you to put a horizontal legend in the bottom, but I still managed to do it, using this answer.
The plot now looks great
The code for this plot is
semiformal_savings_chart <- ggplot(semiformal_savings, aes(x = Country, y =
Percent, fill = Category)) +
geom_bar(stat = 'identity', width = 0.7) +
theme_tufte() +
scale_fill_brewer(palette = "Paired") +
theme(axis.title.y = element_blank()) +
theme(axis.title.x = element_blank()) +
ylim(0, 80) +
theme(legend.text = element_text(size = 12)) +
theme(axis.text.x = element_text(size = 12)) +
theme(axis.text.y = element_text(size = 12)) +
theme(plot.margin = margin(0.1, 0.1, 0.1, 0.1, "cm"))
ggplotly(semiformal_savings_chart) %>% config(displayModeBar = F) %>%
layout(legend = list(orientation = "h", x = 0.4, y = -0.2))
When I put it into Shiny format, I am forced to drop the last two lines of code with ggplotly, which disables the Plotly panel. Just connecting it to ggplot with pipe does not work and I get an error.
Error: no applicable method for 'layout' applied to an object of class "c('theme', 'gg')"
Reactivity works perfect but in Shiny my now my plot has the Plotly panel + legend in on a right, which I do not like.
The Shiny code looks like this
semiformal_savings_data <- reactive({
filter(semiformal_savings,
Country %in% input$Country)
selectInput(inputId = "Country", label = "Please select a
country/countries", choices = unique(semiformal_savings$Country),
selected = unique(semiformal_savings$Country), multiple = TRUE)
plotlyOutput("semiformalsavingsPlot")
output$semiformalsavingsPlot <- renderPlotly({
ggplot(semiformal_savings_data(), aes(x = Country, y = Percent, fill =
Category)) + geom_bar(stat = 'identity', width = 0.7) +
theme_tufte() +
scale_fill_brewer(palette = "Paired") +
theme(axis.title.y = element_blank()) +
theme(axis.title.x = element_blank()) +
ylim(0, 80) +
theme(legend.text = element_text(size = 12)) +
theme(axis.text.x = element_text(size = 12)) +
theme(axis.text.y = element_text(size = 12)) +
theme(plot.margin = margin(0.1, 0.1, 0.1, 0.1, "cm"))
})
But this part is missing now
%>% config(displayModeBar = F) %>% layout(legend = list(orientation = "h",
x = 0.4, y = -0.2))
How to attach this functionality to my almost perfect plot?
Thanks!
Resolved personally
The changes were minor, I still used ggplotly()
g1 <- ggplot(ownership_data(), aes(x = as.character(Year), y = Percent, fill =
Category)) +
geom_bar(stat = 'identity', position = 'stack') + facet_grid(~ Country) +
theme_tufte() +
ylim(0, 100) +
scale_fill_brewer(palette = "Paired") +
theme(axis.title.y = element_blank()) +
theme(axis.title.x = element_blank()) +
theme(legend.text = element_text(size = 13)) +
theme(axis.text.x = element_text(size = 12)) +
theme(axis.text.y = element_text(size = 13)) +
theme(strip.text.x = element_text(size = 12)) +
theme(legend.position = "bottom") +
theme(legend.title = element_blank())
return(ggplotly(g1, tooltip = c("y", "text")) %>% config(displayModeBar = F) %>%
layout(legend = list(orientation = "h", x = 0.4, y = -0.2)))

Pie plot getting its text on top of each other

Just trying to fix this overlapped labeling:
My code:
values=c(164241,179670)
labels=c("Private", "Public")
colors=c("#cccccc", "#aaaaaa")
categoriesName="Access"
percent_str <- paste(round(graph$values / sum(graph$values) * 100,1), "%", sep="")
values <- data.frame(val = graph$values, Type = graph$labels, percent=percent_str )
pie <- ggplot(values, aes(x = "", y = val, fill = Type)) + geom_bar(width = 1) +
geom_text(aes(y = **val + 1**, **hjust=0.5**, **vjust=-0.5**, label = percent), colour="#333333", face="bold", size=10) +
coord_polar(theta = "y") + ylab(NULL) + xlab(NULL) +
scale_fill_manual(values = graph$colors) + labs(fill = graph$categoriesName) +
opts( title = graph$title,
axis.text.x = NULL,
plot.margin = unit(c(0,0,0,0), "lines"),
plot.title = theme_text(face="bold", size=14),
panel.background = theme_rect(fill = "white", colour = NA) )
print(pie)
Tried messing with the values marked with asterisks (** **) but haven't got anywhere.
Any help appreciated.
here is an example:
pie <- ggplot(values, aes(x = "", y = val, fill = Type)) +
geom_bar(width = 1) +
geom_text(aes(y = val/2 + c(0, cumsum(val)[-length(val)]), label = percent), size=10)
pie + coord_polar(theta = "y")
Perhaps this will help you understand how it work:
pie + coord_polar(theta = "y") +
geom_text(aes(y = seq(1, sum(values$val), length = 10), label = letters[1:10]))

Resources