I've been producing different sets of charts, all in R base. I have a problem though with barplots. I've formatted the x-axis to show the dates by year, however, many years show up several times. I would like each year to only show up once.
Here's my example code:
library(quantmod)
start <- as.Date("01/01/2010", "%d/%m/%Y")
#Download FRED data
tickers <- c("WTISPLC", "DCOILBRENTEU")
fred <- lapply(tickers, function(sym) {na.omit(getSymbols(sym, src="FRED", auto.assign=FALSE, return.class = "zoo"))})
df <- do.call(merge, fred)
#Subset for start date
df <- subset(df, index(df)>=start)
#Create bar plot
par(mar = c(5,5,5,5))
barplot(df[,2], names.arg=format(index(df), "%Y"), ann=FALSE, bty="n", tck=-0, col=1:1, border=NA, space=0); title(main="Example chart", ylab="y-axis")
This example should be reproducible and show clearly what I mean. Now, I've been researching how to add a separate x-axis and how to define that axis. So, I've tried to add the following code:
#Plot bars but without x-axis
barplot(df[,2], names.arg=format(index(df), "%Y"), ann=FALSE, bty="n", tck=-0, xaxt="n", col=1:1, border=NA, space=0); title(main="Example chart", ylab="y-axis")
# Set x-axis parameters
x_min <- min(index(df))
x_max <- max(index(df))
xf="%Y"
#Add x-axis
axis.Date(1, at=seq(as.Date(x_min), x_max, "years"), format=xf, las=1, tck=-0)
This does not give me an error message, but it also does absolutely nothing in terms of drawing an x-axis.
Please do not provide a solution for ggplot. Even though I like ggplot, these barplots are part of a bigger project for me, all using R base and I would not like to introduce ggplot into this project now.
Thanks!
If you are not limited to barplot, you may use the following very simple solution using plot.zoo behind the screens:
# only use what you want, and avoid multiple plots
df2 <- df[ , 2]
# use zoo.plot's functionality
plot(df2, main = "Example Chart", ylab = "y-axis", xlab = "")
This yields the following plot:
I know it is not a barplot, but I don't see what a barplot would add here. Please let me know, whether this is what you want or not.
Edit 1
If you do want to use barplot you may use the following code:
### get index of ts in year format
index_y <- format(index(df), "%Y")
### logical vector with true if it is the start of a new year
index_u <- !duplicated(index_y)
### index of start of new year for tick marks
at_tick <- which(index_u)
### label of start of new year
labels <- index_y[index_u]
### draw barplot without X-axis, and store in bp
### bp (bar midpoints) is used to set the ticks right with the axis function
bp <- barplot(df[,2], xaxt = "n", ylab= "y-axis")
axis(side = 1, at = bp[at_tick] , labels = labels)
yielding the following plot:
Please let me know, whether this is what you want.
Edit 2
We need to take into account two bits of information, when explaining why the ticks and labels group together at the left-hand side.
(1) in barplot, space defines the amount of space before each bar (as a fraction of the average bar width). In our case, it defaults to around zero (see ?barplot for details). In the illustration below, we use spaces of 0.0, 0.5, and 2.0
(2) Barplot returns a numeric vector with the midpoints of the bars drawn (again see the help pages for more detailed info). We can use these midpoints to add information to the graph, like we do in the following excerpt: after storing the result of barplot in bp, we use bp to set the ticks: axis(... at = bp[at_tick] ... ).
When we add space, the location of the bar midpoints change. So, when we want to use the bar midpoints after adding space, we need to be sure we have the right information. Simply stated, use the vector returned by barplot with the call where you added space. If you don't, the graph will be messed up. In the below, if you continue to use the bar-midpoints of the call with (space=0), and you increase space, the ticks and labels will group at the left-hand side.
Below, I illustrate this with your data limited to 3 months in 2017.
In the top layer 3 barplots are drawn with space equal to 0.0, 0.5 and 2.0. The information used to calculated the location of ticks and labels is recalculated and saved at every plot.
In the bottom layer, the same 3 barplots are drawn, but the information used to draw the ticks and labels is only created with the first plot (space=0.0)
# Subset for NEW start for illustration of space and bp
start2 <- as.Date("01/10/2017", "%d/%m/%Y")
df2 <- subset(df, index(df)>=start2)
### get index of ts in month format, define ticks and labels
index_y2 <- format(index(df2), "%m")
at_tick2 <- which(!duplicated(index_y2))
labels2 <- index_y2[!duplicated(index_y2)]
par(mfrow = c(2,3))
bp2 <- barplot(df2[,2], xaxt = "n", ylab= "y-axis", space= 0.0, main ="Space = 0.0")
axis(side = 1, at = bp2[at_tick2] , labels = labels2)
bp2 <- barplot(df2[,2], xaxt = "n", ylab= "y-axis", space= 0.5, main ="Space = 0.5")
axis(side = 1, at = bp2[at_tick2] , labels = labels2)
bp2 <- barplot(df2[,2], xaxt = "n", ylab= "y-axis", space= 2.0, main ="Space = 2.0")
axis(side = 1, at = bp2[at_tick2] , labels = labels2)
### the lower layer
bp2 <- barplot(df2[,2], xaxt = "n", ylab= "y-axis", space= 0.0, main ="Space = 0.0")
axis(side = 1, at = bp2[at_tick2] , labels = labels2)
barplot(df2[,2], xaxt = "n", ylab= "y-axis", space= 0.5, main ="Space = 0.5")
axis(side = 1, at = bp2[at_tick2] , labels = labels2)
barplot(df2[,2], xaxt = "n", ylab= "y-axis", space= 2.0, main ="Space = 2.0")
axis(side = 1, at = bp2[at_tick2] , labels = labels2)
par(mfrow = c(1,1))
Have a look here:
Top layer: bp recalculated every time
Bottom layer: bp space=0 reused
Cutting and pasting the commands in your console may illustrate the effects better than the pic above.
I hope this helps.
You could use the axis function, I used match to obtain the indices of the dates on the axis:
space=1
#Plot bars but without x-axis
barplot(df[,2], names.arg=format(index(df), "%Y"), ann=FALSE, bty="n", tck=-0, xaxt="n",
col=1:1, border=NA, space=space); title(main="Example chart", ylab="y-axis")
# Set x-axis parameters
x_min <- min(index(df))
x_max <- max(index(df))
#Add x-axis
axis(1, at=match(seq(as.Date(x_min), x_max, "years"),index(df))*(1+space),
labels = format(seq(as.Date(x_min), x_max, "years"),"%Y"),lwd=0)
Hope this helps!
Related
I have data sets containing daily precipitation and discharge data. Now I would like to plot everything in one plot. All data sets are of length 61, so they can share the same x axis. The discharge data should be plotted the "normal" way, meaning that the y axis starts at the bottom and is placed on the left side. The precipitation data should be plotted "from the top", meaning that the y axis is reversed and placed on the right side.
Here is some code for a minimal reproducible example:
precipitation <- runif(61, min=0, max=25)
discharge <- runif(61, min=370, max=2610)
The result should approximately look like this:
Anybody with an idea how to achieve this?
EDIT: thanks pascal for the answer that implies the usage of ggplot2.
I also found a way by myself to do it with Base R, in case it could help anybody in the future:
precipitation <- runif(61, min=0, max=25)
discharge <- runif(61, min=370, max=2610)
# plot with Base R
par(mar = c(5, 5, 3, 5), xpd = TRUE)
plot(precipitation, type= "l", ylim= c(0,80), ylab= "Precipitation [mm/day]", main= "Comparison",
xlab= "Day", col= "blue")
par(new = TRUE)
plot(discharge, type= "l", xaxt = "n", ylim= rev(c(0,5000)), yaxt = "n", ylab = "", xlab = "", col= "red", lty= 2)
axis(side = 4)
mtext("Discharge [m³/s]", side = 4, line = 3)
The ggplot2 way looks a bit fancier of course.
ggplot2 can be used to make plots with a second, inverted axis. One has to specify sec.axis in scale_y_continuous(). I'm using a transformation ((100-x)*100) for your data and apply it to the axis as well, so that it fits. This can be changed to any numbers.
ggplot() +
geom_line(aes(y=precipitation, x=1:61), col="orange") +
geom_line(aes(y=100-discharge/100, x=1:61), col="blue") +
scale_y_continuous(name="rain", sec.axis=sec_axis(~(100-.)*100, name= "discharge"))
Please understand that this is not a serious exercise or any research project, and I would ask the context be left to the side as ane
The issue is that when I try to plot the values on a column against the names of the countries, some of them are excluded from the x axis, and I don't know why.
Here is the data.
And this is the code:
require(RCurl)
require(foreign)
require(tidyverse)
x = getURL("https://raw.githubusercontent.com/RInterested/PLOTS/master/drinks_csv.csv")
data <- read.csv(textConnection(x))
data <- data[,c(1:5,8)]
plot(data$country,data$cases,las=2, xlab="", ylab="")
How do I either print different alternate countries, or all of them in the x axis?
Well, there are 169 countries, so they'd have to be pretty small to print all of them.
plot(data$country,data$cases,las=2, xlab="", ylab="", xaxt = 'n')
axis(1, at = 1:length(data$country), labels = data$country, cex.axis = 0.1, las = 2)
We can select which countries to plot x-axis ticks for by finding their indices in the rows of data$country and then using axis to plot those selected countries.
my.countries <- match(c("poland","japan","togo", "belarus"),data$country)
plot(data$country,data$cases,las=2, xlab="", ylab="", xaxt = 'n')
axis(1, at = my.countries, labels = data$country[my.countries], las = 2)
I would like to create a plot of this data, with x-axis increments of 500000 and with sampleIDs on the y-axis. The following code works to create the plot, but the y-axis labels don't work, and I am unsure how to code the x-axis ticks. Also, I had to add headings manually to the data file (and then obviously add header = TRUE when I assigned d) to get the code to work. I shouldn't have had to put the column titles in though should I since I use setNames?
d = read.delim("n_reads_per_sample.tsv", header = TRUE, sep = "\t")
xticks <- ( ? increments of 500000 to xmax ? )
dotchart(
sort(setNames(d$n_reads, d$X.sample)),
xlim = c(0, at = xticks, 1 max(d$n_reads)),
labels = dimnames(d[[1]])
,
main = "reads per sample",
xlab = "number of reads",
ylab = "sample"
)
In case the link doesn't work, this is what the file looks like.
x.sample n_reads
LT-145 3193621
LT-323 786578
LT-458 485543
LT-500 3689123
LT-95 3308764
LT-367 765972
LT-205 2090226
LT-245 10238727
I can't get at your full data right now, so I am just using your sample in the question.
Not sure what you mean that the y-axis labels don't work. They seem OK to me. You can get the x-axis labels that you want by suppressing the x-axis produced by dotchart and then making your own axis using the axis function. That requires a little fancy footwork with par. Also, unless you stretch out your graphics window, there will not be enough room to print all of the axis labels. I reduced the font size and stretched the window to get the graph below.
UpperLimit <- ceiling(max(d$n_reads)/500000)*500000
xticks <- seq(0,UpperLimit, 500000)
par(xaxt = "n")
dotchart(
sort(setNames(d$n_reads, d$X.sample)),
xlim=c(0, UpperLimit),
labels = dimnames(d[[1]]),
main = "reads per sample",
xlab = "number of reads",
ylab = "sample"
)
par(xaxt = "s")
axis(1, at=xticks, cex.axis=0.7)
I am trying for the last few hours to get the ticks of desired dates with labels as Month-Year on the x-axis of a time series plot. I have tried tons of things available on Stack and others but none worked out so far.
Below is an example of what I am trying so far. I am getting plot with x-axis as a numeric such as 2014.0, while I want it to be in the date format such as Jan-2014.
I am also trying to learn, in case of numeric year labels, how can I start my x-axis with 2014.1 instead of 2014.0 as the first month of my series is January. To get this I tried time function with offset=1 but it didn't work either. Please check below example
## dataframe and its time series
temp_df<- data.frame(date_temp= as.Date(dates_of_data), opp_temp= rnorm(29,mean = 100,sd=5))
temp_ts<- ts(temp_df[,2], start=2014, freq=12)
## plot
plot(temp_ts, axes=F, lwd=3, ylim=c(min(temp_ts),max(temp_ts)), xlab="", ylab="",type="l",col="black", main="")
points(temp_ts,pch=20,col="yellow")
## y-axis
axis(2, ylim=c(min(temp_ts),max(temp_ts)),col="black",lwd=2,line=1)
mtext(2,text="Y-axis count",line=3,col="black")
## x-axis
axis(1,pretty(range(time(temp_ts)),12))
mtext("Time - Year",side=1,col="black",line=2, lwd=3)
## axis(1,pretty(range(time(temp_ts, offset=1)),12)) -- didnt work either
temp_dates<- as.Date(as.yearmon(time(temp_ts)))
axis(side=1, at=tt, labels = FALSE)
axis(side = 1, at = tt[ix], labels = labs[ix], tcl = -0.7, cex.axis = 1)
grid (NULL,NULL, lty = 6, col = "blue")
dev.off()
Couple of things that I have tried so far includes
# 1. par(xaxt="n") ## didn't work
# 2. axis(1, at=seq(from = min(temp_dates),to = max(temp_dates), by="month"), labels=format(temp_dates,"%Y-%b"),las=2)
Can you please tell me how to get x-axis labels as Jan-2014 (Month-Year)?
These are some of the link I went through as requested: here
here
here
here
and
here
EDIT: Below solution works perfectly using zoo library. However I have't been using zoo the whole time in my study and was interested more in doing the other way. Please correct what is wrong in the previous approach.
require(zoo)
dev.off()
x<- (zoo(temp_df$opp_temp, temp_df$date_temp))
plot(x, xaxt = "n")
x_times <- time(x)
ticks <- seq(x_times[1], x_times[length(x_times)], by = "month")
grid (5,5, lty = 6, col = "blue")
axis(1, at = ticks, labels = format(x_times,"%Y-%b"),las=2, tcl = -0.3)
I'm trying to move the x-axis labeling and tick marks above the plot on top. Here's my code.
ucsplot <- plot(ucs, depth, main= "Depth vs. UCS", xlab = "UCS (psi)", ylab="Depth (ft)", type="l", col="blue", xlim=c(0, max(dfplot[,3]+5000)), ylim = rev(range(depth)))
ucsplot
How do I get the x-axis labeling and tick marks to appear only on top, instead of the bottom? Also, how do I get the title to not sit right on top of the numbers right above the tick marks? Also, how do I get the chart to start not offset a little bit to the right? As in the zero and starting numbers are in the corners of the plot and not offset.
Seems the OP is looking for a plot where x-axis is at top. The data has not been provided by OP. Hence using a sample dataframe, solution can be displayed as:
df <- data.frame(a = 1:10, b = 41:50)
plot(a ~ b, data = df, axes = FALSE, xlab = NA, ylab = NA)
axis(side = 2, las = 1)
axis(side = 3, las = 1)