Table below x axis in ggplot - r

Hello everyone I was trying to add some text below the x axis in ggplot2 and I was able to do so using geom_textand with help of coord_cartesian but I couldn't make it reproducible as this need to run in a loop. I thought that adding the values I want with the row names (First, Second) in a table would fix it, does anybody have experience in that. below is the workaround I did. Thank you very much in advance.
## Data
Grade <- 1 : 20
Case <- rep(paste('case' , 1:5,sep = ''),4)
Number <- paste('n', 1:20 , sep = '')
Class <- c(rep('Class1',5) , rep('Class2',5) , rep('Class3',5) , rep('Class4',5))
se <- 0.2
df <- data.frame(Grade,Case ,Number, Class , se)
## plot
ggplot(df, aes(x= factor(Case , levels = c('case1','case2' , 'case3' , 'case4','case5')) , y=Grade ,
fill= Grade)) +
geom_bar(position="dodge", stat="identity",
colour="black",
size=.4) +
geom_errorbar(aes(ymin=Grade +se, ymax=Grade +se),
size=.3,
width=.2,
position=position_dodge(.9))+
geom_linerange(aes(ymin = Grade , ymax = Grade +se),position=position_dodge(.9))+
geom_text(aes(label=Number , y = Grade + se + 1),data=df, position=position_dodge(0.9), size= 4) +
ggtitle('Place a table below x axis')+
facet_grid(~Class) +
xlab('') +
ylab('Case Num') +
theme_gray()+
theme(plot.margin = unit(c(1,1,1,6), "lines"),
axis.text.x = element_text(size = 15)) +
scale_x_discrete(labels = paste(1:5 , '\n' , 10:15, sep = '')) +
geom_text(data = df[df$Class == 'Class1',],x = -1 , y = -3,
label= 'First\nSecond' , size = 4)+
coord_cartesian(clip = "off" , xlim = c(1, 5) )
EDIT:
Sorry for the confusion,although the solution suggested by #stefan is pretty much convenient but the main purpose is to have something like this:
considering that the proposed table will contain external characters, not taken from the data frame at all (if possible!).

As an alternative approach to tackle this problem I simply set up the table as a second ggplot which I glue together with the major ggplot using patchwork.
## Data
Grade <- 1 : 20
Case <- rep(paste('case' , 1:5,sep = ''),4)
Number <- paste('n', 1:20 , sep = '')
Class <- c(rep('Class1',5) , rep('Class2',5) , rep('Class3',5) , rep('Class4',5))
se <- 0.2
df <- data.frame(Grade,Case ,Number, Class , se)
library(patchwork)
library(ggplot2)
library(tidyr)
library(dplyr)
## plot
p1 <- ggplot(df, aes(x= factor(Case , levels = c('case1','case2' , 'case3' , 'case4','case5')) , y=Grade ,
fill= Grade)) +
geom_bar(position="dodge", stat="identity",
colour="black",
size=.4) +
geom_errorbar(aes(ymin=Grade +se, ymax=Grade +se),
size=.3,
width=.2,
position=position_dodge(.9))+
geom_linerange(aes(ymin = Grade , ymax = Grade +se),position=position_dodge(.9))+
geom_text(aes(label=Number , y = Grade + se + 1),data=df, position=position_dodge(0.9), size= 4) +
ggtitle('Place a table below x axis')+
facet_grid(~Class) +
xlab(NULL) +
ylab('Case Num') +
theme_gray()+
theme(axis.text.x = element_blank())
p2 <- df %>%
mutate(First = as.integer(stringr::str_extract(Case, "\\d")),
Second = First + 9,
Third = Second + 9) %>%
pivot_longer(c(First, Second, Third), names_to = "layer", values_to = "label") %>%
ggplot(aes(x = Case)) +
geom_text(aes(y = factor(layer, c("Third", "Second", "First")), label = label)) +
labs(y = "", x = NULL) +
theme_minimal() +
theme(axis.line = element_blank(), axis.ticks = element_blank(), axis.text.x = element_blank(),
panel.grid = element_blank(), strip.text = element_blank()) +
facet_grid(~Class)
p1 / p2 + plot_layout(heights = c(8, 1))
Created on 2020-05-23 by the reprex package (v0.3.0)
EDIT: Tweak to get a more table like output by adding a geom_tile and removing the spacing between facets as well as setting expansion of x-axis to zero:
p2 <- df %>%
select(Case, Class) %>%
mutate(First = letters[1:nrow(.)],
Second = LETTERS[1:nrow(.)],
Third = as.character(1:nrow(.))) %>%
pivot_longer(c(First, Second, Third), names_to = "layer", values_to = "label") %>%
ggplot(aes(x = Case, y = factor(layer, c("Third", "Second", "First")))) +
# Add Table Style
geom_tile(fill = "blue", alpha = .4, color = "black") +
geom_text(aes(label = label)) +
# Remove expansion of axsis
scale_x_discrete(expand = expansion(mult = c(0, 0))) +
labs(y = "", x = NULL) +
theme_minimal() +
theme(axis.line = element_blank(), axis.ticks = element_blank(), axis.text.x = element_blank(),
panel.grid = element_blank(), strip.text = element_blank(), panel.spacing.x = unit(0, "mm")) +
facet_grid(~Class)
p1 / p2 + plot_layout(heights = c(8, 1))
Created on 2020-05-24 by the reprex package (v0.3.0)

