Specify plot area in a multiplot - r

I create a row of plots in a graphic device with the par() command and run the first 2 plots:
par(mfrow = c(1, 4))
hist(mydata)
boxplot(y ~ x)
Now let's say the boxplot is wrong and I want to replace it with a new one. By default the next plot goes to the left side of the previous one (or one row below, first column, in case of a multiple rows layout), leaving the previous plot unchanged.
Is there a way to specify the location of the next plot in the multiplot grid area?

To specify the location of the next plot in the multiplot grid area, I prefer to use the function layout.
The layout function provides an alternative to the mfrow and mfcol settings.
For example the equivalent of par(mfrow = c(1, 4)) is :
layout(matrix(c(1, 3, 2, 4), byrow=TRUE, ncol=4))
or
layout(matrix(c(1, 2, 3, 4), byrow=TRUE, ncol=4))
The function layout.show() may be helpful for visualizing the figure regions
that are created. The following code creates a figure visualizing the layout
created in the previous example:
layout.show(4)

The base graphics model is ink-on-paper and does not allow revisions. The lattice and ggplot models are based on lists that can be modified. You can "go back" an add items with lines, points and as pointed out you can change the focus to a particular panel, but to remove or replace stuff .... not possible. Re-running the code shouldn't be a big problem, should it? Pixels are very cheap.

You can specify the next frame to plot to useing the mfg argument to par. See ?par for details. So a command like:
par(mfg=c(1,2))
Will mean that the next high level plot will go to the plot in the 1st row 2nd column. This can be used to plot in your own custom order. However, using layout for this is probably easier better in most cases.
When you use this to specify a frame to plot in R assumes that the frame is ready to be plotted in, it will not remove anything already there, so if there is an existing plot there it will be plotted over and you will likely see both plots and it won't look pretty.
You can draw a rectangle over the top of an existing plot to give yourself a blank frame to plot in using code like:
par(xpd=NA)
rect( grconvertX(0, from='nfc'), grconvertY(0,from='nfc'),
grconvertX(1,from='nfc'), grconvertY(1, from='nfc'),
col='white',border='white')
This works OK for looking at on the screen, but you need to be careful with this if exporting or printing, in some cases the printer or interpreter of the graphics file will interpret the white rectangle as "do nothing" and you will again see both plots.
In general it is best to do plots that take more than a line or 2 of code in a script window so that if you want to change something you can edit the script and just recreate the whole plot from scratch rather than relying on tricks like this.

Related

Can I change the on_click events associated with the click of the labels in a plotly plot?

I am plotting the same entity in two different plots. Each plot is showing different aspects of the same entity: one can be shown as a circle and another one is an FFT of some calculations applied to the circle - as you can see in the figure below.
plotly_subplot
As you can see, there are repeated labels - since they are different traces, I assume this is normal. Given this, I'd like to double-click a label (for example, the first "A 2nd full - Cycle 1") and all the others would be disable except the other label with the same name - from now on, I will call this "affect the elements with the same name" effect as the group effect.
Further, I'd also like the group effect to work with the single click to disable all the labels and traces with the same name.
How can I accomplish this?
I am aware of the crosstalk package and the SharedData$new method, but I can't find a way to structure my data to fit this solution.
Well I am not sure about your data, however you can use ifelse within the plot function as shown below:
x=1:5
plot(x, x, col=ifelse(x==3, "red", "black"),
pch=ifelse(x==3, 19, 1), cex=ifelse(x==3, 2, 1))

How can I return to previous frame in R?

