Ggplot2: coord_polar() with geom_col() - r

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:

Related

GGplot circular: Data dissapears when trying to format x-axis

I am trying to create a circular plot showing the number of movements fish have during each hour. It works fine if the code is like this:
ggplot(aragx, aes(x = eventhour, y = Changes, group=eventhour, col=Family)) +
geom_boxplot(position=position_dodge()) +
scale_x_continuous(breaks = seq(0, 23), labels = seq(0, 23)) +
coord_polar(start = 0) + theme_minimal() +
scale_fill_brewer() + ylab("Count") +
ggtitle("Daily Section Changes per Hour") +ylim(0,20) +facet_wrap(.~Family) +
theme(legend.position = "none") + theme(axis.title.x = element_blank())
However, the 0-12 line doesn't quite run straight to the middle, the angle between 23 and 0 isn't straight and it just doen't look nice. So I modify scale_x_continuous as follows:
ggplot(aragx, aes(x = eventhour, y = Changes, group=eventhour, col=Family)) +
geom_boxplot(position=position_dodge()) +
scale_x_continuous(limits = c(0,24), breaks = seq(0, 23), labels = seq(0, 23)) +
coord_polar(start = 0) + theme_minimal() +
scale_fill_brewer() + ylab("Count") +
ggtitle("Daily Section Changes per Hour") +ylim(0,20) +facet_wrap(.~Family) +
theme(legend.position = "none") + theme(axis.title.x = element_blank())
This fixes the cosmetic issue, but the data from eventhour=0 is all screwed up, like so:
Does anyone know how to help me? It would be much appreciated, I've been banging my head against the wall over this small thing.
The issue is that by setting limits = c(0, 24) the parts of your box plot which range to the left of 0 (or to the right of 24) are clipped off. Hence, for the boxplot at the zero position only the whiskers and the right segment of the box are drawn.
To prevent that you have to adjust the limits to take account of the width of the boxplot which by default is .75. Hence you could get a full boxplot at the zero position set limits = c(-width_bp / 2, 24 - width_bp / 2). However, doing so will rotate your circular plot slightly which we could compensate for by setting start in coord_polar eqaul to -width_bp / 8 (Note: I checked that out by trial and error but there is for sure a reason why it has to be one eigth. Sigh, was always better in algebra than in geometry. (; ).
Using some random fake example data:
library(ggplot2)
aragx <- data.frame(
eventhour = rep(0:23, 100),
Changes = runif(24 * 100)
)
width_bp <- .75
ggplot(aragx, aes(x = eventhour, y = Changes, group = eventhour)) +
geom_boxplot(position = position_dodge()) +
scale_x_continuous(
limits = c(-width_bp / 2, 24 - width_bp / 2),
breaks = seq(0, 23), labels = seq(0, 23)
) +
coord_polar(start = -width_bp / 8) +
theme_minimal() +
scale_fill_brewer() +
ylab("Count") +
ggtitle("Daily Section Changes per Hour") +
theme(legend.position = "none") +
theme(axis.title.x = element_blank())
Created on 2022-02-03 by the reprex package (v2.0.1)

Bunched up x axis ticks on multi panelled plot in ggplot

I am attempting to make a multi-panelled plot from three individual plots (see images).However, I am unable to rectify the bunched x-axis tick labels when the plots are in the multi-panel format. Following is the script for the individual plots and the multi-panel:
Individual Plot:
NewDat [[60]]
EstRes <- NewDat [[60]]
EstResPlt = ggplot(EstRes,aes(Distance3, `newBa`))+geom_line() + scale_x_continuous(n.breaks = 10, limits = c(0, 3500))+ scale_y_continuous(n.breaks = 10, limits = c(0,25))+ xlab("Distance from Core (μm)") + ylab("Ba:Ca concentration(μmol:mol)") + geom_hline(yintercept=2.25, linetype="dashed", color = "red")+ geom_vline(xintercept = 1193.9, linetype="dashed", color = "grey")+ geom_vline(xintercept = 1965.5, linetype="dashed", color = "grey") + geom_vline(xintercept = 2616.9, linetype="dashed", color = "grey") + geom_vline(xintercept = 3202.8, linetype="dashed", color = "grey")+ geom_vline(xintercept = 3698.9, linetype="dashed", color = "grey")
EstResPlt
Multi-panel plot:
MultiP <- grid.arrange(MigrPlt,OcResPlt,EstResPlt, nrow =1)
I have attempted to include:
MultiP <- grid.arrange(MigrPlt,OcResPlt,EstResPlt, nrow =1)+
theme(axis.text.x = element_text (angle = 45)) )
MultiP
but have only received errors. It's not necessary for all tick marks to be included. An initial, mid and end value is sufficient and therefore they would not need to all be included or angled. I'm just not sure how to do this. Assistance would be much appreciated.
There are several options to resolve the crowded axes. Let's consider the following example which parallels your case. The default labelling strategy wouldn't overcrowd the x-axis.
library(ggplot2)
library(patchwork)
library(scales)
df <- data.frame(
x = seq(0, 3200, by = 20),
y = cumsum(rnorm(161))
)
p <- ggplot(df, aes(x, y)) +
geom_line()
(p + p + p) / p &
scale_x_continuous(
name = "Distance (um)"
)
However, because you've given n.breaks = 10 to the scale, it becomes crowded. So a simple solution would just be to remove that.
(p + p + p) / p &
scale_x_continuous(
n.breaks = 10,
name = "Distance (um)"
)
Alternatively, you could convert the micrometers to millimeters, which makes the labels less wide.
(p + p + p) / p &
scale_x_continuous(
n.breaks = 10,
labels = label_number(scale = 1e-3, accuracy = 0.1),
name = "Distance (mm)"
)
Yet another alternative is to put breaks only every n units, in the case below, a 1000. This happens to coincide with omitting n.breaks = 10 by chance.
(p + p + p) / p &
scale_x_continuous(
breaks = breaks_width(1000),
name = "Distance (um)"
)
Created on 2021-11-02 by the reprex package (v2.0.1)
I thought it would be better to show with an example.
What I mean was, you made MigrPlt, OcResPlt, EstResPlt each with ggplot() +...... For plot that you want to rotate x axis, add + theme(axis.text.x = element_text (angle = 45)).
For example, in iris data, only rotate x axis text for a like
a <- ggplot(iris, aes(Sepal.Width, Sepal.Length)) +
geom_point() +
theme(axis.text.x = element_text (angle = 45))
b <- ggplot(iris, aes(Petal.Width, Petal.Length)) +
geom_point()
gridExtra::grid.arrange(a,b, nrow = 1)

