Add small histogram inside plot area of another plot - r

Is there a way to add a histogram inside the plot area of another plot, but independent of the "base" plot's coordinate system? In my case, I want to add a histogram as a legend to a choropleth map (the histogram would show the number of regions that fall in each class), but the question could just as easily apply to any plot. For example
plot(1:10)
rect(1, 7, 4, 9, col="gray")
Could I make a histogram appear where the gray rectangle is in the above plot? Currently, if I try to create a histogram of the series 1:10, it appears using the coordinate system set by the scatterplot, and I can't figure out how (or whether it is possible) to reposition it and resize it to appear in the top left.
plot(1:10)
hist(1:10, col="gray90", add=TRUE)

Try subplot in the TeachingDemos package (and also replicated in the Hmisc package). subplot takes user coordinates but grconvertX / grconvertY can be used to convert from normalized plot coordinates. See comments below for additional discussion.
library(TeachingDemos)
plot(1:10)
subplot(hist(1:10), grconvertX(c(.1, .4), "npc"), grconvertY(c(.7, .9), "npc"))
which gives:

Related

R language: plot grid lines only inside the graph

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)

Histogram bars exceed chart area in R

I am creating a histogram with the following line:
hist(mydata$freq2,col="lightgreen")
This produces the image below:
I would like the bars to stay within the chart area. Why doesn't R increase the values of the X and Y axis, and how can I increase these values manually?
The bars to stay in the chart area. R calculates the axis dimensions based on your data and with default parameters even extends it a bit.
The axis with its labels is drawn for the boxplot only inside the label range.
If you draw a box around the figure, you will see that the plot uses up the space always the same disregarding of your data. So it is not the bars going outside the chart but the axis being restricted to the labels.
set.seed(12345)
par(mfrow=c(2,2))
plot_random_hist <- function() {
hist(rbeta(100,1,8)*runif(1))
# plot a box to illustrate the plot area
box(col="red")
}
replicate(4, plot_random_hist() )
Have a look at par("usr") to query the dimensions of your plot in user coordinates.
If you need to control the length of the axis and the ticks/labels you can use the axis command and suppress automatic axis in your hist call.
set.seed(12345)
hist(rbeta(100,1,8),yaxt="n")
at <- c(0,10,30,par("usr")[4])
axis(2,at=at,labels=round(at))

setting mfg in a multi plot prevents drawin on margin

I'm trying to add common axes to a bunch of plots by putting them in the outer margin.
Plots are drawn first in a loop (not in the example) then I wanted to draw axes on the bottom of the two rows of plots.
But drawing the axis outside the plotting region is only possible without mfg being changed. How can I enable out-of-plot-drawing after changing mfg?
par(mfrow=c(2,2),
mar=c(1,1,0,0),
oma=c(3,0,0,0))
#Some plots
plot(function(x)x^2,from=-1,to=2, frame.plot=T,axes=F)
plot(function(x)x^3,from=-2,to=2, frame.plot=T,axes=F)
plot(rnorm(10), frame.plot=T,axes=F)
plot(1:10, frame.plot=T,axes=F)
# axis on last drawn plot (mfg=c(2,2)) - works
axis(side=1,line=0,outer=TRUE)
# set mfg to same value (mfg=c(2,2))
par(mfg=c(2,2))
# red axis is clipped to plot region, even with xpd?
axis(side=1,line=-.2,outer=FALSE,xpd=NA,col="red")
par(mfg=c(2,1))
axis(side=1,line=-.2,outer=FALSE,xpd=NA,col="red")
You can set :
par(xpd=NA)
to make sure that the axis is not clipped to the plotting region.

How to display all x labels in R barplot?