If I understand your requirement correctly, (as in my comment above), this may help you. You just need to name your graph and add the labels in loop and render outside the loop.
...
theme(plot.margin = unit(c(1,1,1,6), "lines"),
axis.text.x = element_text(size = 15)) +
scale_x_discrete(labels = paste(1:5 , '\n' , 10:15, sep = '')) +
coord_cartesian(clip = "off" , xlim = c(1, 5) )
label = NULL
ordinal <- c('first','second','third','fourth','fifth','sixth','seventh','eighth','ninth','tenth')
for (i in 1:5) {
label <- paste(label, '\n', ordinal[i])
}
g1 <- g1 + geom_text(data = df[df$Class == 'Class1',],x = -1 , y = -3,
label= label , size = 4)
g1
This is what I get as a result:

Related

Displaying R plots in a 1x4 grid, using a shared y-axis

I am trying to display some graphs in a 1x4 grid, but I would like all the graphs to have the same x and y axes.
time maxhgs.sleep_LIPA maxhgs.sed_LIPA maxhgs.stand_LIPA maxhgs.MVPA_LIPA maxhgs.LIPA_MVPA
1 5 0.08289621 0.03241295 0.1129983 0.112998341 -0.01928050
2 10 0.16289049 0.06139545 0.2236818 -0.006728721 -0.04950022
3 15 0.24025861 0.08721203 0.3323473 -0.047756360 -0.08927656
4 20 0.31524160 0.11009218 0.4392581 -0.144261526 -0.13791276
5 25 0.38805152 0.13023596 0.5446498 -0.424789999 -0.19517306
6 30 0.41660977 0.13756729 0.5864293 -0.934884300 -0.26117695
This is the data I am working with.
library(ggplot2)
library(egg)
maxhgs.a <- ggplot(maxhgs.df, aes(time, maxhgs.sleep_LIPA)) + geom_point()+geom_line()
maxhgs.a <- maxhgs.a + scale_x_continuous(name = "Time Reallocated", breaks = seq(5,30, by=5)) +
scale_y_continuous(name = "Change in maxhgs", breaks = seq(0,1, by=0.1))+
ggtitle("Sleep to LIPA")
maxhgs.b <- ggplot(maxhgs.df, aes(time, maxhgs.sed_LIPA)) + geom_point()+geom_line()
maxhgs.b <- maxhgs.b + scale_x_continuous(name = "Time Reallocated", breaks = seq(5,30, by=5)) +
scale_y_continuous(name = "Change in maxhgs", breaks = seq(0,1, by=0.1))+
ggtitle("Sedentary to LIPA")
maxhgs.c <- ggplot(maxhgs.df, aes(time, maxhgs.stand_LIPA)) + geom_point()+geom_line()
maxhgs.c <- maxhgs.c + scale_x_continuous(name = "Time Reallocated", breaks = seq(5,30, by=5)) +
scale_y_continuous(name = "Change in maxhgs", breaks = seq(0,1, by=0.1))+
ggtitle("Standing to LIPA")
maxhgs.d <- ggplot(maxhgs.df, aes(time, maxhgs.MVPA_LIPA)) + geom_point()+geom_line()
maxhgs.d <- maxhgs.d + scale_x_continuous(name = "Time Reallocated", breaks = seq(5,30, by=5)) +
scale_y_continuous(name = "Change in maxhgs", breaks = seq(0.5,-1, by=-0.1))+
ggtitle("MVPA to LIPA")
ggarrange(maxhgs.a,
maxhgs.b +
theme(axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
axis.title.y = element_blank() ),
maxhgs.c +
theme(axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
axis.title.y = element_blank() ),
maxhgs.d +
theme(axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
axis.title.y = element_blank() ),
nrow = 1)
This is what I have attempted so far. This actually "works" in that all the graphs have the same y-axis, but the y-axis doesn't actually reflect what should be on the graphs. As you can see in the graph, the y-axis goes from 0.1 to 0.4, but the maxhgs.d graph should extend from 0.1 to -0.9.
Any advice or suggestions would be greatly appreciated!
You can make this much easier by reshaping your data and using faceting. That way, you only need to define a single plot. This requires you to pivot_longer and change the factor levels to the names you want for each facet, but once this is done, the plot itself is straightforward:
library(ggplot2)
library(dplyr)
# Define the label names for the facets first
labs <- c("LIPA to MVPA", "MVPA to LIPA", "Sedentary to LIPA",
"Sleep to LIPA", "Standing to LIPA")
gg <- maxhgs.df %>%
tidyr::pivot_longer(cols = -1) %>%
mutate(plot = factor(`levels<-`(factor(name), labs), labs[c(4, 3, 5, 2, 1)])) %>%
ggplot(aes(x = time, y = value)) +
geom_line() +
geom_point() +
scale_x_continuous(name = "Time Reallocated") +
scale_y_continuous(name = "Change in maxhgs") +
theme(strip.background = element_blank(),
strip.text = element_text(size = 13))
Now we can either choose to plot with fixed y axes:
gg + facet_grid(.~plot, scale = "fixed")
or with flexible y axes:
gg + facet_wrap(.~plot, scale = "free_y", ncol = 5)
Created on 2020-08-04 by the reprex package (v0.3.0)