I'm doing a plot in R using a simple layout:
layout(matrix(c(1,2),1,2))
After I have drawn the two sides of the plot, I need to return to the first to draw two more lines (that span to the other side, and only after drawing the second side I will know the right coordinates).
I know I can use frame() to move between frames, but it only goes forward, and when it returns to the beginning, it clears the whole drawing. Is it possible to move a frame back?
Despite the warnings you can use par(mfg=...) to control the focus of plotting when using layout:
layout(matrix(1:4,2,2));
plot(1:10, 1:10);
plot(10:1, 1:10);
par(mfg=c(1,1));
abline(h=5)
I would not have expected dev.set(dev.prev()) to work since I think it's all being written to the same device.
IRTFM is correct, but if the different graphs in the layout have different scaling, then you may have to reset the scale after changing the target frame for new graphical elements added to the previous frame to be scaled correctly.
Modifying IRTFM's example a bit to demonstrate, note that this code does not produce the expected result of a horizontal line in the first graph at a value of 5 due to inconsistent scaling.
layout(matrix(1:4,2,2))
plot(1:10, 1:10)
plot(12:1, 1:12)
par(mfg=c(1,1))
abline(h=5)
However, the following code produces the expected result of a horizontal line in the first graph at a value of 5 due to resetting the appropriate scale before adding the abline element.
layout(matrix(1:4,2,2))
plot(1:10, 1:10)
plot(12:1, 1:12)
par(mfg=c(1,1))
plot.window(xlim = c(1, 10), ylim = c(1, 10))
abline(h=5)
Changing to an arbitrary frame in a layout is possible with the "mfg" graphics parameter, but you will need to reset the window scaling for any added elements to appear on the same scale as previously established. Same goes for use of mfrow or mfcol graphics parameters to create multipanel graphs.

Formatting Issue with barchart() of Cluster Analysis

I've created a segment profile plot of my cluster analysis but I'm having an issue with the formatting of a barchart() command. Here is the chart I created. The obvious issue is that my lines are too close together to read.
Here you can see the code I used to create this chart. Can someone tell me what to add in order to make this chart readable? Below is an example of my code used.
R code for reproducing the clustering and PCA we used:
## if not installed, install: install.packages("flexclust")
library("flexclust")
load("vacpref.RData")
cl6 <- kcca(vacpref, k=vacpref6, control=list(iter=0),
simple=FALSE, save.data=TRUE)
summary(cl6)
hierarchical clustering of the variables
varhier <- hclust(dist(t(vacpref)), "ward")
par(mar=c(0,0,0,15))
plot(as.dendrogram(varhier), xlab="", horiz=TRUE,yaxt="n")
principal component projection
vacpca <- prcomp(vacpref)
R code for generating the Segment Separation Plot
pairs(cl6, project=vacpca, which=1:3, asp=TRUE,points=FALSE,
hull.args=list(density=10))
R code for generating the Segment Positioning Plot:
col <- flxColors(1:6)
col[c(1,3)] <- flxColors(1:4, "light")[c(1,3)]
par(mar=rep(0,4))
plot(cl6, project=vacpca, which=2:3,
col=col,asp=TRUE,points=F,hull.args=list(density=10),axes=FALSE)
projAxes(vacpca, minradius=.5, which=2:3, lwd=2, col=”darkblue”)
R code for generating the Segment Profile Plot:
barchart(cl6, shade=TRUE, which=rev(varhier$order),legend=TRUE)
The last command was the one I used to create my segment profile plot but I wasn't sure if the commands before may have affected it in any way. I'm new to R.
One trick I often use is to change the width/height and resolution through exporting the image. Try this:
png("c:\\temp\\myCrazyPlot.png", res=250, height=8, width=12, unit="in")
barchart(cl6, shade=TRUE, which=rev(varhier$order),legend=TRUE)
# And whatever other plot commands for the same plot
dev.off()
Then go check your .png file. By tinkering the height and width, you can somehow adjust the spacing of the labels at the y-axis. You may even make its height longer than its width to let the labels spread out. (I think currently you can't do that because that's the maximal height of your screen?)

How to add points to two plots parallelly ? (in R)

