How to assign dates on x-axis to the barplot in R? - r

I have multiple dates data set that I would like to plot using barplot functions in R. The data is for two different periods so I want to have its respective dates on the x-axis for ease of comparison. Here is my code so far. A_Date is for dataset in A while B_Date is for dataset contain in B.
A= runif(24, min = 25, max = 45)
B=runif(24, min = 35, max = 100)
DF=rbind(A,B)
A_Date= as.data.frame(seq(as.Date("1987-01-01"), to= as.Date("1988-12-31"),by="months"))
names(A_Date)= "Dates"
A_Date$year=as.numeric(format(A_Date$Dates, "%Y"))
A_Date$month=as.numeric(format(A_Date$Dates, "%m"))
A_Date=A_Date[,-1]
A_Date = as.character(paste(month.abb[A_Date$month], A_Date$year, sep = "_" ))
B_Date= as.data.frame(seq(as.Date("2010-01-01"), to= as.Date("2011-12-31"),by="months"))
names(B_Date)= "Dates"
B_Date$year=as.numeric(format(B_Date$Dates, "%Y"))
B_Date$month=as.numeric(format(B_Date$Dates, "%m"))
B_Date=B_Date[,-1]
B_Date = as.character(paste(month.abb[B_Date$month], B_Date$year, sep = "_" ))
barplot(DF, beside = T, col = c("red","darkblue"), legend.text =c("1987-88", "2010-11"), args.legend =list(x="topleft", cex = 1.2, bty="n", x.intersp=0.2),
ylab = "Precipitation (mm)", cex.axis = 1.2, cex.lab=1.5)
Also, I would like to have x-axis line (just like the line on y-axis.
Thank you

barplot also throws a coordinate matrix, which we may catch by assignment, here by b <-. Now we can make an axis with ticks at the right places. To avoid that the plot becomes too crowded, we could unify the redundant month information and just split the different years in mtextlines. I've used here built-in month.abbs.
b <- barplot(DF, beside=T, col=c("red","darkblue"),
legend.text=c("1987-88", "2010-11"),
args.legend=list(x="topleft", cex=1.2, bty="n", x.intersp=0.2),
ylab="Precipitation (mm)", cex.axis=1.2, cex.lab=1.5, ylim=c(0, 130))
axis(1, at=b[1, ], labels=FALSE)
axis(1, at=b[2, ], labels=FALSE)
mtext(rep(c(1987, 1988), each=12), 1, 1, at=b[1, ], cex=.8, las=2)
mtext(rep(c(2010, 2011), each=12), 1, 1, at=b[2, ], cex=.8, las=2)
mtext(rep(month.abb, 2), 1, 3, at=colMeans(b), las=2)
 
Result
If you'd also like to close the gap between y and x axis, you could add this line:
abline(h=0, cex=1.3)

I feel like it's going to be hard to fit all 4 dates into one spot on the axis. Here is the best I could come up with. I also rearranged your data so it fits all in one dataframe and used ggplot2.
library(tidyverse)
new_df <- tibble(precip = runif(48, c(25, 25), c(45,100)),
dates = c(seq(as.Date("1987-01-01"), as.Date("1988-12-31"), by = "months"),
seq(as.Date("2010-01-01"), as.Date("2011-12-31"), by = "months")),
group = ifelse(lubridate::year(dates) %in% c(1987,1988), "1987-88", "2010-11"),
month = lubridate::month(dates))
ggplot(new_df, aes(x = month, y = precip, fill = group)) +
geom_bar(stat = 'identity', position = position_dodge()) +
scale_x_continuous(labels = paste0(1:12, "/1987 - 1988", "\n", 1:12, "/2010 - 2011"),
breaks = 1:12) +
scale_fill_manual(values = c("red", "navy")) +
theme_classic() +
theme(legend.title = element_blank(),
axis.text = element_text(size = 10))

Related

How do I add the degree symbol and letters to each value along the x- and y-axis of a graph

So I am trying to add the degree symbol and some letters to the axis values of my graph to make them look like longitude and latitudes.
My current graph:
Want to make the axis look like this graph (with e.g., 90°N etc.)
This is the code I am using to generate my current graph:
image.plot(lon_baseline_temp, lat_baseline_temp, dat_baseline_temp,
col=rev(brewer.pal(11,"RdBu")), xlab="",
ylab="",
main="Global surface temperature (Baseline)", sub="Year 1970 ~ 1999", font.sub=2,
legend.lab="K", legend.line=2.5, legend.mar=7,
xaxp=c(-180, 180, 6), yaxp=c(-90, 90, 6), las=1)
title(ylab = expression(paste("Latitude "(degree))), line = 2, cex.lab = 1)
title(xlab = expression(paste("Longitude "(degree))), line = 2.5, cex.lab = 1)
minor.tick(nx = 5, ny = 5, tick.ratio = 0.5)
map(database = 'world', add = T, lwd=1.5)
I would really appreciate any help on this soon, thank you very much!
I cant use your data but I think you just need to use a specify your labels as follows:
#some example plot
g <- ggplot() + geom_point(aes(50,50)) + ylim(0,100) + xlim(0,100) + labs(y = "Latitude",x = "Longitude")
#plot it
g
#add a new scale with specific labels
g + scale_y_continuous(breaks = c(0,25,50,75,100),
limits = c(0,100),
labels = c(expression(0~degree),
expression(25~degree),
expression(50~degree),
expression(75~degree),
expression(100~degree)
)
) +
labs(y = "Latitude",x = "Longitude")
#plot
g

How can I change the x axis scale (years to months) in a time series plot?

I have the following code and graph:
bleeds <- read.csv("C:/Users/aaron/OneDrive/MSc Operational Research/Dissertation/Bleeds.csv", header = TRUE)
bleeds
#Change date to object(date)
bleeds$Month <- as.Date(bleeds$Month, format = "%b")
## Transform data into time series
bleedts <- ts(bleeds$Number.of.Bleeds, frequency = 12, start = c(2019, 01), end = c(2021, 08))
bleedts
plot(bleedts)
bleeds$Month <- as.Date(bleeds$Month, format="%b")
str(bleeds$Month)
##Training and Test sets
training = window(bleedts, start = c(2019, 1), end = c(2020, 12))
testing = window(bleedts, start = c(2021, 1))
##Baseline (seasonal Naive) forecast
naive_forecast = snaive(training, h = length(testing), level = 95)
MAPE(naive$mean, testing) * 100
plot(bleedts, xlab = "Year", ylab = "Number of Bleeds", main = "Seasonal Naive Forecast",
col = "blue", lwd=2)
lines(naive_forecast$mean, col = "red", lwd=2)
legend( x = "topleft",
legend = c("Observed Number of bleeds", "Seasonal Naive Forecast"),
col = c("Blue", "red"),
lty = c(1, 1),
lwd = c(2, 2),
cex = 0.65)
and get the following graph
Naive forecast vs Testing Set
I'm trying to change the time scale to months (Jan 2019 - August 2020) instead of the "2019, 2019.5" etc.

Create bar plot with logarithmic scale in R

I am trying to create a bar plot with a logarithmic scale as my data varies from 3.92 to 65700.
This is the code i have used so far:
beach <- c(PlasticsBlue=3.92, PlasticsGrey=65700, FoamsOrange=17.9, FoamsWhite=51300, RopesGreen=9.71, RopesGreen=3140)
beach
par(mar = c(10, 5, 10, 5))
barplot(beach, names.arg=c("Plastics/Blue", "Plastics/Grey", "Foams/Orange", "Foams/White", "Ropes/Green", "Ropes/Green"), col=c("red2", "slateblue4", "red2", "slateblue4", "red2", "slateblue4", "red2"), legend.text = c("Lowest", "Highest"), args.legend=list(cex=0.75,x="topright"), ylim=c(1,100000), log = ("y"), las=2, ylab = expression("mg g"^-1))
Which has given me this graph graph
This is exactly what I'm looking for apart from the log function used means that the next tick mark would be 1000000 which is far too large and therefore currently the y axis is only numbered up to 10000 which does not incorporate my largest values. Is there any way around this to have the y axis numbered up to 100000 whilst still using the log function as this seemed to work when I first made the graph in excel (see graph2 link) graph2
Thanks in advance, Alistair
You can always get what if you are willing to fiddle with the details in R. In this case it is easier to bypass R's helpful log axis and construct your own:
options(scipen=8)
out <- barplot(log10(beach), names.arg=c("Plastics/Blue", "Plastics/Grey", "Foams/Orange",
"Foams/White", "Ropes/Green", "Ropes/Green"), col=c("red2", "slateblue4", "red2",
"slateblue4", "red2", "slateblue4", "red2"), legend.text = c("Lowest", "Highest"),
args.legend=list(cex=0.75,x="topright"), ylim=c(0, 5), las=2, yaxt="n",
ylab = expression("mg g"^-1))
yval <- c(1, 10, 100, 1000, 10000, 100000)
ypos <- log10(yval)
axis(2, ypos, yval, las=1)
text(out, log10(beach), beach, pos=3, xpd=NA)
The first line just keeps R from switching to scientific notation for the 100000 value. The barplot differs in that we convert the raw data with log10() set the ylim based on the log10 values, and suppress the y-axis. Then we create a vector of the positions on the y axis we want to label and get their log10 positions. Finally we print the axis. The last line uses the value out from barplot which returns the positions of the bars on the x axis so we can print the values on the tops of the bars.
Using ggplot2 and company could look like:
library(dplyr)
library(ggplot2)
library(tibble)
library(scales)
beach <- c(PlasticsBlue = 3.92, PlasticsGrey = 65700, FoamsOrange = 17.9, FoamsWhite = 51300, RopesGreen = 9.71, RopesGreen = 3140) %>%
enframe() %>%
mutate(colorID = rep(c('Lowest', 'Highest'), 3))
plot <- beach %>%
ggplot(aes(x = 1:nrow(beach), y = value, label = value, fill = colorID)) +
geom_col(stat = 'identity') +
scale_y_continuous(trans = "log10", labels = label_number(), breaks = c(1, 10, 100, 1000, 10000, 100000)) +
scale_x_discrete(labels = beach$name, breaks = 1:nrow(beach), limits = 1:nrow(beach)) +
geom_text(vjust = -1) +
theme_minimal() +
theme(panel.background = element_blank(),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
axis.line.y = element_line(colour = 'black'),
legend.position = 'right',
legend.title = element_blank()) +
labs(y = expression("mg g"^-1),
x = 'Category/Sample colour') +
scale_fill_manual(values = rep(c('slateblue4', 'red2'), 3))
This gives us:

R: Two graphs (boxplot and barplot) sharing one X-Axis

I am trying to match two graphs in such a way that the two graphs are located vertically above each other sharing one x Axis
I already tried to use ggplot but didn't succeed. I did not manage to rewrite the commands barplot() and plot() to ggplot() in such a way that the graphs still come out right.
I would be very grateful for any help!
That's the first plot:
plot(as.factor(DauerK_mcpM$Kulturkategorie),
DauerK_mcpM$Electivity,
ylim = c(-1,1),
ylab="Elektivitätsindex",
col = DauerK_mcpM$Farbe, xaxt = "n",
main = "Elektivität Männchen mit Dauer")
abline(h = 0, lty = 2)
x.labels <- gsub("^.*?)","",levels(as.factor(DauerK_mcpM$Kulturkategorie)))
breaks <- seq(1,length(x.labels), 1)
axis(1, labels = x.labels, at = breaks, las = 2, cex.axis = 1)
dev.off()
That's the second plot:
barplot(Dauer_pro_Kultur_prozentM,
beside = TRUE,
xaxt = "n", ylab="verbrachte Zeit [%]",
main = "Männchen", col = Dauer_pro_KulturW$Farbe)
x.labels <- gsub("^.*?)", "", levels(as.factor(Dauer_pro_KulturW$Kulturkategorie)))
length <- length(x.labels)*1.2
breaks <- seq(from = 0.7, to = length, 1.2)
axis(1, labels = x.labels, at = breaks, las = 2, cex.axis = 1)
dev.off()
This can be done in ggplot by adding an indicator column for the plot type and then faceting by that indicator:
library(tidyverse)
#create some data
set.seed(20181022)
data <- data.frame(x = letters[ceiling(runif(100, 0, 10))],
y = runif(100),
stringsAsFactors = FALSE)
#duplicate the data and add an indicator for the Plot Type
data <- data %>%
bind_rows(data) %>%
mutate(PlotType = rep(1:2, each = nrow(data)))
#Facet by the plot type and subset each geom
data %>%
ggplot(aes(x, y)) +
facet_grid(PlotType~., scales = "free")+
geom_boxplot(data = filter(data, PlotType == 1)) +
geom_bar(data = filter(data, PlotType == 2), stat = "identity")

How to show plotted data with big value differences?

I have the data car_crashes that I am plotting using ggplot. It has 3 different data sets as seen below
but since Average of Cars is huge, the other values do not show even bit because they are in the range of 100. If I remove the average of cars data, the plot actually looks like this
Is there a way I can show all the data in one plot so that at least I can see the num of crashes plot?
The code I used is below:
carcrashes_figure <- ggplot()+geom_area(aes(YEAR_WW,AverageofCars,group = 1,colour = 'Average of cars'),car_crashes,fill = "dodgerblue1",alpha = 0.4)+
geom_line(aes(YEAR_WW,averageofcars,group = 1,linetype ='num of crashes'),car_crashes,fill = "dodgerblue3",colour = "dodgerblue3",size = 1.6) +
geom_line(aes(car_crashes$YEAR_WW,constantline,group = 1, size = 'constant line' ),car_crashes1,fill = "green4",colour = "green4")+
theme_bw() +
theme(axis.text.x = element_text(angle=70, vjust=0.6, face = 'bold'))+
theme(axis.text.y = element_text(angle=0, vjust=0.2, face = 'bold'))+
scale_colour_manual('', values = "dodgerblue1")+
scale_size_manual('',values = 1.4)+
scale_linetype_manual('',values = 1)+
scale_y_continuous()+
theme(legend.text = element_text(size = 8, colour = "black", angle = 0))
carcrashes_figure
I agreed the idea, using a separate y-axis by #Jim Quirk. As far as I know, ggplot2 isn't very good at doing it, so I used basic plot.
# making example ts_data
set.seed(1); data <- matrix(c(rnorm(21, 1000, 100), rnorm(21, 53, 10), rep(53, 21)), ncol=3)
ts_data <- ts(data, start = 1980, frequency = 1)
par(mar=c(4, 4.2, 1.5, 4.2)) # enlarge a right margin
# plot(ts_data[,1]) # check y-range
plot(ts_data[,2:3], plot.type = "single", ylab="num of crashes & constant line",
col=c(2,3), ylim=c(35,100), lwd=2) # draw "num of crashes" and "constant line"
par(usr = c(par("usr")[1:2], 490, 1310)) # set the second y coordinates
axis(4) # write it on the right side
polygon(x = c(1980:2000, rev(1980:2000)), y = c(ts_data[,1], rep(0,21)),
col="#0000FF20", border = "blue") # paint "Average of cars"
mtext(side=4, "Average of cars", line=2.5)
legend("topright",paste(c("num of crashes","constant line","Average of cars")),
pt.cex=c(0,0,3), lty=c(1,1,0), pch=15, cex=0.9, col=c(2, 3, "#0000FF20"), bty="n",
inset=c(0.02,-0.02), y.intersp=1.5)

Resources