This question is related to a question I asked earlier.
So I've got some code with which I someone's overall mean emotion (dashed line), mean emotion per day (horizontal grey lines) and emotions measured per occasion (red line). I need to add a line that connect means per day. So in this case it means that I have to plot a line between the two grey lines. I have added a picture below in which the green line represents what kind of line I want to add.
MWE:
beeps.MWE <- c(91.188697, 87.846194, 93.166418, 96.249094, 95.495146, 99.362597, 94.373646,
81.995712, 87.626009, 91.880172, 93.112647, 99.349234, 87.073372, 85.161982, 88.119728,
89.738318, 68.891181, 62.504569, 75.131526, 56.035989, 66.035109, 56.012537)
day.MWE <- rep(c(91.35869, 63.17620), each = 11)
loc.MWE <- c(8, 15)
plot(day.MWE, type = "n", pch = 15, cex = 1.5, ylim = c(40, 110), bty = "n",
ylab = "score on PA/NA", xlab = "days of person i", axes = FALSE)
dayUn <- unique(day.MWE)
for (i in seq_along(dayUn))
{
lines(which(day.MWE==dayUn[i]),day.MWE[day.MWE==dayUn[i]], lwd = "2", col = "grey")
lines(which(day.MWE==dayUn[i]),day.MWE[day.MWE==dayUn[i]], lwd = "2")
}
lines(1:length(beeps.MWE), rep(mean(day.MWE), 22), lwd = "2", lty = 2)
axis(1, at = c(1, 20), labels = c("day 1", "day 2"))
axis(2, las = 1)
This is the output of the above code:
If you have an unknown (or large) number of days you can do it in several ways, but an easy way is to add
if(i>1){
lines(c(mean(which(day.MWE==dayUn[i-1])),mean(which(day.MWE==dayUn[i]))),dayUn[(i-1):i],col="green",lwd=5)
}
inside the for-loop. This will draw a line from day i-1 to day i for day i=2,3,....
You can do it the same way you add any other lines to a plot - with lines:
lines(c(mean(which(day.MWE==dayUn[1])),mean(which(day.MWE==dayUn[2]))),dayUn,col="green",lwd=5)
Related
I am plotting correlation coefficients (values = 0.0:1.0) for two isotopes measured in each individual from two populations. I would like to have a fixed aspect-ratio for my scatter-plot so that the x- and y-axis are exactly the same size no matter the graphics device. Suggestions?
This is my first plot in R, any comments on refinements to my code is appreciated? Finally, is it worth investing in learning the basic plotting techniques or should I jump right to ggplot2 or lattice?
My plot script:
## Create dataset
WW_corr <-
structure(list(South_N15 = c(0.7976495, 0.1796725, 0.5338347,
0.4103769, 0.7447027, 0.5080296, 0.7566544, 0.7432026, 0.8927161
), South_C13 = c(0.76706752, 0.02320767, 0.88429902, 0.36648357,
0.73840937, 0.0523504, 0.52145159, 0.50707858, 0.51874445), North_N15 = c(0.7483608,
0.4294148, 0.9283554, 0.8831571, 0.5056481, 0.1945943, 0.8492716,
0.5759033, 0.7483608), North_C13 = c(0.08114805, 0.47268136,
0.94975596, 0.06023815, 0.33652839, 0.53055943, 0.30228833, 0.8864435,
0.08114805)), .Names = c("South_N15", "South_C13", "North_N15",
"North_C13"), row.names = c(NA, -9L), class = "data.frame")
opar <- par()
## Plot results
par(oma = c(1, 0, 0, 0), mar = c(4, 5, 2, 2))
plot(1,1,xlim=c(0:1.0), ylim=c(0:1.0), type="n", las=1, bty="n", main = NULL,
ylab=expression(paste("Correlation Coefficient (r) for ", delta ^{15},"N ",
"\u0028","\u2030","\u0029")),
xlab=expression(paste("Correlation Coefficient (r) for ", delta ^{13},"C ",
"\u0028","\u2030","\u0029")))
points(WW_corr$South_N15, WW_corr$South_C13, pch = 23, cex = 1.25,
bg ="antiquewhite4", col = "antiquewhite4")
points(WW_corr$North_N15, WW_corr$North_C13, pch = 15, cex = 1.25,
bg ="black")
axis(1, at = seq(0, 1.0, by = 0.1), labels = F, tick = TRUE, tck = -0.01)
axis(2, at = seq(0, 1.0, by = 0.1), labels = F, tick = TRUE, tck = -0.01)
abline(h=.86, v=.86, col = "gray60", lty = 2)
legend("topleft", c("North", "South"), pch = c(15, 23),
col = c("black", "antiquewhite4"), pt.bg = c("black", "antiquewhite4"),
horiz=TRUE, bty = "n")
par(opar)
par(pty="s")
plot(...)
sets the plot type to be square, which will do the job (I think) in your case because your x and y ranges are the same. Fairly well hidden option documented in ?par.
Using asp=1 as a parameter to plot will get interpreted by the low-level plot.window call and should give you a unitary aspect ratio. There is the potential that a call using ylim and xlim could conflict with an aspect ratio scpecification and the asp should "prevail". That's a very impressive first R graph, by the away. And an excellent question construction. High marks.
The one jarring note was your use of the construction xlim=c(0:1.0). Since xlim expects a two element vector, I would have expected xlim=c(0,1). Fewer keystrokes and less subject to error in the future if you changed to a different set of limits, since the ":" operator would give you unexpected results if you tried that with "0:2.5".
I would like to draw three dotted lines all of them at the end of the existing line. This is my dataset and code:
x = data.frame(Debt = c(115.413 , 116.522 , 123.361, 129.021, 131.786, 131.557, 131.397, 131.355, 132.1, 134.77))
future = data.frame(144.9, 147.9, 150.9)
plot(x$Debt, lwd = 2, lty = 1, type = "l", ylab = "", xlab ="", col = "red", xaxt = "n")
lines(????)
axis(1, at = seq(2010, 2020, 1), labels = seq(2010, 2020, 1))
abline(v = 2019, col = "black", ldy = 3)
legend("bottomright", col = c("black", "blue", "green"), bty = "n", lty = 1)
An example of the plot I would like to get is:
In my case the lines that I want to draw from x$Debt are the points in future.
Can anyone help me?
This solution is not beautiful at all, but you can try this.
From your initial dataframes, x and future, create new dataframe combined two data, and slice the dataframe to show
The code is as follow:
x <- data.frame(Debt = c(115.413 , 116.522 , 123.361, 129.021, 131.786, 131.557, 131.397, 131.355, 132.1, 134.77))
future <- data.frame(Debt=c(144.9, 147.9, 150.9))
df <- data.frame(x=c(1:(nrow(x)+nrow(future))), y= c(x$Debt, future$Debt))
plot(range(df[,1]), range(100,150), type='n')
lines(df[1:nrow(x),1], df[1:nrow(x),2], type='l', col='black')
lines(df[nrow(x):nrow(df),1], df[nrow(x):nrow(df),2], type='l', col='blue')
If you want to multiple lines in future range, you can append the data with years and values to the df, and add lines() with proper slices.
This question already has an answer here:
R - how to make barplot plot zeros for missing values over the data range?
(1 answer)
Closed 4 years ago.
I have a vector of observations, and I wish to plot a bar chart in R.
The vector contains discrete values from 0 to 9. There are no observations of 6, however when I plot it, I would like 6 to appear on the x-axis, with no bar above it. I coulnd't find anywhere online guidance how to do it.
My code so far is:
sick = c(0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,3,3,3,3,4,4,4,4,4,5,5,5,5,5,5,5,5,7,7,7,7,7,8,8,9)
ft = data.frame(table(sick))
colnames(ft) = c('Value','Freq')
ft$Perc = round(ft$Freq / sum(ft$Freq) * 100,1)
counts = table(sick)
bp = barplot(counts, main="Sick Leave Distribution", ylab = "Frequency", xlab = "Days of Sick Leave Taken" , ylim = c(0,10), cex.names = 1, col = "blue", names.arg=gsub("\\s","\n", unique(sick)))
text(x=bp, y=counts, labels=round(counts,0), pos=3, xpd=NA)
The code is working fine, but I would like the value of 6 to be added to the x-axis. How can it be done in R?
Providing a factor to the table function fixes this. And you'll also need to adjust name.arg.
sick = c(0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,3,3,3,3,4,4,4,4,4,5,5,5,5,5,5,5,5,7,7,7,7,7,8,8,9)
ft = data.frame(table(sick))
colnames(ft) = c('Value','Freq')
ft$Perc = round(ft$Freq / sum(ft$Freq) * 100,1)
counts = table(factor(sick,levels = c(0:9)))
bp = barplot(counts, main="Sick Leave Distribution", ylab = "Frequency", xlab = "Days of Sick Leave Taken" , ylim = c(0,10), cex.names = 1, col = "blue", names.arg=gsub("\\s","\n", c(0:9)))
text(x=bp, y=counts, labels=round(counts,0), pos=3, xpd=NA)
I want to create a figure where for various reasons I need to specify the axis labels myself. But when I specify my labels (some have one digit, some two digits) R suppresses every other two-digit label because it decides there isn't enough room to show them all, but it leaves all of the one-digit labels, leaving the axis looking lopsided.
Is there a way to suppress labels consistently across the whole axis, based on whether any of them need to be skipped? Note: I have a lot of plots with varying scales, so I was looking for something I could use for all of them - I don't want to render all the labels for every plot, or to skip every other label in every plot. Suppressing labels will be desirable for some plots and not for others. I just want to skip every other label consistently, if that's what R chooses to do for the particular plot.
(Here is an example figure of what I mean. What I want is for the "6%" label to also be suppressed in the x axis.)
Example code:
library(labeling)
df <- data.frame("estimate" = c(9.81, 14.29, 12.94),
"lower" = c(4.54, 6.25, 5.12),
"upper" = c(12.85, 20.12, 15.84))
ticks <- extended(min(df$lower), max(df$upper), m = 5, only.loose = TRUE,
Q=c(2, 5, 10))
png("examplePlot.png", width = 1200, height = 900, pointsize = 10, res = 300)
bars <- barplot(df$estimate, horiz = TRUE, col = "white", border = NA,
xlim = c(min(ticks), max(ticks)), xaxt = "n", main = "Example")
arrows(df$lower, bars, df$upper, bars, code = 3, angle = 90, length = 0.03)
points(df$estimate, bars, pch = 20)
tickLabels <- paste(ticks, "%", sep = "")
axis(1, at=ticks, labels = tickLabels, cex.axis=1)
axis(2, at = bars, labels = c("c", "b", "a"), lwd = 0, las = 2)
dev.off()
This depends on the size of the plot, so you'll have to plot each label separately:
axis(1, lwd.ticks = 1, labels = FALSE, at = ticks) # plot line and ticks
i <- seq(1,length(ticks),2) # which labels to plot
for(ii in i)
axis(1, at = ticks[ii], labels = tickLabels[ii], cex.axis = 1, lwd = 0)
So I have the following MWE, a horizontal line expresses the mean of a particular day and the points are measurements of emotion.
I'd like to draw a line instead of points within a day between the points, but the line must have breaks between days. I can't seem to figure out how to do this.
I tried the example on this page, but that does not seem to work for my data.
A friend of mine managed to do this for the horizontal lines (they have spaces between days), but I can't seem to change my code to let it work for my measurements within days.
MWE:
beeps.MWE <- c(91.188697, 87.846194, 93.166418, 96.249094, 95.495146, 99.362597, 94.373646,
81.995712, 87.626009, 91.880172, 93.112647, 99.349234, 87.073372, 85.161982, 88.119728,
89.738318, 68.891181, 62.504569, 75.131526, 56.035989, 66.035109, 56.012537)
day.MWE <- rep(c(91.35869, 63.17620), each = 11)
loc.MWE <- c(8, 15)
plot(day.MWE, type = "n", pch = 15, cex = 1.5, ylim = c(40, 110), bty = "n",
ylab = "score on PA/NA", xlab = "days of person i", axes = FALSE)
dayUn <- unique(day.MWE)
for (i in seq_along(dayUn))
{
points(which(day.MWE==dayUn[i]),day.MWE[day.MWE==dayUn[i]], type = 'l', lwd = "2")
}
points(1:length(beeps.MWE), beeps.MWE, type = "p")
lines(1:length(beeps.MWE), rep(mean(day.MWE), 22), lwd = "2", lty = 2)
axis(1, at = c(1, 20), labels = c("day 1", "day 2"))
axis(2, las = 1)
This is the output of the above code:
You're nearly there with the code provided. Just add a line to the loop to draw the lines between the points:
for (i in seq_along(dayUn)){
# draw horizontal lines to show the mean per day
points(which(day.MWE==dayUn[i]),day.MWE[day.MWE==dayUn[i]], type = 'l', lwd = "2")
# draw a line that connects points within a day
points(which(day.MWE==dayUn[i]),beeps.MWE[day.MWE==dayUn[i]], lwd = "2", type='l')
}
Also note that points(x,y,type='l') is the same as lines(x,y). Makes more sense ;)