Plotting multiple x axis profiles from a csv file in R?

I am planning to plot vertical profile of multiple parameters on x axis, for example, salinity, temperature, density, against pressure as y axis, in the same graph. This is the kind of plot i am hoping to get :
Here is a sample from my data :
ï..IntD.Date. IntT.Time. Salinity..psu. SIGMA.Kg.m3. Pressure.dbar.
1 21-April-2019 5:31:55 PM 30.2502 20.2241 0.7160
2 21-April-2019 5:32:00 PM 31.0254 20.8081 0.8409
3 21-April-2019 5:32:05 PM 31.2654 20.9930 1.0551
4 21-April-2019 5:32:10 PM 31.2953 21.0176 1.2694
Temp..0C. Vbatt.volt.
1 23.4054 12.29
2 23.4148 12.30
3 23.4060 12.29
4 23.4024 12.33
I already used these codes:
data <- read.csv('file location')
vert_plot <- ggplot(data, aes(x = Pressure.dbar., y = Temp..0C.)) + geom_line(color = '#088DA5', size = 0.75) + labs(size = 18) + ggtitle("temp vs pressure") + theme_grey() + coord_flip() + scale_y_reverse()
Which generated this plot :
as you can see, i was able to bring a single profile where the scale of y axis wasn't in reverse order whereas I'd prefer pressure value (0, 5, 10....) starting from the top left corner. Unlike the plot i made where pressure value begins in bottom left corner.
I'd be grateful if someone helped me to get figure where i will be able to plot multiple vertical profile in same graph where y axis is pressure and is in reverse order, as shown in that barrier layer thickness picture.
Add as many geom_line() as required and call aes in each geom_line(). For breaks of 5, add scale_x_continuous and call sequence of breaks in it.
vert_plot <- ggplot(df) +
geom_line(aes(x = Pressure.dbar., y = Temp..0C.), color = 'blue', size = 0.75) +
geom_line(aes(x = Pressure.dbar., y = Salinity..psu.), color = 'red', size = 0.75) +
geom_line(aes(x = Pressure.dbar., y = SIGMA.Kg.m3.), color = 'green', size = 0.75) +
labs(size = 18) + ggtitle("Dummy Title") + xlab("Pressure") + ylab("Dummy Label") +
scale_x_reverse(limits = c(40, 0), breaks = seq(40, 0, -5)) +
theme_grey() + coord_flip() + scale_y_reverse()
Alternate method:
Instead of going through all these, you can melt the data frame keeping the variable names as groups.
library(reshape2)
newdf <- melt(df, id.vars = c("IntD.Date.", "IntT.Time.", "Pressure.dbar."),
variable.name = "group")
vert_plot <- ggplot(newdf, aes(x = Pressure.dbar., y = value, color = group)) +
geom_line(size = 0.75) +
labs(size = 18) + ggtitle("Dummy Title") +
xlab("Pressure") + ylab("Dummy Label") +
scale_x_reverse(limits = c(40, 0), breaks = seq(40, 0, -5)) +
theme_grey() + coord_flip() + scale_y_reverse()

