I am trying to plot the vectors [0.7, 0.7] and [0,7, -0.7] in a way that it is visually obvious that they are orthogonal.
Since R plots points (not vectors) the origin of the vectors will be cut-off unless I adjust the x-axis to include the origin:
dat <- cbind(c(.7,.7),c(.7,-.7))
plot(dat, main = "data", xlim=c(0,.8), xlab=NA, ylab=NA, type ="n")
arrows(x0 = 0, y0 = 0, x1 = dat[1,1], y1 = dat[2,1], lwd = 5, col="purple")
arrows(x0 = 0, y0 = 0, x1 = dat[1,2], y1 = dat[2,2], lwd = 5, col="orange")
But on top of it I have different spacings between ticks in the x and y axis distorting the geometry of the vectors:
To prove some attempt at solving this issue, I resorted unsuccessfully to plotting the axes after the plot:
plot(dat, axes = FALSE)
axis(side = 1, at = seq(0,0.8, 0.01))
axis(side = 2, at = seq(-.8,.8,0.05))
arrows(x0 = 0, y0 = 0, x1 = dat[1,1], y1 = dat[2,1], lwd = 5, col="purple")
arrows(x0 = 0, y0 = 0, x1 = dat[1,2], y1 = dat[2,2], lwd = 5, col="orange")
... not a pretty picture.
Specify the asp argument, which determines y/x aspect ratio.
dat <- cbind(c(.7,.7),c(.7,-.7))
plot(dat, main = "data", xlim=c(0,.8), xlab=NA, ylab=NA, type ="n", asp=1)
arrows(x0 = 0, y0 = 0, x1 = dat[1,1], y1 = dat[2,1], lwd = 5, col="purple")
arrows(x0 = 0, y0 = 0, x1 = dat[1,2], y1 = dat[2,2], lwd = 5, col="orange")
You can find details on this argument from:
?plot.window
asp: If asp is a finite positive value then the window is set up so
that one data unit in the x direction is equal in length to asp * one
data unit in the y direction.
Note that in this case, par("usr") is no longer determined by, e.g.,
par("xaxs"), but rather by asp and the device's aspect ratio. (See
what happens if you interactively resize the plot device after running
the example below!)
The special case asp == 1 produces plots where distances between
points are represented accurately on screen. Values with asp > 1 can
be used to produce more accurate maps when using latitude and
longitude.
try setting limits:
xlim = c(-.1, 1)
ylim = c(-.8, .8)
This will draw the full extent of the space your vectors are described by. If your goal is to constrain the proportions as well you can change the scope of the limits and not fill the whole space, but preserve the proportions for both axes
xlim = c(-1, 1)
ylim = c(-1, 1)
Related
I was wondering if it is possible to seperate two plots from eachother (both should be on the same plot, using double Y axis). So the double plot should be split into two but without actually plotting them seperate - par(mfrow(1,2)).
I was trying to imitate it with layout plot, or with latticeExtra, ggplot but no success.
I have two different dataset one for the exchange rate one for the logaritmic returns.
par(mar=c(4,4,3,4))
plot(rates$EURHUF~rates$Date, type="l", ylab="Rate", main="EUR/HUF", xlab="Time")
par(new=TRUE)
plot(reteslog$EURHUF~rateslog$Date, type="l", xaxt="n", yaxt="n", ylab="", xlab="", col="red")
axis(side=4)
mtext("Log return", side=4, line=3)
legend("topleft", c("EUR/HUF Rates","EUR/HUF Logreturns"), col=c("black", "red"), lty=c(1,1))
So far I am here, I just don't know how to seperate them or scale them (maybe using margin, or layout?)
Thank you very much guys for helping
I have a solution to this that isn't too outlandish, and is entirely in base, which is nice. For it to work, you just need to be able to force all of your data onto the same scale, which usually isn't a hassle.
The idea is that once your data is on the same scale, you can plot it all normally, and then add in custom axes that show the respective scales of the different data.
set.seed(1986)
d01 <- sample(x = 1:20,
size = 200,
replace = TRUE)
d02 <- sample(x = 31:45,
size = 200,
replace = TRUE)
# pdf(file = "<some/path/to/image.pdf>",
# width = 4L,
# height = 4L) # plot to a pdf
jpeg(file = "<some/path/to/image.jpeg>") # plot to a jpeg
par(mar=c(3.5, 3.5, 2, 3.5)) # parameters to make things prettier
par(mgp=c(2.2, 1, 0)) # parameters to make things prettier
plot(x = 0,
y = 0,
type = "n",
xlim = c(1, 200),
ylim = c(1, 50),
xlab = "Label 01!",
ylab = "Label 02!",
axes = FALSE,
frame.plot = TRUE)
points(d01,
pch = 1,
col = "blue") # data 01
points(d02,
pch = 2,
col = "red") # data 02
mtext("Label 03!",
side = 4,
line = 2) # your extra y axis label
xticks <- seq(from = 0,
to = 200,
by = 50) # tick mark labels
xtickpositions <- seq(from = 0,
to = 200,
by = 50) # tick mark positions on the x axis
axis(side = 1,
at = xtickpositions,
labels = xticks,
col.axis="black",
las = 2,
lwd = 0,
lwd.ticks = 1,
tck = -0.025) # add your tick marks
y01ticks <- seq(from = 0,
to = 1,
by = 0.1) # tick mark labels
y01tickpositions <- seq(from = 0,
to = 50,
by = 5) # tick mark positions on the y01 axis
axis(side = 2,
at = y01tickpositions,
labels = y01ticks,
las = 2,
lwd = 0,
lwd.ticks = 1,
tck = -0.025) # add your tick marks
y02ticks <- seq(from = 0,
to = 50,
by = 5L) # tick mark labels
y02tickpositions <- seq(from = 0,
to = 50,
by = 5) # tick mark positions on the y02 axis
axis(side = 4,
at = y02tickpositions,
labels = y02ticks,
las = 2,
lwd = 0,
lwd.ticks = 1,
tck = -0.025) # add your tick marks
dev.off() # close plotting device
A few notes:
Sizing for this plot was originally set for a pdf, which unfortunately cannot be uploaded here, however that device call is included as commented out code above. You can always play with parameters to find out what works best for you.
It can be advantageous to plot all of your axis labels with mtext().
Including simple example data in your original post is often much more helpful than the exact data you're working with. As of me writing this, I don't really know what your data looks like because I don't have access to those objects.
I'm a relative beginner in R so please forgive me if it's a noob question.
So, is there a package which provides an easy interface to plot (real-real, mathematical) functions? I need coordinate axis with arrows (and their intersection should be (0;0)) and ticks, grid, etc. I want similar plots as in this document.
Background: now I create function plots with LaTeX's tikzpicture and axis but I'm using R to generate randomized exams since few months (R creates tex-files and include them into document) and would be nice if R can create similar plots (png, jpg), because axis in LaTeX is very slow.
Thanks!
I made you a little function for this
math_plot <- function(f, xlim = c(-2,2), ylim = c(-2,2),
xlab = "x", ylab = "f(x)", ax.ext = .02,
frame.plot = F, grid.tick = .1, ...){
curve(f, from = xlim[1], to = xlim[2], ylim = ylim,
axes = F, xlab = "", ylab = "",
frame.plot = frame.plot, ...)
# x-axis
axis(1, pos = 0)
arrows(x0 = xlim[2], x1 = xlim[2] + diff(xlim)*ax.ext, y0 = 0, length = .1)
mtext(text = xlab, side = 4, line = 0, las = 2, at = 0)
# y-axis
axis(2, pos = 0, las = 2)
arrows(y0 = ylim[2], y1 = ylim[2] + diff(ylim)*ax.ext, x0 = 0, length = .1)
mtext(text = ylab, side = 3, line = 0, at = 0)
grid(nx = diff(xlim)/grid.tick, ny = diff(ylim)/grid.tick)
}
# give it a function
math_plot(function(x) 3*x + 2 - 2*x^2, ylim = c(-2,4))
With R graphic tools such as arrows, points, abline, etc. you can draw practically anything.
Example
op <- par(mar=c(1, 1, 1, 1)) ## adjust outer margins
plot(x, y, type="n", axes=F, asp=1, xlab="", ylab="") ## asp=1 to maintain 1:1 aspect ratio
lines(x, y, lwd=2)
arrows(par()$usr[1], 0, par()$usr[2], length=.05) ## par()$usr helps to find xlim and ylim
arrows(0, par()$usr[3], 0, par()$usr[4], length=.05)
points((-5:5)*10, rep(0, 11), pch=3, cex=.6) ## pch=3 for crosses
points(rep(0, 11), (-5:5)*10, pch=3, cex=.6)
mtext("y", 3, -1, adj=.55, font=8)
mtext("x", 4, -1, padj=-1, las=2, font=8)
abline(h=(-5:5)*10, lty=3, col="gray")
abline(v=(-5:5)*10, lty=3, col="gray")
text(10, -4, "10", font=7, cex=.8)
text(-4, 10, "10", font=7, cex=.8)
par(op) ## reset par
Data
x <- (-10):10; y <- x^2 - 50
I've inherited this R code that plots a simple line graph. However, it does it so that the y axis values are plotted downwards below 0 (plots it in the 4th quadrant with 0 at the top and +3600 at the bottom). I want to plot the data right-side up (1st quadrant) so the y axis data goes from 0 up to +3600 at the top like a typical grade-school plot.
I've tried ylim = rev(y) but it returns an error...
I've also tried flipping the seq() command but no luck there.
list.vlevel = numeric(9) # placeholder
plot(
rep(0, length(list.vlevel)),
seq(1, length(list.vlevel)),
type = "n",
xlim = biaslim,
axes = F,
main = paste(list.var.bias[vv], list.score.bias[vv]),
xlab = "",
ylab = ""
)
abline(h = seq(1, length(list.vlevel)),
lty = 3,
col = 8)
axis(2,
labels = list.vlevel,
at = seq(length(list.vlevel), 1, -1),
las = 1)
axis(1)
box()
legend(
x = min(biasarray.var.runhour),
y = length(list.vlevel),
legend = expname,
lty = 3,
lwd = 3,
col = expcol
)
for (exp in seq(length(expname), 1, -1)) {
lines(
biasarray.var.runhour[exp, ],
seq(length(list.vlevel), 1, -1),
col = expcol[exp],
lwd = 3,
lty = 3
)
}
abline(v = 0, lty = 3)
The plot should end up in the first quadrant with yaxis values increasing from 0 upwards to +###.
The axis(2, ...) line draws the y axis. You can see that is the labels follow a descending sequence: seq(length(list.vlevel), 1, -1). seq(1, length(list.vlevel))
Similarly, inside lines(), probably you need to make the same change from seq(length(list.vlevel), 1, -1) to ``seq(1, length(list.vlevel))`
That's as much as we can tell with the info you've provided - can't run any of yoru code without values for all the constants you use, e.g., biasarray.var.runhour, list.var.bias, vv, etc.
I have plotted five graphs and a legend. The graphs work just fine, however the legens disappears without an error.
My preview in RStudio looks like this
When I zoom in, the area where the legend should be is blank.
I use the following code:
opar <- par (no.readonly = TRUE)
par (mfrow = c(3, 2))
library(deSolve)
# Plot A
LotVmod <- function (Time, State, Pars) {
with(as.list(c(State, Pars)), {
dx = (b*x) - (b*x*x/K) - (y*(x^k/(x^k+C^k)*(l*x/(1+l*h*x))))
dy = (y*e*(x^k/(x^k+C^k)*(l*x/(1+l*h*x)))) - (m*y)
return(list(c(dx, dy)))
})
}
Pars <- c(b = 1.080, e = 2.200, K = 130.000, k = 20.000, l = 2.000,
h = 0.030, C = 2.900, m = 0.050)
State <- c(x = 0.25, y = 2.75)
Time <- seq(1, 9, by = 1)
out <- as.data.frame(ode(func = LotVmod, y = State, parms = Pars, times = Time))
matplot(out[,-1], type = "l", xlim = c(1, 9), ylim = c(0, 45),
xlab = "time",
ylab = "population",
main = "Compartment A")
mtext ( "Coefficient of Variance 4.96", cex = 0.8 )
x <- c(# Validation data)
y <- c(# Validation data)
lines (Time, x, type="l", lty=1, lwd=2.5, col="black")
lines (Time, y, type="l", lty=1, lwd=2.5, col="red")
# Legend
plot.new()
legend("center", c(expression (italic ("F. occidentalis")*" observed"),
expression (italic ("M. pygmaeus")*" observed"),
expression (italic ("F. occidentalis")*" simulated"),
expression (italic ("M. pygmaeus")*" simulated")),
lty = c(1, 1, 1, 2),
col = c(1, 2, 1, 2),
lwd = c(2.5, 2.5, 1, 1),
box.lwd = 0, bty = "n")
# Plot C to F = same as A
par(opar)
My output doesn't give an error. I have used the exact same code before without any trouble, thus I restarted R, removed all objects, cleared all plots and restarted both RStudio and my computer.
Try to add xpd=TRUE in your legend statement. I.e.
legend("center", c(expression (italic ("F. occidentalis")*" observed"),
expression (italic ("M. pygmaeus")*" observed"),
expression (italic ("F. occidentalis")*" simulated"),
expression (italic ("M. pygmaeus")*" simulated")),
lty = c(1, 1, 1, 2),
col = c(1, 2, 1, 2),
lwd = c(2.5, 2.5, 1, 1),
box.lwd = 0, bty = "n", xpd=TRUE)
By default, the legend is cut off by the plotting region. This xpd parameter enables plotting outside the plot region. See e.g. ?par for more on xpd.
This is due to how the plot canvas is set up and how rescaling that device works. The way you do it, you add the legend in the plotting region of the top right plot. The plotting region is however not the complete device, but only the part inside the space formed by the axes. If you rescale, that plotting region will be rescaled as well. The margins around the plotting region don't change size though, so zooming in makes your plotting region so small that it doesn't fit the legend any longer. It is hidden by the margins around the plotting region.
For that reason AEBilgrau is very right you need to add xpd = TRUE. This allows the legend to extend outside of the plotting region, so it doesn't disappear behind the margins when resizing the plotting device.
I'm trying to tile plots, specifically in a 2x3 matrix, for example:
x <- seq(1, 10, by=.01)
y <- 1/x
prms<-
list(xlab=rep(c("", "x"), each=3),
ylab=rep(c("y", "", ""), 2),
xaxt=rep(c("n", "s"), each=3),
yaxt=rep(c("s", "n", "n"), 2),
mar=list(c(0 , 4.1, 4.1, 0),
c(0 , 0, 4.1, 0),
c(0 , 0, 4.1, 1.1),
c(5.1, 4.1, 0, 0),
c(5.1, 0, 0, 0),
c(5.1, 0, 0, 1.1)))
par(mfrow=c(2, 3))
for (ii in 1:6){
par(mar=prms$mar[[ii]])
plot(x, y, type="l", lwd=2,
xlab=prms$xlab[ii], ylab=prms$lab[ii],
xaxt=prms$xaxt[ii], yaxt=prms$yaxt[ii])
}
Which produces:
I've suppressed the "inner" margins and axes because all x (resp., y) units are the same, so such axes would be redundant. However, as you can see, by squeezing the margins on the left- and rightmost plots, I've accidentally given the middle plots too much space (it's not as apparent, but the same trouble plagues the top vis-a-vis the bottom row).
Therein lies the conundrum. mfrow assigns equal space to each subplot (i.e., axes, margins, etc), not to each plot area. How can I change my approach so that each plotting area is of equal size, ceteris paribus (i.e., axes, etc. unchanged)? I thought of using layout, but couldn't think of a nice programmatic way to go about making sure everything has equal representation.
You may set mar to 0, and use oma to give the size of the outer margins. Axes are added to relevant plots in a loop. Common x and y axis labels are added with mtext and outer = TRUE
par(mfrow = c(2, 3),
mar = c(0, 0, 0, 0),
oma = c(4, 4, 0.5, 0.5))
for (i in 1:6) {
plot(x, y, type = "l", axes = FALSE)
if (i %in% c(4, 5, 6))
axis(side = 1)
if (i %in% c(1, 4))
axis(side = 2)
box()
}
mtext("x values", side = 1, outer = TRUE, line = 2.5)
mtext("y values", side = 2, outer = TRUE, line = 2.5)
See also How to create multiple plots, each with same plot area size, when only one plot has axis labels?