I need to draw a 2 line R program plot with data points on one line and a minimum Y value set to -6. The following data is the .csv input file:
> cat verifyRecording.csv
Time,MaxDBK,DBChange
07:30,20,2
07:35,21,1
07:40,22,0
07:45,23,-1
07:50,24,-2
07:55,32,-5
08:00,19,3
Below is an R program that takes the above .csv input and outputs a bar chart with 2 lines. I only need the 2 lines so it needs the barplot converted to a 2 line (plot) chart. Then add the d1$DBChange data points on the DBChange line and set the minimum Y value to -6.
#!/usr/bin/Rscript
d1 <- read.csv(file="verifyRecording.csv",head=T,sep=",")
# Provide an image size which will ensure the x labels display
png(filename="verifyRecording.png", width=1024, bg="white")
# Replace the barplot function with a plot function.
# Fix the Y values be to actually show -6 as the minimum value.
mp <- barplot(d1$MaxDBK, ylim=c(-6,50), main="Sound Recording started: 05/21/2017 7:25 AM", xlab="Time in 24hr", ylab="Sound in Decibals", border='blue')
axis(1,at=mp,labels=d1$Time)
lines(mp,d1$DBChange,type="o",pch=19,lwd=2,col="red")
lines(mp,d1$MaxDBK,type="o",pch=19,lwd=2,col="blue")
# Display the DBChange data values on the d1$DBChange line points.
##### points(d1$Time, d1$DBChange, type="l", col="red")
legend("topright", c("Recommended_DB_Change","Max_DB_Volume"), lty=c(1,1), lwd=c(2.5,2.5), col=c("red","blue"))
dev.off()
You can achieve a plot with only the lines if you start with an empty plot, instead of a barplot. This way, you just add the elements you want in it.
# Empty plot ("type = "n")
# xaxt = "n" in place to allow labelling with axis
# Set y axis limits
plot(1:nrow(d1), d1$MaxDBK, type = "n", ylim = c(-6, 50), xaxt = "n",
main = "Sound Recording started: 05/21/2017 7:25 AM",
xlab = "Time in 24hr",
ylab = "Sound in Decibals")
# Lines added
lines(d1$Time, d1$MaxDBK,type = "o", pch = 19, lwd = 2, col = "blue")
lines(d1$Time, d1$DBChange,type = "o", pch = 19, lwd = 2, col = "red")
# Label added in x axis. Changed at value to show properly
axis(side = 1, labels = d1$Time, at = d1$Time)
# Label each point with the values in d1$DBChange
text(d1$Time, d1$DBChange, labels = d1$DBChange, pos = 3)
Related
I am doing quarterly analysis, for which I want to plot a graph. To maintain continuity on x axis I have turned quarters into factors. But then when I am using plot function and trying to color it red, the col argument is not working.
An example:
quarterly_analysis <- data.frame(Quarter = as.factor(c(2020.1,2020.2,2020.3,2020.4,2021.1,2021.2,2021.3,2021.4)),
AvgDefault = as.numeric(c(0.24,0.27,0.17,0.35,0.32,0.42,0.38,0.40)))
plot(quarterly_analysis, col="red")
But I am getting the graph in black color as shown below:
Converting it to a factor is not ideal to plot unless you have multiple values for each factor - it tries to plot a box plot-style plot. For example, with 10 observations in the same factor, the col = "red" color shows up as the fill:
set.seed(123)
fact_example <- data.frame(factvar = as.factor(rep(LETTERS[1:3], 10)),
numvar = runif(30))
plot(fact_example$factvar, fact_example$numvar,
col = "red")
With only one observation for each factor, this is not ideal because it is just showing you the line that the box plot would make.
You could use border = "red:
plot(quarterly_analysis$Quarter,
quarterly_analysis$AvgDefault, border="red")
Or if you want more flexibility, you can plot it numerically and do a little tweaking for more control (i.e., can change the pch, or make it a line graph):
# make numeric x values to plot
x_vals <- as.numeric(substr(quarterly_analysis$Quarter,1,4)) + rep(seq(0, 1, length.out = 4))
par(mfrow=c(1,3))
plot(x_vals,
quarterly_analysis$AvgDefault, col="red",
pch = 7, main = "Square Symbol", axes = FALSE)
axis(1, at = x_vals,
labels = quarterly_analysis$Quarter)
axis(2)
plot(x_vals,
quarterly_analysis$AvgDefault, col="red",
type = "l", main = "Line graph", axes = FALSE)
axis(1, at = x_vals,
labels = quarterly_analysis$Quarter)
axis(2)
plot(x_vals,
quarterly_analysis$AvgDefault, col="red",
type = "b", pch = 7, main = "Both", axes = FALSE)
axis(1, at = x_vals,
labels = quarterly_analysis$Quarter)
axis(2)
Data
set.seed(123)
quarterly_analysis <- data.frame(Quarter = as.factor(paste0(2019:2022,
rep(c(".1", ".2", ".3", ".4"),
each = 4))),
AvgDefault = runif(16))
quarterly_analysis <- quarterly_analysis[order(quarterly_analysis$Quarter),]
I am planning to reproduce the attached figure, but I have no clue how to do so:
Let´s say I would be using the CO2 example dataset, and I would like to plot the relative change of the Uptake according to the Treatment. Instead of having the three variables in the example figure, I would like to show the different Plants grouped for each day/Type.
So far, I managed only to get this bit of code, but this is far away from what it should look like.
aov1 <- aov(CO2$uptake~CO2$Type+CO2$Treatment+CO2$Plant)
plot(TukeyHSD(aov1, conf.level=.95))
Axes should be switched, and I would like to add statistical significant changes indicated with letters or stars.
You can do this by building it in base R - this should get you started. See comments in code for each step, and I suggest running it line by line to see what's being done to customize for your specifications:
Set up data
# Run model
aov1 <- aov(CO2$uptake ~ CO2$Type + CO2$Treatment + CO2$Plant)
# Organize plot data
aov_plotdata <- data.frame(coef(aov1), confint(aov1))[-1,] # remove intercept
aov_plotdata$coef_label <- LETTERS[1:nrow(aov_plotdata)] # Example labels
Build plot
#set up plot elements
xvals <- 1:nrow(aov_plotdata)
yvals <- range(aov_plotdata[,2:3])
# Build plot
plot(x = range(xvals), y = yvals, type = 'n', axes = FALSE, xlab = '', ylab = '') # set up blank plot
points(x = xvals, y = aov_plotdata[,1], pch = 19, col = xvals) # add in point estimate
segments(x0 = xvals, y0 = aov_plotdata[,2], y1 = aov_plotdata[,3], lty = 1, col = xvals) # add in 95% CI lines
axis(1, at = xvals, label = aov_plotdata$coef_label) # add in x axis
axis(2, at = seq(floor(min(yvals)), ceiling(max(yvals)), 10)) # add in y axis
segments(x0=min(xvals), x1 = max(xvals), y0=0, lty = 2) #add in midline
legend(x = max(xvals)-2, y = max(yvals), aov_plotdata$coef_label, bty = "n", # add in legend
pch = 19,col = xvals, ncol = 2)
I have built two graphs in one (two different y axis but plotting on the same graph). I want to show the connection between the values on the left and the values on the right (Do they stay consistently > 0 or <0 or change?)
Now what I need is to link the two sides of the graph with a line to see if it decreases/increases. So I want a corresponding dot on the left to be linked to the corresponding dot on the right by a line.
But because the y axis values on the left and the right are different, I am not figuring out how this can work.
Here is my code to build the graph:
## Plot first set of data and draw its axis
plot(rep(1, length(DEG)), DEG, xlim = c(0,4), xaxt = "n",
ylim = c(-5, 5), col = "black", xlab = "", ylab = "")
axis(1, at = c(1))
## Allow a second plot on the same graph
par(new = TRUE)
## Plot the second plot and put axis scale on right
plot(rep(3, length(DMG)), DMG, axes = F, xlim = c(0, 4), xaxt = "n",
ylim = c(-80, 80), col = "black", xlab = "", ylab = "")
axis(1, at = c(3)))
axis(side = 4)
abline(h = 0, col = "red")
Does anyone have an idea? I tried the basic line:
lines(x$DEG[x$Genes == "FEX_0000936"], x$DMG[x$Genes == "FEX_0000936"],
type="o", pch=22, col="seagreen3")
Here is my graph perhaps it is clearer when seeing it:
Thanks for your help.
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!
This question already has answers here:
How can I plot with 2 different y-axes?
(6 answers)
Closed 6 years ago.
i'm having troubles in a multi axis barplot. I have an X,Y axis with bars and dots in the same graph. The point is that I have to shown both of them in different scales
While I can shown both (bars and dots) correctly, the problem comes when I try to set different scales in left and right axis. I dont know how to change the aditional axis scale, and how to bind the red dots to the right axis, and the bars to the left one.
This is my code and what I get:
labels <- value
mp <- barplot(height = churn, main = title, ylab = "% churn", space = 0, ylim = c(0,5))
text(mp, par("usr")[3], labels = labels, srt = 45, adj = c(1.1,1.1), xpd = TRUE, cex=.9)
# Population dots
points(popul, col="red", bg="red", pch=21, cex=1.5)
# Churn Mean
media <- mean(churn)
abline(h=media, col = "black", lty=2)
# Population scale
axis(side = 4, col= "red")
ylim= c(0,50)
ylim= c(0,5)
What I want is to have left(grey) axis at ylim=c(0,5) with the bars bound to that axis. And the right(red) axis at ylim=c(0,50) with the dots bound to that axis...
The goal is to represent bars and points in the same graph with diferent axis.
Hope I explained myself succesfully.
Thanks for your assistance!
Here is a toy example. The only "trick" is to store the x locations of the bar centers and the limits of the x axis when creating the barplot, so that you can overlay a plot with the same x axis and add your points over the centers of the bars. The xaxs = "i" in the call to plot.window indicates to use the exact values given rather than expanding by a constant (the default behavior).
set.seed(1234)
dat1 <- sample(10, 5)
dat2 <- sample(50, 5)
par(mar = c(2, 4, 2, 4))
cntrs <- barplot(dat1)
xlim0 <- par()$usr[1:2]
par(new = TRUE)
plot.new()
plot.window(xlim = xlim0, ylim = c(0, 50), xaxs = "i")
points(dat2 ~ cntrs, col = "darkred")
axis(side = 4, col = "darkred")