How to colour background on a scatterplot using ggplot but still show data points in R?

This is my first question here so hope this makes sense and thank you for your time in advance!
I am trying to generate a scatterplot with the data points being the log2 expression values of genes from 2 treatments from an RNA-Seq data set. With this code I have generated the plot below:
ggplot(control, aes(x=log2_iFGFR1_uninduced, y=log2_iFGFR4_uninduced)) +
geom_point(shape = 21, color = "black", fill = "gray70") +
ggtitle("Uninduced iFGFR1 vs Uninduced iFGFR4 ") +
xlab("Uninduced iFGFR1") +
ylab("Uninduced iFGFR4") +
scale_y_continuous(breaks = seq(-15,15,by = 1)) +
scale_x_continuous(breaks = seq(-15,15,by = 1)) +
geom_abline(intercept = 1, slope = 1, color="blue", size = 1) +
geom_abline(intercept = 0, slope = 1, colour = "black", size = 1) +
geom_abline(intercept = -1, slope = 1, colour = "red", size = 1) +
theme_classic() +
theme(plot.title = element_text(hjust=0.5))
Current scatterplot:
However, I would like to change the background of the plot below the red line to a lighter red and above the blue line to a lighter blue, but still being able to see the data points in these regions. I have tried so far by using polygons in the code below.
pol1 <- data.frame(x = c(-14, 15, 15), y = c(-15, -15, 14))
pol2 <- data.frame(x = c(-15, -15, 14), y = c(-14, 15, 15))
ggplot(control, aes(x=log2_iFGFR1_uninduced, y=log2_iFGFR4_uninduced)) +
geom_point(shape = 21, color = "black", fill = "gray70") +
ggtitle("Uninduced iFGFR1 vs Uninduced iFGFR4 ") +
xlab("Uninduced iFGFR1") +
ylab("Uninduced iFGFR4") +
scale_y_continuous(breaks = seq(-15,15,by = 1)) +
scale_x_continuous(breaks = seq(-15,15,by = 1)) +
geom_polygon(data = pol1, aes(x = x, y = y), color ="pink1") +
geom_polygon(data = pol2, aes(x = x, y = y), color ="powderblue") +
geom_abline(intercept = 1, slope = 1, color="blue", size = 1) +
geom_abline(intercept = 0, slope = 1, colour = "black", size = 1) +
geom_abline(intercept = -1, slope = 1, colour = "red", size = 1) +
theme_classic() +
theme(plot.title = element_text(hjust=0.5))
New scatterplot:
However, these polygons hide my data points in this area and I don't know how to keep the polygon color but see the data points as well. I have also tried adding "fill = NA" to the geom_polygon code but this makes the area white and only keeps a colored border. Also, these polygons shift my axis limits so how do I change the axes to begin at -15 and end at 15 rather than having that extra unwanted length?
Any help would be massively appreciated as I have struggled with this for a while now and asked friends and colleagues who were unable to help.
Thanks,
Liv
Your question has two parts, so I'll answer each in turn using a dummy dataset:
df <- data.frame(x=rnorm(20,5,1), y=rnorm(20,5,1))
Stop geom_polygon from hiding geom_point
Stefan had commented with the answer to this one. Here's an illustration. Order of operations matters in ggplot. The plot you create is a result of each geom (drawing operation) performed in sequence. In your case, you have geom_polygon after geom_point, so it means that it will plot on top of geom_point. To have the points plotted on top of the polygons, just have geom_point happen after geom_polygon. Here's an illustrative example:
p <- ggplot(df, aes(x,y)) + theme_bw()
p + geom_point() + xlim(0,10) + ylim(0,10)
Now if we add a geom_rect after, it hides the points:
p + geom_point() +
geom_rect(ymin=0, ymax=5, xmin=0, xmax=5, fill='lightblue') +
xlim(0,10) + ylim(0,10)
The way to prevent that is to just reverse the order of geom_point and geom_rect. It works this way for all geoms.
p + geom_rect(ymin=0, ymax=5, xmin=0, xmax=5, fill='lightblue') +
geom_point() +
xlim(0,10) + ylim(0,10)
Removing whitespace between the axis and limits of the axis
The second part of your question asks about how to remove the white space between the edges of your geom_polygon and the axes. Notice how I have been using xlim and ylim to set limits? It is a shortcut for scale_x_continuous(limits=...) and scale_y_continuous(limits=...); however, we can use the argument expand= within scale_... functions to set how far to "expand" the plot before reaching the axis. You can set the expand setting for upper and lower axis limits independently, which is why this argument expects a two-component number vector, similar to the limits= argument.
Here's how to remove that whitespace:
p + geom_rect(ymin=0, ymax=5, xmin=0, xmax=5, fill='lightblue') +
geom_point() +
scale_x_continuous(limits=c(0,10), expand=c(0,0)) +
scale_y_continuous(limits=c(0,10), expand=c(0,0))

