How can I use R to make axes always square in scatter plots? for example in:
> plot(iris)
or
> plot(iris$Petal.Width, iris$Petal.Length)
I'd like the axes to be square, i.e. the same length and tick labels for the x and y axes.
The current proposed answer does not work: the call,
plot(iris$Petal.Width, iris$Petal.Length, xlim=c(0,10), ylim=c(0,10), asp=1)
Generates:
which is not square, and does not have the same axis ticks and tick labels. The spaces between the x tick labels must be the same and the plot should be square, not rectangular.
You need to also set pty="s" in the graphics parameters to make the plot region square (independent of device size and limits):
par(pty="s")
plot(iris$Petal.Width, iris$Petal.Length, asp=1)
lines(2+c(0,1,1,0,0),3+c(0,0,1,1,0)) # confirm square visually
First of all, for me the plot already comes out square (big image). Clearly for you this is not the case, and you might need to make plots larger than the screen anyhow.
So, the size of the plot is controlled by the size of the output area, ie the plot window, the image file, or whatever else. Using Rstudio, you can use the built-in GUI the specify plot size. If you insist on using the base R console, you'll need to manually do the exporting. First open the file:
png("image.png", width=600, height=600)
This will open an image file in the working directory with equal proportions. Now plot:
x = iris$Petal.Width
y = iris$Petal.Length
all = c(x,y)
range = c(min(all), max(all))
plot(x, y, xlim=range, ylim=range)
And close the file:
dev.off()
The result:
Related
I want to put two plots on the same pdf page.
The first plot needs an aspect ratio of 1.
x <- 1:5
y <- 1:5
z <- 1:5
t <- 1:5
pdf("test.pdf")
par(mfrow=c(2,1))
plot(x,y,asp=1)
plot(z,t)
dev.off()
I end up with the following:
Let's say negative values have no meaning in the context of the first plot. How can I do to get a square plot instead of this horizontally spread rectangle ?
I tried specifying xlim=c(0, 6) and ylim=c(0, 6), but the plot is still a long rectangle with empty spaces on both sides of the points. Besides, I may not know in advance what the highest values are.
Ideally, I would like to be able to say: For the first plot, start the axes at 0, use the same length for both axes, fit the first plot in the first half of an A4 page, and the second plot in the second half of the same page.
How can I do this ?
A tact to force square plotting regions is to add pty="s" to the par function:
pdf("temp.pdf", height=11, width=8.5)
par(mfrow=c(2,1), pty="s")
plot(x,y,asp=1, xlim=c(0, 6))
plot(z,t, xlim=c(0, 6))
dev.off()
From the help file, ?par, the pty argument takes
A character specifying the type of plot region to be used; "s" generates a square plotting region and "m" generates the maximal plotting region.
Maybe you can change pdf's width and height like this:
pdf("test.pdf",width=2.height=5)
and then
par(mfrow=c(2,1))
plot(x,y)#remove asp=1
plot(z,t)
dev.off()
I am trying to remove all grid lines outside the graph. I noticed that behavior in R is not deterministic, i.e., sometimes grid lines are inside the graph only (as I want), but sometimes it spans an entire figure (see sample). I'd like to always put grid lines inside.
I read grid manual, but could not find an option to do so. abline() also puts grid lines across an entire figure.
The code I am using is
plot(xrange, yrange, type="n", xlab="X", ylab="Y", xlim=c(200,1500), ylim=c(0,10000))
...
grid(lty=3, col="gray")
Any help is appreciated. Thanks,
Nodir
When I have had this problem it is because par(xpd=TRUE) is somewhere in the code. Try setting par(xpd=FALSE) before using grid() and then par(xpd=TRUE). The sample code was used to generate the same the two plots, one of which has the grid lines extending outside of the plot region.
set.seed(1)
x <- rnorm(100)
y <- rnorm(100)
# scatter plot with gridlines inside
par(xpd=FALSE) # do not plot outside the plot region
plot(x,y)
grid(lwd=2)
# scatterplot with gridlines outside the region
par(xpd=TRUE) # plot outside the plot region
plot(x,y)
grid(lwd=2)
Lets say I want to have a plot and lose the box in R. But still I would need a scale bar so one can understand the scaling. I didn't find a solution.
plot(1,1, type="n", xlim=c(0,5), ylim=c(0,5))
When I use the scalebar function from the raster package, the scaling is not right:
require(raster)
scalebar(1)
The added scalebar is too short to represent 1 in the x axis.
I tried to find something else, but most scalebar functions are related to maps.
edit:
So what I want is something like this:
plot(1,1, type="n", xlim=c(0,5), ylim=c(0,5)
, yaxt="n",
xaxt="n", frame.plot=F, ann=F
# adding a blank plot without the axes
)
#adding some simple function
x=c(1:5)
y=x*x
lines(x=x, y=y)
#defining where the scale bar should appear
lines(x=c(4,5), y=c(5,5))
#placing the text right under the line
text(x=4.5, y=5, pos=1, label="1 km")
Is there an easier way to do something like this?
There might be a function that does what you want, but you can also create your own function that will hopefully serve well enough. See below for one possibility. You can of course adjust the function settings to get the positioning you want. In particular, I've included yadj as an argument to the function, with a default value of 1.5. You can change this if the scalebar label isn't positioned properly under the scale line.
If the x-axis spans a larger range than the values used below, you'll want to adjust the x-coordinates of the scale line so that it spans 10, 100, etc. x-units, as the case may be. If you want to get fancy, you can have the function itself determine how many x-units to span, based on the x-range of the plot and then use the magnitude of that span in the units label.
# Function to add a scalebar to a base-graphics plot
myScalebar = function(units_label, yadj=1.5) {
# Get plot coordinates
pc = par("usr")
# Position scale line between last two major x-axis tick marks
# and 1/10th of the total y-range above the lower y-axis coordinate
lines(c(floor(pc[2]-1),floor(pc[2])),
rep(pc[3] + 0.1*(pc[4] - pc[3]), 2))
# Place the units label at the midpoint of and just below the scale line
text(x=mean(c(floor(pc[2]-1), floor(pc[2]))),
y=pc[3] + 0.1*(pc[4] - pc[3]),
label=units_label, adj=c(0.5, yadj))
}
# Now redo your plot
# Start with blank plot
plot(1,1, type="n", xlim=c(0,5), ylim=c(0,5),
yaxt="n", xaxt="n", frame.plot=F, ann=F)
# Add a simple function
x=c(1:5)
y=x*x
lines(x=x, y=y)
# Add scalebar
myScalebar("1 km")
I usually use this sort of function that allows for lots of flexibility across plots. I have expanded the variables names to help with debugging. Please note: this is designed to work with raster converted to utms only (don't use geographic projections).
ScaleBar <- function(reference_raster_utm, round_to_nearest_km, width_percent, y_percent_from_bottom, x_percent_from_left, y_text_percent_from_bottom, ...) {
# Round by max to nearest... e.g. 5 km
mround <- function(x,base){
base*round(x/base)
}
# scale bar size adjustment to avoid decimals
scale_size <- ((xmax(reference_raster_utm)-xmin(reference_raster_utm))*width_percent)/1000
scale_size_adj <- mround(scale_size, round_to_nearest_km)
scale_size_adj_plot <- (scale_size_adj*1000)/2
# Horizontal percent position (x) for scale bar
x_position <- ((xmax(reference_raster_utm)-xmin(reference_raster_utm))*x_percent_from_left)+xmin(reference_raster_utm)
# Vertical percent position y for scale bar
y_position <- ((ymax(reference_raster_utm)-ymin(reference_raster_utm))*y_percent_from_bottom)+ymin(reference_raster_utm)
y_position_text <- ((ymax(reference_raster_utm)-ymin(reference_raster_utm))*y_text_percent_from_bottom)+ymin(reference_raster_utm)
# Draw line on plot
library(sp)
x_ends <- c((x_position-scale_size_adj_plot), (x_position+scale_size_adj_plot))
y_ends <- c((y_position), (y_position))
scale_bar_line <- SpatialLines(list(Lines(Line(cbind(x_ends, y_ends)), ID="length")))
projection(scale_bar_line) <- projection(reference_raster_utm)
plot(scale_bar_line, add=TRUE, ...)
text(x_position, y_position_text, paste0(scale_size_adj, "km"))
}
Arguments:
reference_raster_utm: One of your personal raster files to source extent/projection from.
round_to_nearest_km: round to nearest kilometre e.g. max out on 2km, 5km ect.
width_percent: percent of plot width that the scale bar should cover (e.g. big 50% small 10%).
y_percent_from_bottom: vertical position from bottom. 0% at bottom, 100% at top, 50% in the middle.
x_percent_from_left: horizontal position from left. 0% at left, 100% at right, 50% in the middle.
y_text_percent_from_bottom: same as y_percent_from_bottom but for text.
Example:
plot(my_raster)
ScaleBar(reference_raster_utm=my_raster, round_to_nearest_km=5, width_percent=0.25, y_percent_from_bottom=0.10, x_percent_from_left=0.50, y_text_percent_from_bottom=0.07, lwd=2)
I'm trying to create a scatter plot + linear regression line in R 3.0.3. I originally tried to create it with the following simple call to plot:
plot(hops$average.temperature, hops$percent.alpha.acids)
This created this first plot:
As you can see, the scales of the Y and X axes differ. I tried fixing this using the asp parameter, as follows:
plot(hops$average.temperature, hops$percent.alpha.acids, asp=1, xaxp=c(13,18,5))
This produced this second plot:
Unfortunately, setting asp to 1 appears to have compressed the X axis while using the same amount of space, leaving large areas of unused whitespace on either side of the data. I tried using xlim to constrain the size of the X-axis, but asp seemed to overrule it as it didn't have any effect on the plot.
plot(hops$average.temperature, hops$percent.alpha.acids, xlim=c(13,18), asp=1, xaxp=c(13,18,5))
Any suggestions as to how I could get the axes to be on the same scale without creating large amounts of whitespace?
Thanks!
One solution would be to use par parameter pty and set it to "s". See ?par:
pty
A character specifying the type of plot region to be used; "s"
generates a square plotting region and "m" generates the maximal
plotting region.
It forces the plot to be square (thus conteracting the side effect of asp).
hops <- data.frame(a=runif(100,13,18),b=runif(100,2,6))
par(pty="s")
plot(hops$a,hops$b,asp=1)
I agree with plannapus that the issue is with your plotting area. You can also fix this within the device size itself by ensuring that you plot to a square region. The example below opens a plotting device with square dimension; then the margins are also set to maintain these proportions:
Example:
n <- 20
x <- runif(n, 13, 18)
y <- runif(n, 2, 6)
png("plot.png", width=5, height=5, units="in", res=200)
par(mar=c(5,5,1,1))
plot(x, y, asp=1)
dev.off()
This has certainly been asked before, but I can't find a solution. I would like to plot some data with a perfect square as bounding box. With par(pty="s") this is easy, but once I save the plot as a pdf file, the square is lost. As I understand, this is because pdf() uses paper="special" as default and thus respects width and height (which does not give a perfect square since we have axis labels). But specifying other paper options did not help.
## the bounding rectangle in the following plot is a perfect square...
U <- matrix(runif(1000), ncol=2)
par(pty="s")
plot(U, type="p", xlab="U_1", ylab="U_2")
## ... however, not anymore if the plot is generated as a .pdf
pdf(file="U.pdf", width=6, height=6)
par(pty="s")
plot(U, type="p", xlab="U_1", ylab="U_2")
dev.off()