I am looking for ways to add points to three different plots in parallel.
I have three scatter plots named s3d1, s3d2 and s3d3 in a single window
layout(matrix(c(1,2,1,3),2, 2, byrow = TRUE))
s3d1<-scatterplot3d(mtcars[,3],mtcars[,4],mtcars[,5],main="common",pch=20)
s3d2<-scatterplot3d(mtcars[,3],mtcars[,4],mtcars[,5],main="common",pch=20)
s3d3<-scatterplot3d(mtcars[,3],mtcars[,4],mtcars[,5],main="common",pch=20)
If I try to add points to s3d1,
s3d1$points3d(mtcars[,3],mtcars[,4],mtcars[,5],col="red")
The points would go to s3d3 but not s3d1. What am I missing ?
More info : I obtain data points while running a program. So, I need to add points to each of these plots as-and-when I get the data specific to that particular plot.
Update :
Tried par() function as well
par(fig=c(0,0.65,0,1), new=TRUE)
s3d1<-scatterplot3d(mtcars[,3],mtcars[,4],mtcars[,5],main="common",pch=20)
par(fig=c(0.7,1,0.5,1), new=TRUE)
s3d2<-scatterplot3d(mtcars[,3],mtcars[,4],mtcars[,5],main="common",pch=20)
par(fig=c(0,0.65,0,1), new=TRUE)
s3d1$points3d(mtcars[,3],mtcars[,4],mtcars[,5],col="red")
s3d1$points3d doesn't add new points to s3d1 (and not even to s3d2). Any ideas ?
If you look at the source of points3d() by just trying to execute s3d1$points3d, you'll see that it just adds points to an existing plot that is assumed to be already open. In other words, the points/plot are not stored in the s3d1,2,3 objects, but simply the transformation info needed to plot to the different views.
Soo, to do what you're trying to do, you'll just have to use the normal graphics device commands. For instance, dev.new will open a new plot window, and dev.set can switch between the active ones. You could do something like:
dev.new(); h1=dev.cur()
s3d1<-scatterplot3d(mtcars[,3],mtcars[,4],mtcars[,5],main="common",pch=20)
dev.new(); h2=dev.cur()
s3d2<-scatterplot3d(mtcars[,3],mtcars[,4],mtcars[,5],main="common",pch=20)
dev.new(); h3=dev.cur()
s3d3<-scatterplot3d(mtcars[,3],mtcars[,4],mtcars[,5],main="common",pch=20)
dev.set(h1)
s3d1$points3d(mtcars[,3],mtcars[,4],mtcars[,5],col="red")
Also check out ?dev.new for more info.

Plotting a box within filled.contour plots in R?

I'm trying to plot a box within a filled.contour plot, but unfortunately, when I plot the lines() after the filled.contour plot is created, the figure is shifted to the right because the scale forces the image to the left, but the box stays at the same coordinates. Here's what my code looks like:
dev.new(width=6,height=7)
mypredict<-matrix(data=mypredict,nrow=20,ncol=25)
filled.contour(x=seq(from=-1.5,to=1.5,length=20),
y=seq(from=1,to=3.75,length=25),
z=mypredict,
col=hsv(h=seq(from=2/3,to=0,length=20),s=1,v=1)
)
top <- 3.42
bot <- 1.56
lines(c(-1,-1),c(bot,top))
lines(c(1,1),c(bot,top))
lines(c(-1,1),c(top,top))
lines(c(-1,1),c(bot,bot))
Does anyone know how I can plot those lines within the filled.contour function? Otherwise, the lines do not plot correctly onto the main image, since the scale/legend of the graph is placed on the right.
Thanks!
The manual page for filled.contour explains the problem (and gives a solution)
This function currently uses the ‘layout’ function and so is restricted
to a full page display. As an alternative consider the ‘levelplot’
and ‘contourplot’ functions from the ‘lattice’ package which work in
multipanel displays.
The output produced by ‘filled.contour’ is actually a combination
of two plots; one is the filled contour and one is the legend.
Two separate coordinate systems are set up for these two plots,
but they are only used internally - once the function has returned
these coordinate systems are lost. If you want to annotate the
main contour plot, for example to add points, you can specify
graphics commands in the ‘plot.axes’ argument. An example is
given below.
So essentially you pass some instructions as the plot.axes parameters to override standard behaviour.
In your example:
filled.contour(x = seq(from=-1.5,to=1.5,length=20),
y = seq(from=1,to=3.75,length=25), z = mypredict,
col = hsv(h=seq(from=2/3,to=0,length=20),s=1,v=1),
plot.axes = {axis(1); axis(2); rect(left, bottom, right, top);})
Note that you have to recreate the two axes otherwise they will not be drawn. Also, no need to use the lines statement, when there is a rect function! :)
Hope this helps

Resources