I'm using plot() to create a map with a legend and because of the shape of the map, it overlaps with the legend. I'm still learning R, but how can I move the map slightly to the left to reduce overlap? I'm sure there's a simple fix, but I was not able to find the right parameter.
Thanks for your help! I'm new to R (and stackoverflow) so I cannot post an image unfortunately.
EDIT: Here's the code that I'm running:
plot(spdfCounties, bg="gray90", col=findColours(ciFisher, colRamp))
title("Fisher-Jenks")
strLegend = paste(
"$", format(round(ciFisher$brks[-(intClasses + 1)]), big.mark=","), " - ",
"$", format(round(ciFisher$brks[-1]), big.mark=","), sep=""
)
legMain = legend(
"topright", legend=strLegend,
title="Median Income, 2010", bg="gray", inset=0.02, cex=0.6,
fill=colRamp
)
Use the mar (for margin) options in par. From ?par
mar A numerical vector of the form c(bottom, left, top, right) which
gives the number of lines of margin to be specified on the four sides
of the plot. The default is c(5, 4, 4, 2) + 0.1.
So, if your legend is on the right, make your right margin bigger by entering
par(mar = c(5, 4, 4, 8) + 0.1)
Some trial and error should be able to get it right.
This question about resetting par values may also be helpful. In general, you can always do dev.off() to close the device, and a new device will start with the default par settings.
EDIT: Adapting #Hugh's example
x <- runif(1000)
y <- runif(1000)
plot(x, y)
legend('topright', legend = "points") # overlaps points
par(mar = c(5, 4, 4, 8) + 0.2)
plot(x, y)
legend('right', legend = "points", inset = -.3, xpd = T)
# The correct right margin and inset value will depend
# on the size of your graphic device.
Adjusting the margins results in
Adding white space to the graph, as in #Hugh's answer, looks like this:
Edit 2
Trying to adapt new code from question. You're still using base graphics' plot function, so nothing should be special about having a map. However, we don't have your data, so we can't really test anything. (If this doesn't work---and regardless before posting another question---you should look at tips for making reproducible examples.)
dev.off() # to reset par
par(mar = c(5, 4, 4, 8))
plot(spdfCounties, bg="gray90", col=findColours(ciFisher, colRamp))
# the margins are set as soon as you call plot()
title("Fisher-Jenks")
strLegend = paste(
"$", format(round(ciFisher$brks[-(intClasses + 1)]), big.mark=","), " - ",
"$", format(round(ciFisher$brks[-1]), big.mark=","), sep=""
)
legMain = legend(
"right", # changed the legend to right
legend=strLegend,
title="Median Income, 2010",
bg="gray",
inset= -0.3, # negative inset to put it outside of the plotting region
xpd = T, # xpd set to allow plotting outside of the plot region
cex=0.6,
fill=colRamp
)
As a one off, you can change the lim arguments of plot to create more space.
x <- runif(1000)
y <- runif(1000)
plot(x,y)
legend('topright', legend = "points") # overlaps points
plot(x,y, xlim = c(0, 1.5), ylim = c(0, 1.5) # adds white space
legend('topright', legend = "points")
Related
Is there a way in base R to manually add a second barplot to an existing one. I know how to do it if the two series are from the same data object (using barplot( ... beside=T)) or I guess one could draw rectangles (rect(...)) which barplot wraps. If your data is from different objects how can you then do it with the barplot function ? How to control bar positions?
I tried this using the space parameter (obviously not working):
h1 <- c(10,5,1)
h2 <- c(8, 3, 1)
barplot(h1, width = 0.5, space = 2, col='red')
barplot(h2, width = 0.5, space = 2.5, col='blue', add=T)
It is impossible to get the bars besides each other as when using the beside=T argument.
Desired output is something along this:
barplot(matrix(c(h1, h2), nrow=2, byrow=T), beside=T, col=c('red', 'blue'))
UPDATE: how it works
In order for me to finally - I hope - understand the width and space arguments, we can plot an axis and play with the parameters for the blue data.
barplot(h1, width = 0.5, space = 2, col='red')
axis(1, seq(0, 10, 0.5)) #way out of the plot region
barplot(h2, width = 0.25, space = c(4,2,4), col='blue', add=T)
From this it seem as (correct me if I am wrong):
1. width is the width of each bar - recycled as necessary
2. space controls the space to the previous bar (to the left) or to 0 for the first bar, and is calculated as width*space for the current bar - recycled as necessary. So the first blue bar starts at (space to 0) 0.25*4 = 1 and its right side is at 1+0.25 = 1.25; the second bar starts at 1.25+0.25*2 = 1.75, and its right side is at 1.75+0.25 = 2. And so forth...
You can do this:
h1 <- c(10,5,1)
h2 <- c(8, 3, 1)
barplot(h1, width = 0.5, space = 2, col='red')
barplot(h2, width = 0.5, space = c(3,2,2), col='blue', add=T)
And this will be the output:
I'm using lsmip from lsmeans to plot my model,
library(lsmeans)
PhWs1 <- lsmip(GausNugget1, Photoperiod:Ws ~ Month,
ylab = "Observed log(number of leaves)", xlab = "Month",
main = "Interaction between Photoperiod and Water stress over the months (3 photoperiods)",
par.settings = list(fontsize = list(text = 15, points = 10)))
but I was not able to get a suggestion on the internet on how to handle the legend position, size, title, etc.
I used trellis.par.get() to see the parameters but I could not find the one related to my issue. As you can see from the graph, the legend should be "Photoperiod*Ws" but Ws is not visible.
I see two possibly complementing alternatives to approach this issue. The first would be to create a fully customized legend and pass it on to the key argument of xyplot (which lsmip is heavily based on). Here is an example taken from ?lsmip to clarify my point.
## default trellis point theme
trellis_points <- trellis.par.get("superpose.symbol")
## create customized key
key <- list(title = "Some legend title", # legend title
cex.title = 1.2,
x = .7, y = .9, # legend position
points = list(col = trellis_points$col[1:2], # points
pch = trellis_points$pch[1:2],
cex = 1.5),
text = list(c("A", "B"), cex = .9)) # text
## create results and extract lattice plot
d <- lsmip(warp.lm, wool ~ tension, plotit = FALSE,
main = "Some figure title", key = key)
p <- attr(d, "lattice")
p
As you can see, setting up a customized legend let's you modify all the different components of the legend - including labels, text and symbol sizes, legend spacing, etc. Have a deeper look at the key argument described in ?xyplot which describes the various modification options in detail.
Now, if you have a long legend title and you do not want to include the legend inside the plot area, you could also define separate viewports, thus allowing the legend to occupy more space at the right margin. Note the use of update to remove the initially created legend from p and the subsequent assembly of the single figure components using grid functionality.
## remove legend from figure
p <- update(p, legend = NULL)
## assemble figure incl. legend
library(grid)
png("plot.png", width = 14, height = 10, units = "cm", res = 300)
grid.newpage()
## add figure without legend
vp0 <- viewport(x = 0, y = 0, width = .75, height = 1,
just = c("left", "bottom"))
pushViewport(vp0)
print(p, newpage = FALSE)
## add legend
upViewport(0)
vp1 <- viewport(x = .7, y = 0, width = .3, height = 1,
just = c("left", "bottom"))
pushViewport(vp1)
draw.key(key, draw = TRUE)
dev.off()
I have a plot where I have introduced vertical x axis labels via las = 2. Those labels are words. Category words. These words are too long, they range out of the picture. I have no main title in my plot (not needed), so there is enough room at the top of the image. But how do I shift everything up? I find code for parameters called mai and mar. But they do not change anything.
I tried to use mar by setting the third value of mar ("top") to 0. So I want 0 margin at the top. But the plot stays where it is :/
Here is my code (german words for the x labels):
categories <- c("Introvertiert", "Selbstbewusst", "Kooperativ", "Ehrgeizig",
"Einfühlsam", "Autoritär", "Temperamentvoll", "Flexibel", "Tolerant", "Teamfähig",
"Zielorientiert", "Überheblich", "Vielseitig", "Ungeduldig", "Zuverlässig", "Eigensinnig",
"Anpassungsfähig", "Souverän", "Selbstkritisch", "Entscheidungsfreudig", "Intelligent",
"Kontaktfreudig", "Kreativ", "Stressresistent", "Hilfsbereit", "Emotional",
"Kompromissbereit", "Gesellig", "Standhaft", "Pünktlich", "Unruhig", "Tatkräftig",
"Aufgeschlossen", "Fröhlich", "Zuvorkommend", "Uneigennützig", "Selbstbeherrscht",
"Schüchtern", "Freundlich", "Sprachgewandt")
x <- seq(1,40)
y <- seq(1,40)
plot(x,y,xaxt="n",main="", mar=c(5, 4, 0, 2) + 0.1, xlab ="")
axis(1, at=1:40, labels=categories, las = 2, cex.axis = 0.8)
Use par:
#save old settings
op <- par(no.readonly = TRUE)
#change settings
par(mar=c(8, 4, 2, 2) + 0.1)
plot(x,y,xaxt="n",main="", xlab ="")
axis(1, at=1:40, labels=categories, las = 2, cex.axis = 0.8)
#reset settings
par(op)
I tried simply plotting some data in R with the y-axis label horizontal and left of the y-axis tick labels. I thought the code below would work:
set.seed(1)
n.obs <- 390
vol.min <- .20/sqrt(252 * 390)
eps <- rnorm(n = n.obs, sd = vol.min)
mar.default <- c(5,4,4,2) + 0.1
par(mar = mar.default + c(0, 4, 0, 0)) # add space to LHS of plot
pdf("~/myplot.pdf", width=5.05, height=3.8)
plot(eps, main = "Hello World!", las=1, ylab="") # suppress the y-axis label
mtext(text="eps", side=2, line=4, las=1) # add horiz y-axis label
# 4 lines into the margin
Instead, as you may see, the y-axis label almost fell completely outside of the graphics window. This phenomenon still exists no matter how much I expand the LHS margin.
Q: What am I doing wrong? Is there something I need to do with the oma parameter? What do I need to do to plot things the way I'm intending? I'm a little overwhelmed by all of this!
This is a classic one, maybe should be a FAQ. You have to set the par settings after the call to pdf, which creates the plotting device. Otherwise you're modifying the settings on the default device:
set.seed(1)
n.obs <- 390
vol.min <- .20/sqrt(252 * 390)
eps <- rnorm(n = n.obs, sd = vol.min)
# add space to LHS of plot
pdf("~/myplot.pdf", width=5.05, height=3.8)
mar.default <- c(5,4,4,2) + 0.1
par(mar = mar.default + c(0, 4, 0, 0))
plot(eps, main = "Hello World!", las=1, ylab="") # suppress the y-axis label
mtext(text="eps", side=2, line=4, las=1)
dev.off()
I am creating a boxplot in R with the following code:
boxplot(perc.OM.y ~ Depth, axes = F, ylim = c(-0.6, 0.2), xlim = c(3.5, 5.5),
lwd = 0.1, col = 8,
ylab = "Loss of Percent Organic Matter per Year", cex.lab = 1.5)
axis(1, at = c(3.5, 4, 5, 5.5), labels = c(" ", "Shallow", "Deep", " "),
cex.axis = 1.5)
axis(2, cex.axis = 1.5)
The problem is that the number labels on the y-axis currently overlap the axis title. Is there a way to put more space between the axis title and the axis number labels?
Thanks
## dummy data
dat <- data.frame(Depth = sample(c(3:6), 20, replace = TRUE), OM = 5 * runif(20))
Add some room for the y-axis labels and annotations, by making the margin bigger on the left hand side of the plot (side = 2):
## margin for side 2 is 7 lines in size
op <- par(mar = c(5,7,4,2) + 0.1) ## default is c(5,4,4,2) + 0.1
Now plot:
## draw the plot but without annotation
boxplot(OM ~ Depth, data = dat, axes = FALSE, ann = FALSE)
## add axes
axis(1, at = 1:4, labels = c(" ", "Shallow", "Deep", " "), cex.axis = 1.5)
axis(2, cex.axis = 2)
## now draw the y-axis annotation on a different line out from the plot
## using the extra margin space:
title(ylab = "Loss of Percent Organic Matter per Year", cex.lab = 1.5,
line = 4.5)
## draw the box to finish off
box()
Then reset the plotting margins:
par(op)
This gives:
So we've created more space for the margin of the plot on side 2, and then drawn the axes and the annotation (ylab) separately to control how the plot is spaced out.
So the key to this is this line:
op <- par(mar = c(5,7,4,2) + 0.1) ## default is c(5,4,4,2) + 0.1
What we do is save the original graphical parameters in object op, and change the margin sizes (in numbers of lines) to be 5, 7, 4, 2 + 0.1 lines each for the bottom , left, top, right margins respectively. The line above shows the defaults, so the code gives 2 more lines on the left margin than usually provided by default.
Then when we draw the y-axis label using title(), we specify which line (of the 7) to draw the label at:
title(ylab = "Loss of Percent Organic Matter per Year", cex.lab = 1.5,
line = 4.5)
Here I used line 4.5, but 5 would work also. The greater the values of 'line' the farther from the plot the label is drawn.
The trick is to find the value for the left margin and the value of 'line' in the title() call that allows the axis tick marks and the axis label to not overlap. Trial and error is likely the best solution to find the values you need with base graphics.
Try setting the first value of mgp larger. You'll want to make the margins bigger too, with mar.
par(mgp=c(5,1,0))
par(mar=c(5,6,4,2)+0.1)
I just found this solution very straightforward and useful when I wanted to shrink the white space around the diagram (consider size limits in the conference papers!) while I wanted to avoid overlapping Y-axes title and big numbers as the ticks.
I use to set the titles as text and put them wherever I want, after setting the margins manually:
First, set the margins to the arbitrary values:
par( mar=c(m1, m2, m3, m4) )
where m1 to m4 are margins for four sides (1=bottom, 2=left, 3=top and 4=right).
For example:
par( mar=c(3.1, 4.7, 2.3, 0))
Then, when plotting, set main="", xlab="" and ylab="" (otherwise their text will overlap with this new text)
Finally, using mtext(), set the axis titles and diagram title manually:
mtext(side=1, text="X axes title", line=0.5)
mtext(side=2, text="Y axes title", line=3)
mtext(side=3, text="Diagram title", line=1.5)
The line parameter is the distance from the diagram (the smaller values puts it closer to the diagram).