side-by-side histogram with different data size | R using ggplot2

I was working with ggplot2 and especially histogram, I have 3 different histograms each with different size (1st: n = 12, 2nd: n = 11, 3rd: n = 13).
I combined them using grid.arrange(g1, g2, g3, ncol = 1) which's fine.
But to be more comparative, I need to put them together (side-by-side) like this plot (with a percentage in my case as y-axis)
* Note I have different sizes
This is my code:
library(ggplot2)
P<-read.table("try11.txt", sep = "", header = F)
N<-read.table("try22.txt", sep = "", header = F)
D<-read.table("try33.txt", sep = "", header = F)
# Converted into list
Ps = unlist(P)
Non = unlist(N)
Ds = unlist(D)
dat1 <- data.frame(dens1 = c(Ps), lines1 = rep(c("A"), by = length(Ps)))
dat2 <- data.frame(dens2 = c(Ds), lines2 = rep(c("B"), by = length(Ds)))
dat3 <- data.frame(dens3 = c(Non), lines3 = rep(c("C"), by = length(Non)))
dat1$veg <- 'A'
dat2$veg <- 'B'
dat3$veg <- 'C'
colnames(dat1) <- c("x", "Y")
colnames(dat2) <- c("x", "Y")
colnames(dat3) <- c("x", "Y")
# Plot each histogram
g1 <- ggplot(dat1, aes(dat1$x, fill = dat1$Y)) +
geom_histogram(bins = 150, alpha = 0.3, color = "orange",
aes(y = (..count..)/sum(..count..)), position = 'identity') +
scale_x_continuous(trans='log10') +
scale_y_continuous(labels = percent, limits = c(0,1)) +
labs(x = "", y = "") +
theme_bw() +
theme(panel.border = element_rect(colour = "black"),
panel.grid.minor = element_blank(),
axis.line = element_line(colour = "black"),
legend.title = element_blank())
g2 <- ggplot(dat2, aes(dat2$x, fill = dat2$Y)) +
geom_histogram(bins = 150,alpha = 0.3, color="purple", aes(y = (..count..)/sum(..count..)),
position = 'identity') +
scale_x_continuous(trans = 'log10') +
scale_y_continuous(labels = percent, limits = c(0,1)) +
labs(x = "") +
theme_bw() +
theme(panel.border = element_rect(colour = "black"),
panel.grid.minor = element_blank(),
axis.line = element_line(colour = "black"),
legend.title=element_blank())
g3 <- ggplot(dat3, aes(dat3$x, fill = dat3$Y)) +
geom_histogram(bins = 150,alpha = 0.3, color="black",
aes(y = (..count..)/sum(..count..)), position = 'identity') +
scale_x_continuous(trans = 'log10') +
scale_y_continuous(labels = percent, limits = c(0,1)) +
labs(x="X Values", y="") +
theme_bw() +
theme(panel.border = element_rect(colour = "black"),
panel.grid.minor = element_blank(),
axis.line = element_line(colour = "black"),
legend.title = element_blank())
library(gridExtra)
grid.arrange(g1, g2, g3, ncol = 1)
And here is my input files:
try11.txt:
2.98669E-06
3.37203E-06
7.0028E-06
8.50885E-06
8.71491E-06
8.9869E-06
9.59295E-06
9.96175E-06
9.97605E-06
1.00225E-05
9.59295E-06
9.59295E-06
try22.txt:
6.07E-09
1.07E-08
1.18E-08
1.41E-08
1.57E-08
1.57E-08
1.68E-08
1.75E-08
1.77E-08
1.95E-08
1.77E-08
try33.txt:
1.93E-07
2.25E-07
2.84E-07
3.00E-07
3.38E-07
4.33E-07
4.87E-07
5.20E-07
5.23E-07
5.46E-07
5.23E-07
4.33E-07
2.84E-07
And this what I got:
I'm new to R to know those more complicated functionalities, any help will be appreciated.
Not sure if that's what you mean:
require(tidyverse)
options(scipen = 999)
df1 <- data.frame(x = c(2.98669e-06, 3.37203e-06, 7.0028e-06, 8.50885e-06,
8.71491e-06, 8.9869e-06, 9.59295e-06, 9.96175e-06,
9.97605e-06, 1.00225e-05, 9.59295e-06, 9.59295e-06))
df2 <- data.frame(x = c(6.07e-09, 1.07e-08, 1.18e-08, 1.41e-08, 1.57e-08,
1.57e-08, 1.68e-08, 1.75e-08, 1.77e-08, 1.95e-08,
1.77e-08))
df3 <- data.frame(x = c(1.93E-07, 2.25E-07, 2.84E-07, 3.00E-07, 3.38E-07,
4.33E-07, 4.87E-07, 5.20E-07, 5.23E-07, 5.46E-07,
5.23E-07, 4.33E-07, 2.84E-07))
rbind(df1 %>%
mutate(var = "df1"),
df2 %>%
mutate(var = "df2"),
df3 %>%
mutate(var = "df3")) %>%
ggplot(aes(x, group = var, color = var,
fill = var, alpha = 0.2))+
geom_histogram(aes(y = (..count..)/sum(..count..))) +
scale_y_continuous(labels= scales::percent)
If you want all histograms to be side-by-side as shown in the first image you can use three geom_histogram() with different data argument each time:
# first load all your datasets
try11 = data.frame(x = c(2.98669e-06, 3.37203e-06, 7.0028e-06, 8.50885e-06,
8.71491e-06, 8.9869e-06, 9.59295e-06, 9.96175e-06,
9.97605e-06, 1.00225e-05, 9.59295e-06, 9.59295e-06))
try22 = data.frame(x = c(6.07e-09, 1.07e-08, 1.18e-08, 1.41e-08, 1.57e-08,
1.57e-08, 1.68e-08, 1.75e-08, 1.77e-08, 1.95e-08,
1.77e-08))
try33 = data.frame(x = c(1.93E-07, 2.25E-07, 2.84E-07, 3.00E-07, 3.38E-07,
4.33E-07, 4.87E-07, 5.20E-07, 5.23E-07, 5.46E-07,
5.23E-07, 4.33E-07, 2.84E-07))
# plot the histogram
library("ggplot2")
ggplot() +
aes(x = x) +
geom_histogram(data = try11, fill = "darkblue") +
geom_histogram(data = try22, fill = "darkred") +
geom_histogram(data = try33, fill = "darkgreen")
Or you can provide a single data.frame with a fill attribute in a single column like this:
# Add column in datasets
try11$type = "try11"
try22$type = "try22"
try33$type = "try33"
# Combine the three data.frame
total_try = rbind(try11, try22, try33)
# plot histogram
ggplot(total_try, aes(x = x, fill = type)) +
geom_histogram()

R: Aligning/Sizing for plot_grid in cowplot?

I'm having trouble with the sizing and aligning of one my plots using the plot_grid function in the cowplot package. The bottom left plot always seems to be a tad bit smaller then the others. I did some researching and couldn't seem to find anything that works. I'm new to R, so any help would be greatly appreciated! Thanks!
Attached is my code as well as what the plot is looking like and what I want it to look like
'#Data frame with huc results for each parameter
parameter_results <- readRDS("param_results_2014.RDS") %>% select(1:84)
#list of parameter names
parameters <- sort(readRDS("parameters.RDS"))
blank_theme <- theme_minimal()+ theme(
axis.title.x = element_blank(),
plot.margin = unit(c(0,0,0,0), "pt"),
axis.title.y = element_blank(),
panel.border = element_blank(),
legend.position=c(.5,.02),
legend.direction="horizontal",
legend.key=element_rect(colour="black",size=0.5,linetype="solid"),
panel.grid=element_blank(),
axis.ticks = element_blank(),
plot.title= element_text(size=8, vjust=-4.0, face="bold")
)
#Function for creating poroportions table for parameters
parameter_summary <-function(parameter) {
parameter_df <- parameter_results %>%
select(results = parameter) %>% #keep only column for the parameter you want to plot
filter(results != "Not Applicable") %>% #filters out 'not applicable' results
count(results) %>% #
mutate(prop = prop.table(n), perc = paste0(round(prop * 100),"%"))
return(parameter_df)
}
parameter_pie_chart <- function(parameter,title="",nudgex=5,nudgey=-10) {
# parameter: the parameter you want to create a pie chart for, example: 'DO'
# title: plot title, default is the name of the parameter
parameter_df <- parameter_summary(parameter)
#data frame of proportions less than 10%. necessary because for these values, labels are implemented with an arrow
small_perc <- parameter_df %>% filter(prop < .10)
#dataframe of proportions greater than 10%
signif_perc <- parameter_df %>% filter(prop >= .10)
pie_chart <- ggplot(parameter_df, aes(x = "", y = n, fill = fct_inorder(results))) +
geom_bar(stat = "identity", width = 1,colour='black') +
coord_polar(theta = "y") +
blank_theme +
theme(axis.text.x=element_blank()) +
theme(legend.title=element_blank()) +
#ggtitle(title)+
theme(plot.title = element_text(hjust = 0.5)) +
geom_text(data = signif_perc, aes(label = perc),
position = position_stack(vjust = .5), size = 5, show.legend = F) +
scale_fill_manual(values = c("Attaining" = "#99FF99","Insufficient Information" = "#FFFF99", "Non Attaining" = "#FF9999", "Not Applicable" = "orange"),labels=c("Attaining ",
"Insufficient Information ",
"Non Attaining "))
if (sum(parameter_df$prop < .10) > 0) {
pie_chart <- pie_chart + geom_text_repel(data = small_perc, aes(label = perc), size= 5, show.legend = F, nudge_x = nudgex,nudge_y = nudgey)
}
pie_chart
}
#Indivdual pie charts to create combined pie charts
pie_do <- parameter_pie_chart('DO')
pie_TP<-parameter_pie_chart('Total Phosphorus')
pie_temp<-parameter_pie_chart('Temperature')
pie_pH<-parameter_pie_chart('pH')
pie_arcs<-parameter_pie_chart('Arsenic-HH')
pie_TDS<-parameter_pie_chart('Total Dissolved Solids')
pie_causebio<-parameter_pie_chart('Biological (Cause Unknown)')
pie_human_lead<-parameter_pie_chart('Lead-HH - DWS')
pie_mercury<-parameter_pie_chart('Mercury-HH')
pie_nitrate<-parameter_pie_chart('Nitrate')
pie_aluminum <- parameter_pie_chart("Aluminum")
pie_temp_trout<-parameter_pie_chart('Temperature Trout')
pie_do_trout<-parameter_pie_chart('DO Trout')
pie_fish_merc<-parameter_pie_chart('Fish-Mercury')
pie_fish_ddt<-parameter_pie_chart('Fish-DDx')
pie_fish_dioxin<-parameter_pie_chart('Fish-Dioxin')
pie_fish_chlordane<-parameter_pie_chart('Fish-Chlordane')
pie_fish_pcb<-parameter_pie_chart('Fish-PCB')
pie_human_arsenic<-parameter_pie_chart('Arsenic-HH')
pie_TDS<-parameter_pie_chart('Total Dissolved Solids')
pie_arsenic_dws<-parameter_pie_chart('Arsenic HH - DWS')
pie_trout_do<-parameter_pie_chart('DO Trout')
pie_unknown_trout<-parameter_pie_chart('Biological Trout (Cause Unknown)')
pie_ecoli<-parameter_pie_chart('e.Coli')
pie_enterococcus<-parameter_pie_chart('Enterococcus')
pie_beach_enterococcus<-parameter_pie_chart('Beach Closing (Enterococcus)')
##Figure 2.10
combined_plot1 <- plot_grid(pie_human_arsenic + theme(legend.position="none"),
pie_TDS + theme(legend.position = "none"),
pie_human_lead + theme(legend.position = "none"),
pie_mercury + theme(legend.position = "none"),
pie_nitrate + theme(legend.position = "bottom"),
nrow = 2,ncol=3,align="hv",labels=c("Arsenic,human health","TDS","Lead,human health","Mercury,human health","Nitrate"),label_fontface="bold",label_size=10,hjust=-0.3,vjust=9)+
draw_label("Figure 2.10:Assessment Results for Key Parameters Associated with Water Supply Use,\nPercent(%) of 826 AUs",fontface="bold",hjust=0.5,vjust=-14.5)
ggsave(filename="Figure2.10-Water Supply Use.pdf",path="V:/lum/WM&S/BEAR (Bureau of Environmental Analysis and Restoration)/Envpln/Hourly Employees/KevinZolea/Rwork/2014IR/PieCharts",width=11.5,height=11)
`
Plot that I have:
Plot I Want:

How to add axis text in this negative and positive bars differently using ggplot2?

I've drawed bar graph with negative and positive bars which is familiar to the research. However, my code seems extremely inconvenient and verbose usinggraphics::plot() and graphics::text() as showed below. Try as I may, I could find the solution using element_text to fulfill in ggplot2. Please help or try to give some ideas how to achieve this in ggplot2.Thanks in advance.
# my data
df <- data.frame(genus=c("Prevotella","Streptococcus","YRC22","Phascolarctobacterium","SMB53","Epulopiscium",
"CF231","Anaerovibrio","Paludibacter","Parabacteroides","Desulfovibrio","Sutterella",
"Roseburia","Others__0_5_","Akkermansia","Bifidobacterium","Campylobacter","Fibrobacter",
"Coprobacillus","Bulleidia","f_02d06","Dorea","Blautia","Enterococcus","Eubacterium",
"p_75_a5","Clostridium","Coprococcus","Oscillospira","Escherichia","Lactobacillus"),
class=c(rep("groupA",18),rep("groupB",13)),
value=c(4.497311,4.082377,3.578472,3.567310,3.410453,3.390026,
3.363542,3.354532,3.335634,3.284165,3.280838,3.218053,
3.071454,3.026663,3.021749,3.004152,2.917656,2.811455,
-2.997631,-3.074314,-3.117659,-3.151276,-3.170631,-3.194323,
-3.225207,-3.274281,-3.299712,-3.299875,-3.689051,-3.692055,
-4.733154)
)
# bar graph
tiff(file="lefse.tiff",width=2000,height=2000,res=400)
par(mar=c(5,2,1,1))
barplot(df[,3],horiz=T,xlim=c(-6,6),xlab="LDA score (log 10)",
col=c(rep("forestgreen",length(which(df[,2]=="groupA"))),
rep("goldenrod",length(which(df[,2]=="groupB")))))
axis(1,at=seq(-6,6,by=1))
# add text
text(0.85,36.7,label=df[,1][31],cex=0.6);text(0.75,35.4,label=df[,1][30],cex=0.6)
text(0.75,34.1,label=df[,1][29],cex=0.6);text(0.85,33.0,label=df[,1][28],cex=0.6)
text(0.75,31.8,label=df[,1][27],cex=0.6);text(0.6,30.6,label=df[,1][26],cex=0.6)
text(0.8,29.5,label=df[,1][25],cex=0.6);text(0.85,28.3,label=df[,1][24],cex=0.6)
text(0.45,27.1,label=df[,1][23],cex=0.6);text(0.4,25.9,label=df[,1][22],cex=0.6)
text(0.55,24.7,label=df[,1][21],cex=0.6);text(0.55,23.5,label=df[,1][20],cex=0.6)
text(0.85,22.3,label=df[,1][19],cex=0.6);text(-0.75,21.1,label=df[,1][18],cex=0.6)
text(-1,19.9,label=df[,1][17],cex=0.6);text(-1,18.8,label=df[,1][16],cex=0.6)
text(-0.85,17.6,label=df[,1][15],cex=0.6);text(-0.85,16.3,label=df[,1][14],cex=0.6)
text(-0.7,15.1,label=df[,1][13],cex=0.6);text(-0.65,13.9,label=df[,1][12],cex=0.6)
text(-0.85,12.7,label=df[,1][11],cex=0.6);text(-1.05,11.5,label=df[,1][10],cex=0.6)
text(-0.85,10.3,label=df[,1][9],cex=0.6);text(-0.85,9.1,label=df[,1][8],cex=0.6)
text(-0.47,7.9,label=df[,1][7],cex=0.6);text(-0.85,6.7,label=df[,1][6],cex=0.6)
text(-0.49,5.5,label=df[,1][5],cex=0.6);text(-1.44,4.3,label=df[,1][4],cex=0.6)
text(-0.49,3.1,label=df[,1][3],cex=0.6);text(-0.93,1.9,label=df[,1][2],cex=0.6)
text(-0.69,0.7,label=df[,1][1],cex=0.6)
# add lines
segments(0,-1,0,40,lty=3,col="grey")
segments(2,-1,2,40,lty=3,col="grey")
segments(4,-1,4,40,lty=3,col="grey")
segments(6,-1,6,40,lty=3,col="grey")
segments(4,-1,4,40,lty=3,col="grey")
segments(-2,-1,-2,40,lty=3,col="grey")
segments(-4,-1,-4,40,lty=3,col="grey")
segments(-6,-1,-6,40,lty=3,col="grey")
legend("topleft",bty="n",cex=0.65,inset=c(0.01,-0.02),ncol=2,
legend=c("groupA","groupB"),
col=c("forestgreen", "goldenrod"),pch=c(15,15))
dev.off()
Here's a solution using dplyr to create some extra columns for the label position and the justification, and then theming the plot to match reasonably closely what you originally had:
library("dplyr")
library("ggplot2")
df <- df %>%
mutate(
genus = factor(genus, levels = genus[order(value, decreasing = TRUE)]),
label_y = ifelse(value < 0, 0.2, -0.2),
label_hjust = ifelse(value < 0, 0, 1)
)
my_plot <- ggplot(df, aes(x = genus, y = value, fill = class)) +
geom_bar(stat = "identity", col = "black") +
geom_text(aes(y = label_y, label = genus, hjust = label_hjust)) +
coord_flip() +
scale_fill_manual(values = c(groupA = "forestgreen", groupB = "goldenrod")) +
theme_minimal() +
theme(axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
axis.title.y = element_blank(),
legend.position = "top",
legend.justification = 0.05,
legend.title = element_blank(),
panel.grid.major.y = element_blank(),
panel.grid.minor.y = element_blank(),
panel.grid.major.x = element_line(colour = "grey80", linetype = "dashed"),
panel.grid.minor.x = element_blank()) +
scale_y_continuous(expression(log[10](italic("LDA score"))),
breaks = -6:6, limits = c(-6, 6))
print(my_plot)
ggsave("lefse.tiff", width = 5, height = 5, dpi = 400, my_plot)
I would try this:
library(ggplot2)
# change the factor levels so it will be displayed in correct order
df$genus <- factor(df$genus, levels = as.character(df$genus))
ggplot(df, aes(x = genus, y = value)) +
geom_bar(aes(fill = class), stat = 'identity') + # color by class
coord_flip() + # horizontal bars
geom_text(aes(y = 0, label = genus, hjust = as.numeric(value > 0))) + # label text based on value
theme(axis.text.y = element_blank())
In the above, hjust will change the direction of the text relative to its y position (flipped to x now), which is similar to pos parameter in base R plot. So you code could also be simplified with a vector for pos argument to text function.
Two options:
library(ggplot2)
# my data
df <- data.frame(genus=c("Prevotella","Streptococcus","YRC22","Phascolarctobacterium","SMB53","Epulopiscium",
"CF231","Anaerovibrio","Paludibacter","Parabacteroides","Desulfovibrio","Sutterella",
"Roseburia","Others__0_5_","Akkermansia","Bifidobacterium","Campylobacter","Fibrobacter",
"Coprobacillus","Bulleidia","f_02d06","Dorea","Blautia","Enterococcus","Eubacterium",
"p_75_a5","Clostridium","Coprococcus","Oscillospira","Escherichia","Lactobacillus"),
class=c(rep("groupA",18),rep("groupB",13)),
value=c(4.497311,4.082377,3.578472,3.567310,3.410453,3.390026,
3.363542,3.354532,3.335634,3.284165,3.280838,3.218053,
3.071454,3.026663,3.021749,3.004152,2.917656,2.811455,
-2.997631,-3.074314,-3.117659,-3.151276,-3.170631,-3.194323,
-3.225207,-3.274281,-3.299712,-3.299875,-3.689051,-3.692055,
-4.733154)
)
ggplot(df, aes(reorder(genus, -value), value, fill = class)) +
geom_bar(stat = "identity") +
coord_flip() +
geom_text(aes(label = genus,
y = ifelse(value < 1, 1.5, -1.5)), size = 2.5) +
theme(axis.title.y=element_blank(),
axis.text.y=element_blank(),
axis.ticks.y=element_blank())
Or this:
library(ggplot2)
# my data
df <- data.frame(genus=c("Prevotella","Streptococcus","YRC22","Phascolarctobacterium","SMB53","Epulopiscium",
"CF231","Anaerovibrio","Paludibacter","Parabacteroides","Desulfovibrio","Sutterella",
"Roseburia","Others__0_5_","Akkermansia","Bifidobacterium","Campylobacter","Fibrobacter",
"Coprobacillus","Bulleidia","f_02d06","Dorea","Blautia","Enterococcus","Eubacterium",
"p_75_a5","Clostridium","Coprococcus","Oscillospira","Escherichia","Lactobacillus"),
class=c(rep("groupA",18),rep("groupB",13)),
value=c(4.497311,4.082377,3.578472,3.567310,3.410453,3.390026,
3.363542,3.354532,3.335634,3.284165,3.280838,3.218053,
3.071454,3.026663,3.021749,3.004152,2.917656,2.811455,
-2.997631,-3.074314,-3.117659,-3.151276,-3.170631,-3.194323,
-3.225207,-3.274281,-3.299712,-3.299875,-3.689051,-3.692055,
-4.733154)
)
ggplot(df, aes(reorder(genus, -value), value, fill = class)) +
geom_bar(stat = "identity") +
coord_flip() +
xlab("genus")

Closing the lines in a ggplot2 radar / spider chart

I need a flexible way to make radar / spider charts in ggplot2. From solutions I've found on github and the ggplot2 group, I've come this far:
library(ggplot2)
# Define a new coordinate system
coord_radar <- function(...) {
structure(coord_polar(...), class = c("radar", "polar", "coord"))
}
is.linear.radar <- function(coord) TRUE
# rescale all variables to lie between 0 and 1
scaled <- as.data.frame(lapply(mtcars, ggplot2:::rescale01))
scaled$model <- rownames(mtcars) # add model names as a variable
as.data.frame(melt(scaled,id.vars="model")) -> mtcarsm
ggplot(mtcarsm, aes(x = variable, y = value)) +
geom_path(aes(group = model)) +
coord_radar() + facet_wrap(~ model,ncol=4) +
theme(strip.text.x = element_text(size = rel(0.8)),
axis.text.x = element_text(size = rel(0.8)))
which works, except for the fact that lines are not closed.
I thougth that I would be able to do this:
mtcarsm <- rbind(mtcarsm,subset(mtcarsm,variable == names(scaled)[1]))
ggplot(mtcarsm, aes(x = variable, y = value)) +
geom_path(aes(group = model)) +
coord_radar() + facet_wrap(~ model,ncol=4) +
theme(strip.text.x = element_text(size = rel(0.8)),
axis.text.x = element_text(size = rel(0.8)))
in order to join the lines, but this does not work. Neither does this:
closes <- subset(mtcarsm,variable == names(scaled)[c(1,11)])
ggplot(mtcarsm, aes(x = variable, y = value)) +
geom_path(aes(group = model)) +
coord_radar() + facet_wrap(~ model,ncol=4) +
theme(strip.text.x = element_text(size = rel(0.8)),
axis.text.x = element_text(size = rel(0.8))) + geom_path(data=closes)
which does not solve the problem, and also produces lots of
"geom_path: Each group consist of only one observation. Do you need to
adjust the group aesthetic?"
messages. Som, how do I go about closing the lines?
/Fredrik
Using the new ggproto mechanism available in ggplot2 2.0.0, coord_radar can be defined as:
coord_radar <- function (theta = "x", start = 0, direction = 1)
{
theta <- match.arg(theta, c("x", "y"))
r <- if (theta == "x")
"y"
else "x"
ggproto("CoordRadar", CoordPolar, theta = theta, r = r, start = start,
direction = sign(direction),
is_linear = function(coord) TRUE)
}
Not sure if the syntax is perfect but it is working...
The codes here seem outdated for ggplot2: 2.0.0
Try my package zmisc: devtools:install_github("jerryzhujian9/ezmisc")
After you install it, you will be able to run:
df = mtcars
df$model = rownames(mtcars)
ez.radarmap(df, "model", stats="mean", lwd=1, angle=0, fontsize=0.6, facet=T, facetfontsize=1, color=id, linetype=NULL)
ez.radarmap(df, "model", stats="none", lwd=1, angle=0, fontsize=1.5, facet=F, facetfontsize=1, color=id, linetype=NULL)
if you are curious about what's inside, see my codes at github:
The main codes were adapted from http://www.cmap.polytechnique.fr/~lepennec/R/Radar/RadarAndParallelPlots.html
solution key factor
add duplicated mpg row after melt by rbind
inherit CoordPolar on ggproto
set is_linear = function() TRUE on ggproto
especially is_linear = function() TRUE is important,
since if not you will get plot like this...
with is_linear = function() TRUE settings you can get,
library(dplyr)
library(data.table)
library(ggplot2)
rm(list=ls())
scale_zero_to_one <-
function(x) {
r <- range(x, na.rm = TRUE)
min <- r[1]
max <- r[2]
(x - min) / (max - min)
}
scaled.data <-
mtcars %>%
lapply(scale_zero_to_one) %>%
as.data.frame %>%
mutate(car.name=rownames(mtcars))
plot.data <-
scaled.data %>%
melt(id.vars='car.name') %>%
rbind(subset(., variable == names(scaled.data)[1]))
# create new coord : inherit coord_polar
coord_radar <-
function(theta='x', start=0, direction=1){
# input parameter sanity check
match.arg(theta, c('x','y'))
ggproto(
NULL, CoordPolar,
theta=theta, r=ifelse(theta=='x','y','x'),
start=start, direction=sign(direction),
is_linear=function() TRUE)
}
plot.data %>%
ggplot(aes(x=variable, y=value, group=car.name, colour=car.name)) +
geom_path() +
geom_point(size=rel(0.9)) +
coord_radar() +
facet_wrap(~ car.name, nrow=4) +
theme_bw() +
theme(
axis.title.y = element_blank(),
axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
axis.title.x = element_blank(),
legend.position = 'none') +
labs(title = "Cars' Status")
final result
Sorry, I was beeing stupid. This seems to work:
library(ggplot2)
# Define a new coordinate system
coord_radar <- function(...) {
structure(coord_polar(...), class = c("radar", "polar", "coord"))
}
is.linear.radar <- function(coord) TRUE
# rescale all variables to lie between 0 and 1
scaled <- as.data.frame(lapply(mtcars, ggplot2:::rescale01))
scaled$model <- rownames(mtcars) # add model names as a variable
as.data.frame(melt(scaled,id.vars="model")) -> mtcarsm
mtcarsm <- rbind(mtcarsm,subset(mtcarsm,variable == names(scaled)[1]))
ggplot(mtcarsm, aes(x = variable, y = value)) +
geom_path(aes(group = model)) +
coord_radar() + facet_wrap(~ model,ncol=4) +
theme(strip.text.x = element_text(size = rel(0.8)),
axis.text.x = element_text(size = rel(0.8)))
It turns out than geom_polygom still produces a polygon in the polar coordinates so that
# rescale all variables to lie between 0 and 1
scaled <- as.data.frame(lapply(mtcars, ggplot2:::rescale01))
scaled$model <- rownames(mtcars) # add model names as a variable
# melt the dataframe
mtcarsm <- reshape2::melt(scaled)
# plot it as using the polygon geometry in the polar coordinates
ggplot(mtcarsm, aes(x = variable, y = value)) +
geom_polygon(aes(group = model), color = "black", fill = NA, size = 1) +
coord_polar() + facet_wrap( ~ model) +
theme(strip.text.x = element_text(size = rel(0.8)),
axis.text.x = element_text(size = rel(0.8)),
axis.ticks.y = element_blank(),
axis.text.y = element_blank()) +
xlab("") + ylab("")
works perfectly...
Thank you guys for the help but it did not cover all of my needs. I used two series of data to be compared so I took the subset of mtcars for Mazda:
nobody mentioned about order of the x variable and ggplot2 sorts this variable for the plot but does not sort the data and it made my chart wrong at the first attempt. Apply sorting function for me it was dplyr::arrange(plot.data, x.variable.name)
I needed to annotate the chart with values and ggplot2::annotate() works fine but it was not included in the recent answers
the above code did not work fine for my data until adding ggplot2::geom_line
Finally this code chunk did my chart:
scaled <- as.data.frame(lapply(mtcars, ggplot2:::rescale01))
scaled$model <- rownames(mtcars)
mtcarsm <- scaled %>%
filter(grepl('Mazda', model)) %>%
gather(variable, value, mpg:carb) %>%
arrange(variable)
ggplot(mtcarsm, aes(x = variable, y = value)) +
geom_polygon(aes(group = model, color = model), fill = NA, size = 1) +
geom_line(aes(group = model, color = model), size = 1) +
annotate("text", x = mtcarsm$variable, y = (mtcarsm$value + 0.05), label = round(mtcarsm$value, 2), size = 3) +
theme(strip.text.x = element_text(size = rel(0.8)),
axis.text.x = element_text(size = rel(1.2)),
axis.ticks.y = element_blank(),
axis.text.y = element_blank()) +
xlab("") + ylab("") +
guides(color = guide_legend()) +
coord_radar()
Hopefully usefull for somebody

Resources