This is a basic question but I am unable to find an answer. I am generating about 9 barplots within one panel and each barplot has about 12 bars. I am providing all the 12 labels in my input but R is naming only alternate bars. This is obviously due to to some default setting in R which needs to be changed but I am unable to find it.
You may be able get all of the labels to appear if you use las=2 inside the plot() call. This argument and the others mentioned below are described in ?par which sets the graphical parameters for plotting devices. That rotates the text 90 degrees. Otherwise, you will need to use xaxt="n" (to suppress ticks and labels) and then put the labels in with a separate call to axis(1, at= <some numerical vector>, labels=<some character vector>).
# midpts <- barplot( ... ) # assign result to named object
axis(1, at = midpts, labels=names(DD), cex.axis=0.7) # shrinks axis labels
Another method is to first collect the midpoints and then use text() with xpd=TRUE to allow text to appear outside the plot area and srt be some angle for text rotation as named arguments to control the degree of text rotation:
text(x=midpts, y=-2, names(DD), cex=0.8, srt=45, xpd=TRUE)
The y-value needs to be chosen using the coordinates in the plotted area.
Copying a useful comment: For future readers who don't know what these arguments do: las=2 rotates the labels counterclockwise by 90 degrees. furthermore, if you need to reduce the font you can use cex.names=.5 to shrink the size down
To get rotated labels on a base R barplot, you could (like I do here) adapt one of the
examples given in the vignette of the gridBase package:
library(grid)
library(gridBase)
## Make some data with names long enough that barplot won't print them all
DD <- table(rpois(100, lambda=5))
names(DD) <- paste("long", names(DD), sep="_")
## Plot, but suppress the labels
midpts <- barplot(DD, col=rainbow(20), names.arg="")
## Use grid to add the labels
vps <- baseViewports()
pushViewport(vps$inner, vps$figure, vps$plot)
grid.text(names(DD),
x = unit(midpts, "native"), y=unit(-1, "lines"),
just="right", rot=50)
popViewport(3)
R won't label every bar if the labels are too big.
I would suggest trying to rotate the labels vertically by passing in the las=2 argument to your plotting function.
If the labels are still too large, you can try shrinking the font by using the cex.names=.5 argument.
Sample Data for plot
sample_curve <- c(2.31,2.34,2.37,2.52,2.69,2.81,2.83,2.85,2.94, 3.03, 3.21, 3.33) # create a sample curve
names(sample_curve)<-c("1 MO","2 MO","3 MO","6 MO","1 YR","2 YR","3 YR","5 YR","7 YR","10 YR","20 YR","30 YR") # label the curve
Example of plot with labels too big
barplot(sample_curve) # labels too big for the plot
Example of plot with labels rotated and small
barplot(sample_curve, las=2, cex.names=.5) # lables are rotated and smaller, so they fit
before plotting the barplot()
You can simply increase the margins with par() and your margins values (your plot has 4 margins) mar = c(v1,v2,v3,V4)
par(mar=c(10,4,4,4))
as example :
par(mar=c(10,4,4,4))
barplot(height=c(1,5,8,19,7),
names.arg=c("very long label 1","very long label 2",
"very long label 3","very long label 4",
"very long label 5"), las=2 )

How can I add a legend to a goodness of fit plot in R?

I'm using goodfit from vcd package to produce goodness of fit plots.
I would like to add a legend stating the bars are the actual counts and the dots (connected by the line) are the fit using e.g. Poisson and ML.
legend does not work. How can I easily add a legend to this plot?
Thanks!
The plot function for goodfit objects is using the grid graphics system (see ?rootogram and getAnywhere(rootogram.default)).
You have two options:
use the rather limited grid.legend function (from package grid).
embed a base graphics legend in the grid plot using the gridBase package.
Here is a simple example for the first option:
library("vcd")
dummy <- rnbinom(200, size=1.5, prob=0.8)
gf <- goodfit(dummy, type="nbinomial", method="MinChisq")
plot(gf)
pushViewport(viewport(x=unit(0.8, "npc"),
y=unit(0.8, "npc"),
width=stringWidth("Legend x"),
height=unit(6, "line"),
name="vp1"))
grid.legend(labels=c("Legend 1", "Legend 2"), pch=1:2)
popViewport()
Modifying #rcs's answer to use grid_legend (in the vcd package along with goodfit), which is intended for users (grid.legend is an undocumented internal function), and to show a legend specifically geared to this plot. It would be nice to use fill=c(NA,"gray") as in legend in base graphics, but it's not implemented in grid_legend.
library("vcd")
dummy <- rnbinom(200, size=1.5, prob=0.8)
gf <- goodfit(dummy, type="nbinomial", method="MinChisq")
plot(gf)
grid_legend(x=unit(0.8, "npc"),
y=unit(0.8, "npc"),
labels=c("est NBinom (MinChiSq)","obs"),
title="",
pch=c(16,15),col=c("red","gray"))
It is hard to tell without a specific example (AFAIK it is not a limitation with goodfit), but I would check a few things with legend:
You can place a legend with "topright", "bottomleft", etc for the argument x.
You can query the x and y axis limits with par("usr"). If the plot is in log scale and you want to place the legend at the maximum value of y, you have to use 10^par("usr")[4], and so on.
Pass the argument xpd=NA to see if you are placing the legend outside of the plotting region and see if you need to set xjust or yjust.

Resources