R ggplot Line With Vertical Bands

I wish to create a plot as the above with data such as this,
data1=data.frame("School"=c(1,2,3,4,5,6,7,8,9,10),
"Score"=c(80,64,79,64,64,89,69,71,61,98),
"ScoreLow"=c(65,62,62,60,60,84,54,55,55,69),
"ScoreHigh"=c(98,79,85,97,88,95,97,90,79,99))
The blue line is 'Score' and score is on the Y-AXIS and 'SChool' is on the X-AXIS. The length of the black line gets determined from 'ScoreLow' and 'ScoreHigh'
geom_errorbar would also work, in case you want to add some ticks at the edges (or leave them out, setting width=0, as below):
library(ggplot2)
data1=data.frame("School"=c(1,2,3,4,5,6,7,8,9,10),
"Score"=c(80,64,79,64,64,89,69,71,61,98),
"ScoreLow"=c(65,62,62,60,60,84,54,55,55,69),
"ScoreHigh"=c(98,79,85,97,88,95,97,90,79,99))
ggplot(data1, aes(x=School, y=Score)) + geom_line(colour="#507bc7", size=2)+
geom_errorbar(aes(ymin=ScoreLow, ymax=ScoreHigh), width=0, col="black", size=1.5) +
theme_minimal()
Created on 2020-04-10 by the reprex package (v0.3.0)
I think you are looking for a combination of geom_line() and geom_segment().
library(ggplot2)
ggplot(data1) +
geom_line(aes(x = School, y = Score), color = "blue", size = 1.5) +
geom_segment(aes(x = School, xend = School, y = ScoreLow, yend = ScoreHigh), size = 2) +
scale_x_continuous(breaks = 1:10) +
scale_y_continuous(limits = c(0, 100), breaks = 0:10 * 10) +
theme_minimal()
Need to probably play around a bit to get it how you want it.

Resources