I am trying to use a polar plot to represent frequencies according to a circular angle/direction (0-360 degrees). For some reason I am having problems trying to define the scale in the plot to represent all 3 angles. At the moment only 2 are showing ("B" and "C"). Any help will be appreciated. Thanks in advance,
library(ggplot2)
data <- read.table(text = "stat angle freq perc
A 1 720 79
B 223.5017 121 13
C 117.9372 68 7", header=T)
head(data)
str(data)
db<-data
db$stat<-factor(db$stat)
levels(db$stat)
# Plot
bp<-ggplot(db, aes(x = angle, y = perc), fill = factor(stat)) +
geom_bar(stat="identity", colour="grey100", aes(fill = factor(stat),
width = 16)) +
coord_polar(theta="x", start=0) +
theme_minimal() + ylab("Detections (%)") +
scale_x_continuous("", lim=c(0,360), breaks = seq(0, 315, 45),
labels = c("N","NE","E","SE","S","SW","W","NW"))
bp2<-bp + theme(panel.grid.major = element_line(colour = "grey60", size=0.45),
panel.grid.minor = element_line(colour = "grey60", size=0.45))
Width in geom_bar is the issue. Following works:
ggplot(db) +
geom_bar(stat="identity",
colour="grey100",
aes(x = angle, y = perc, fill = stat, width = 2)) +
coord_polar() +
theme_minimal() +
ylab("Detections (%)")+
scale_x_continuous(limits=c(0,360),
breaks = seq(0, 315, 45),
labels = c("N","NE","E","SE","S","SW","W","NW"))
Related
I created a bar plot to show differences in water accumulation on different sites and layers. Because one value is way higher than the other ones I want to set the y-axis on log10 scale. It all works but the result looks rather unintuitive. is it possible to set the limit of the y-axis to 0 so the bar with the value 0.2 is not going downwards?
Here is the code I used:
p2 <- ggplot(data_summary2, aes(x= Site, y= small_mean, fill= Depth, Color= Depth))+
geom_bar(stat = "identity", position = "dodge", alpha=1)+
geom_errorbar(aes(ymin= small_mean - sd, ymax= small_mean + sd),
position = position_dodge(0.9),width=0.25, alpha= 0.6)+
scale_fill_brewer(palette = "Greens")+
geom_text(aes(label=small_mean),position=position_dodge(width=0.9), vjust=-0.25, hjust= -0.1, size= 3)+
#geom_text(aes(label= Tukey), position= position_dodge(0.9), size=3, vjust=-0.8, hjust= -0.5, color= "gray25")+
theme_bw()+
theme(legend.position = c(0.2, 0.9),legend.direction = "horizontal")+
theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank())+
labs(fill="Depth [cm]")+
theme(axis.text.x = element_text(angle = 25, size =9, vjust = 1, hjust=1))+
scale_x_discrete(labels= c( "Site 1\n(Hibiscus tillaceus)","Site 2 \n(Ceiba pentandra)","Site 3 \n(Clitoria fairchildiana)","Site 4 \n(Pachira aquatica)"))+
#theme(legend.position = c(0.85, 0.7))+
labs(x= "Sites\n(Type of Tree)", y= "µg Deep-Water/ g rhizosphere soil", title = "Average microbial Deep-water incorporation per Site", subtitle = "Changes over Time and Depth")+
facet_grid(.~Time, scale = "free")
p2 + scale_y_continuous(trans = "log10")
This is what the plot looks like:
On a log scale there is no 0, therefore the only sensible place for bars to start from is y = 10^0 or 1.
However you can create a pseudolog scale using scales::pseudo_log_trans to get 0 included on the axis so all the bars go the same direciton. I'm borrowing from this answer. NOTE it's important to add 0 to the breaks to make it clear that this is a pseudolog scale. Compare the two plots below:
library(tidyverse)
library(scales)
# make up data with distribution positive values above and below 1
d <- tibble(grp = LETTERS[1:5],
val = 10^(-2:2))
# normal plot with true log scale doesn't contain 0
d %>%
ggplot(aes(x = grp, y = val, fill = grp)) +
geom_col() +
ggtitle("On True Log Scale Bars Start at y = 1") +
scale_y_log10() # or if you prefer: scale_y_continuous(trans = "log10")
# set range of 'linear' portion of pseudolog scale
sigma <- min(d$val)
# plot on pseudolog to get all bars to extend to 0
d %>%
ggplot(aes(x = grp, y = val, fill = grp)) +
geom_col() +
ggtitle("On Pseudolog Scale Bars Start at y = 0") +
scale_y_continuous(
trans = pseudo_log_trans(base = 10, sigma = sigma),
breaks = c(0, 10^(-2:2)),
labels = label_number(accuracy = 0.01)
)
Created on 2021-12-30 by the reprex package (v2.0.1)
I have graph consisting of several ggplots combined using patchwork. I have made a ggplot only consisting of the y-axis. This works fine, but the facets are not aligned above each. Any ideas as how to make the facets have the same size and be above each other?
Here's the patchwork code:
y_axis + decreasers_p+late_bloomers_p + o2_lovers_p + solo_riders_p + plot_layout(widths = c(1, 10),
guides = "collect",
design =
"12
13
14
15")
And here's some of the ggplot code:
solo_riders_p <- ggplot(solo_riders, aes(x=days_incubated, y=emission))+
geom_point(aes(shape=compound, size=compound, fill=compound)) +
scale_shape_manual(values=c(21, 25))+
scale_size_manual(values=c(2.8, 2.5))+
scale_fill_manual(values=c("black", "grey"))+
labs(fill = "Compound", shape = "Compound", size = "Compound",
x = "Incubation time (days)",
y = "BVOC emission (nmol g-1 loi soil h-1)",
title = "solo_riders") +
theme_bw() +
facet_wrap(vars(jar), scales = "free_y")
y_axis <- ggplot(data.frame(l = decreasers_p$labels$y, x = 1, y = 1)) +
geom_text(aes(x, y, label = l), angle = 90) +
theme_void() +
coord_cartesian(clip = "off")
Here's an example of how I would like it to be (but without the titles above each row):
I would like to create a polar heatmap like the heatmap from the Lancet paper "Height and body-mass index trajectories of school-aged children and adolescents from 1985 to 2019 in 200 countries and territories: a pooled analysis of 2181 population-based studies with 65 million participants":
I appreciate the idea of annotating the age each layer of ring represents (age 5 to 19 years) by creating a fan-shaped opening of the polar heatmap (manually circled in red). I refer to 5-19 as the Y-AXIS LABELS hereafter.
Below is the code from #Cyrus Mohammadian describing how to arrange the positions of Y-AXIS LABELS of polar heatmaps. I replicate Cyrus Mohammadian's code below:
library(grid)
library(gtable)
library(reshape)
library(ggplot2)
library(plyr)
nba <- read.csv("http://datasets.flowingdata.com/ppg2008.csv")
nba$Name <- with(nba, reorder(Name, PTS))
nba.m <- melt(nba)
nba.m <- ddply(nba.m, .(variable), transform, value = scale(value))
# Convert the factor levels (variables) to numeric + quanity to determine size of hole.
nba.m$var2 = as.numeric(nba.m$variable) + 15
# Labels and breaks need to be added with scale_y_discrete.
y_labels = levels(nba.m$variable)
y_breaks = seq_along(y_labels) + 15
nba.labs <- subset(nba.m, variable==levels(nba.m$variable) [nlevels(nba.m$variable)])
nba.labs <- nba.labs[order(nba.labs$Name),]
nba.labs$ang <- seq(from=(360/nrow(nba.labs))/1.5, to=(1.5* (360/nrow(nba.labs)))-360, length.out=nrow(nba.labs))+80
nba.labs$hjust <- 0
nba.labs$hjust[which(nba.labs$ang < -90)] <- 1
nba.labs$ang[which(nba.labs$ang < -90)] <- (180+nba.labs$ang)[which(nba.labs$ang < -90)]
p<-ggplot(nba.m, aes(x=Name, y=var2, fill=value)) +
geom_tile(colour="white") +
geom_text(data=nba.labs, aes(x=Name, y=var2+1.5,
label=Name, angle=ang, hjust=hjust), size=2.5) +
scale_fill_gradient(low = "white", high = "steelblue") +
ylim(c(0, 50)) +
coord_polar(theta="x") +
theme(panel.background=element_blank(),
axis.title=element_blank(),
panel.grid=element_blank(),
axis.text.x=element_blank(),
axis.ticks=element_blank(),
axis.text.y=element_text(size=5))+ theme(axis.title.y=element_blank(),
axis.text.y=element_blank(),
axis.ticks.y=element_blank())
lab = textGrob((paste("G MIN PTS FGM FGA FGP FTM FTA FTP X3PM X3PA X3PP ORB DRB TRB AST STL BLK TO PF")),
x = unit(.1, "npc"), just = c("left"),
gp = gpar(fontsize = 7))
gp = ggplotGrob(p)
gp = gtable_add_rows(gp, unit(10, "grobheight", lab), -1)
gp = gtable_add_grob(gp, lab, t = -2, l = gp$layout[gp$layout$name == "panel",]$l)
grid.newpage()
grid.draw(gp)
This is the resultant figure:
Y-AXIS LABELS are placed at the bottom of the heatmap instead of being positioned immediately next to each layer of ring like the Lancet paper. I therefore ask if it is possible to modify Cyrus Mohammadian's plot so that Y-AXIS LABELS are positioned next to each layer of the ring instead of being presented outside of the heatmap? In addition, it is preferrable that we can control the size of the fan-shaped opening so that we can customize according to length of the Y-AXIS LABEL texts.
A second request is to place the color legend in the center of the heatmap and make it curved. An example is illustrated in the figure below, which is from Fig 3 of the paper "Infectious diseases in children and adolescents in China: analysis of national surveillance data from 2008 to 2017":
Note that the color legend is centrally located and curved. How this could be done?
Thank you.
Here is some example code for how you can shape something like a legend and add it to your plot. Due to some restrictions on annotation_custom() in relation to polar coordinates, I decided to use the devel version of patchwork from github to use the new inset_element() function (devtools::install_github("thomasp85/patchwork")).
library(ggplot2)
library(patchwork)
df <- reshape2::melt(volcano[1:20, 1:20])
breaks <- scales::extended_breaks()(df$value)
breaks <- scales::discard(breaks, range(df$value))
main <- ggplot(df, aes(Var1, Var2, fill = value)) +
geom_tile() +
scale_y_continuous(limits = c(-20, NA)) +
guides(fill = "none") +
coord_polar()
legend <- ggplot() +
geom_tile(
aes(
x = seq(min(df$value), max(df$value), length.out = 255),
y = 1, fill = after_stat(x)
)
) +
annotate(
"text", x = breaks, y = -0.1, label = breaks, size = 3
) +
annotate(
"segment", x = breaks, xend = breaks, y = 0.5, yend = 0.7,
colour = "white", size = 1
) +
annotate(
"segment", x = breaks, xend = breaks, y = 1.5, yend = 1.3,
colour = "white", size = 1
) +
guides(fill = "none") +
scale_y_continuous(limits = c(-2, 2)) +
scale_x_continuous(expand = c(0.1, 0)) +
coord_polar() +
theme_void()
legend <- ggplotGrob(legend)
main + inset_element(legend, 0.3, 0.3, 0.7, 0.7) &
theme(plot.background = element_blank())
Created on 2020-11-06 by the reprex package (v0.3.0)
I'm new to R and I need your help. I need to remove the point number 8, x = "180" from multiple lines geom_line, but remaining at geom_point. What should you do?
Data is in an excel spreadsheet
data<-melt(CB_fechado, id.vars = 'a');
#Ângulo de incidência de vento
#print(data)
Grafico_CB_fechado <- ggplot(data,aes(x =`Ângulo de incidência de vento [°]`, y=`value`, color=`variable`))+
geom_line() + geom_point()+
scale_x_continuous(limits = c(0,180), breaks = c(0,15,30,45,60,75,90,105,120,135,150,165,180))+
scale_y_continuous(limits = c(-1.5,1.5))+
ylab("b")+theme(legend.position = "bottom")+
theme(legend.title = element_blank())
For exemplo
This is about subsetting the data that you use for the geom_line(). Not that this would be a bit more complex if it were not the last point. Here is an example with similar dummy data since I did not want to type in from the image.
dummy data
data <- data.frame(angle = rep(c(0:6*15, 180), 4),
cat = rep(LETTERS[1:4], each = 8),
value = rep(1:4/-4, each = 8))
subset data
Drop points with angle = 180.
data_lines <- data[data$angle != 180,]
graph it
Use data_lines instead of data in geom_line().
library(ggplot2)
ggplot(data, aes(x = angle, y = value, color= cat)) +
geom_line(data = data_lines) +
geom_point()+
scale_x_continuous(limits = c(0,180), breaks = c(0,15,30,45,60,75,90,105,120,135,150,165,180))+
scale_y_continuous(limits = c(-1.5,1.5))+
ylab("b")+theme(legend.position = "bottom")+
theme(legend.title = element_blank())
The trick is to use a subset of the data in the ggplot call. In this case I use subset to remove the point with a = 180.
Note that I redefine the color argument to "red".
library(ggplot2)
ggplot(data, aes(x = a, y = b, color = "red")) +
geom_point()+
geom_line(data = subset(data, a != 180)) +
scale_x_continuous(limits = c(0,180), breaks = c(0,15,30,45,60,75,90,105,120,135,150,165,180))+
scale_y_continuous(limits = c(-1.5,1.5))+
ylab("b") +
theme(legend.position = "bottom",
legend.title = element_blank())
Data.
data <- read.table(text = "
a b
1 0 0.57395085
2 15 0.47593420
3 30 0.30175686
4 45 0.13363012
5 60 -0.02727459
6 75 -0.17971621
7 90 -0.44955122
8 180 -0.30247414
", header = TRUE)
I have an issue when using coord_polar() together with geom_col(). I have degree values ranging from 0 to <360. Let's say there are in steps of 20, so 0, 20, 40... 340. If I plot them with coord_polar() I have two issues:
values 0 and 340 touch each other and don't have the same gap as the other columns
the "x-axis" is offset slightly, so that 0 does not point "north"
See this minimal example.
suppressWarnings(library(ggplot2))
df <- data.frame(x = seq(0,359,20),y = 1)
ninety = c(0,90,180,270)
p <- ggplot(df, aes(x,y)) +
geom_col(colour = "black",fill = "grey") +
geom_label(aes(label = x)) +
scale_x_continuous(breaks = ninety) +
geom_vline(xintercept = ninety, colour = "red") +
coord_polar()
p
If I set the x-axis limits, the rotation of the coordinate system is correct, but the column at 0 disappears due to lack of space.
p+scale_x_continuous(breaks = c(0,90,180,270),limits = c(0,360))
#> Scale for 'x' is already present. Adding another scale for 'x', which
#> will replace the existing scale.
#> Warning: Removed 1 rows containing missing values (geom_col).
Created on 2019-05-15 by the reprex package (v0.2.1)
Since the space occupied by each bar is 20 degrees, you can shift things by half of that in both scales and coordinates:
ggplot(df, aes(x,y)) +
geom_col(colour = "black",fill = "grey") +
geom_label(aes(label = x)) +
scale_x_continuous(breaks = ninety,
limits = c(-10, 350)) + # shift limits by 10 degrees
geom_vline(xintercept = ninety, colour = "red") +
coord_polar(start = -10/360*2*pi) # offset by 10 degrees (converted to radians)
I got it closer to what you want, but it's a bit of a hack so I don't know if it's a great solution.
Code:
df <- data.frame(x = seq(0,359,20),y = 1)
ggplot(df, aes(x+10,y, hjust=1)) +
geom_col(colour = "black",fill = "grey") +
geom_label(aes(x=x+5,label = x)) +
scale_x_continuous(breaks = c(0,90,180,270),limits = c(0,360)) +
coord_polar()
Instead of plotting the geom_cols's at c(0,20,40,...) I'm now plotting them at c(10,30,50,...). I'm plotting the geom_labels at c(5, 15, 25,...).
The label positioning at the bottom of the chart is still not perfect since 180deg is not South.
I get this graph: