Plotted raster output in R won't eliminate legend margin - r

In R, I have a raster object generated from a kernel density analysis using the ks package. I convert this into a raster object (from the raster package) and try to draw that raster object to a PNG using plot(). I want the png to have exactly one pixel for every pixel in the raster object. Simple enough, right? By default of course, I get all sorts of extraneous junk added to the plot. I can remove most of this using the various settings in plot() or par(), but no matter what I do, I don't seem able to get rid of the space formerly taken up by the legend on the right side of the plot.
library('ks')
library('raster')
# generate the data
set.seed(1)
x = matrix(rnorm(1000,1,0.5),500)
xpix = 100
ypix = 100
# calculate the density function
k = kde(
x,
H=matrix(c(0.1,0,0,0.1),2),
xmin=c(0,0),
xmax=c(1,1),
gridsize=c(xpix,ypix)
)
# convert to raster
r = raster(k)
# plot the image to PNG
png('file.png',width=xpix,height=ypix)
par(
mar=c(0,0,0,0),
bty='n',
bg='black',
plt=c(0,1,0,1)
)
plot(
r,
legend=FALSE,
axes=FALSE,
plt=c(0,1,0,1)
)
# see that 'plt' did not change
print(par())
dev.off()
If I check par before closing the device, I can see that the 'plt' value is not what I set it to; it shows the right margin, where the plotting area has been nudged over to make space for the non-legend. Sample code is above, and the image it generates is linked to here.
Incidentally, I was able to achieve the correct effect with the image() function instead of plot(), though that introduced it's own problems, namely that transparency no longer worked. Can I solve this with plot()? It's very frustrating that I'm so close but just can't seem to change the size of the plot area! I don't want to use another graphics package if there is any way to make the base function work.

Related

Trouble in changing thickness of line segments in base plot

I have a pppmatching object to plot (using the base plot function) where I need to change the thickness of line segments. Unfortunately, it seems that lwd is somehow changing the thickness of the plot border instead of the line segments! I am puzzled how to get around this.
Reproducible example:
library(spatstat)
set.seed(140627)
X <- runifpoint(300)
Y <- runifpoint(500)
m <- pppdist(X, Y)
m
plot(m, lwd = 5) #???
## End(Not run)
This is a question about the plot method plot.pppmatching in the package spatstat. This function plots line segments between the data points, with varying line widths proportional to the matching strength. The parameter lwd would override this behaviour and would plot all lines with the same width, defeating the purpose.
Text added later:
Perhaps you wanted to rescale the line widths, multiplying/dividing them by 5 to make them more visible? This can be done using the argument adjust. For example adjust=0.2 would divide all line widths by 5.
(In a future release of spatstat I will improve the documentation and suppress the irrelevant warning message)

Exporting graphs in R

I have two graphs that I plotted in R and I want to export it as a high-resolution picture for publication.
For example:
a<-c(1,2,3,4,5,6,7)
b<-c(2,3,4,6,7,8,9)
par(mfrow=c(2,1))
plot (a,b)
plot(a,b)
I usually export this graph by:
dev.copy(jpeg,'test.jpeg',width=80,height=150,units="mm",res=200)
dev.off()
However I always find this process a bit troublesome. The graph that was plotted in R does not necessarily look like the one that I exported. Therefore, I am wondering if there is a way to specifiy the dimensions and resolution of graphs before I plot them so that I can visually inspect the graphs before I export them?
Thank you
You can try:
png('out.png')
a<-c(1,2,3,4,5,6,7)
b<-c(2,3,4,6,7,8,9)
par(mfrow=c(2,1))
plot (a,b)
plot(a,b)
dev.off()
As baptiste said, jpeg is the worst format you can choose. You should take a look at the help for the bmp and png functions (with ?bmp and ?png). Both bmp and png have height, width, and res arguments that you can use to specifiy the dimensions and resolution of the output. Also, I wouldn't recommend the use of dev.copy. As you could see, the result of the output is not always what you expect.
To add to Bonifacio2's answer, you if you call the function first to make the plot, you can also define your margins and window size etc before doing any actual plotting. That way you have full control over all fig specs.
pdf(file='test.jpeg',width=80,height=150,units="mm") #I prefer pdf, because they are editable files
a<-c(1,2,3,4,5,6,7)
b<-c(2,3,4,6,7,8,9)
par(mfrow=c(2,1))
plot (a,b)
plot(a,b)
dev.off()
You can use cowplot package to combine multiple panels in several different ways. For example, in your case, we export one plot with two panels arranged in two rows and one column. I assume that you prefer to use base-R 'plot' function instead of ggplot.
library(cowplot)
p1 <- ~{
plot(a,b)
}
p2 <- ~{
plot(b,a)
}
png("plot.png",
width = 3.149606, # 80 mm
height = 5.905512, # 150 mm
units = 'in',
res = 500)
plot_grid(p1, p2, labels = "AUTO", nrow = 2, ncol = 1)
dev.off()
Note that you can either remove the labels if not needed or print small letters by using "auto". Regarding size of the text, axis-labels etc, use the standard arguments for generic plot function of base-R. I hope this answer helps you. Best wishes.

R- spplot not plotting raster stack in gWidgets GUI

I have been building a small GUI for climate analysis using gWidgets in R. Progress has been slow but steady until I hit a problem trying to display my raster stack of results using spplot().
The issue is that only the first raster in the stack is plotted and the rest are not. This issue occurs regardless if:
I produce the plot using a handler within the GUI.
If the plot is produced using a handler within a addHandlerChanged/addHandlerClicked function.
If the plot is loaded to the GUI directly from the R console.
As above but using using levelplot().
If plot() is used, results are displayed correctly but only the first 16 are displayed (I have 24 graphs) and the scales are not merged producing difficulty in interpreting the results.
Here is some example code to illustrate the issue:
require(gWidgets)
require(raster)
## create example GUI plot area
win = gwindow("Graph test")
nb = gnotebook(container=win,expand=T)
plots = ggraphicsnotebook(container=nb)
## create raster stack
rs=list()
for(i in 1:24){
rs1=raster()
rs1[]=rnorm(3600)
rs[i]=rs1
}
rs=stack(rs)
## attempt to plot stack
spplot(rs) ##plot is not produced correctly with only the first raster plotted
##compare this to plotting in a normal window
windows()
spplot(rs)
Here is an example of the expected plot (left) and the actual (right) using the above code.
If anybody has any ideas how to get around this or any alternative plotting options for raster stacks I would love to hear them.
(please note that similar results are produced if I open a separate window using windows() within the GUI or if I use levelplot())
Cheers
To those who may be interested. After 3.5 years and a many trials, including recordPlot(), the gridGraphics package and imager::capture.plot(), the only solution that I found was to save the graph as an image and then plot it in the window using rasterImage()
require(gWidgets)
require(gWidgetsRGtk2)
require(RGtk2)
require(raster)
require(png)
options(guiToolkit="RGtk2")
## create raster stack
rs=list()
for(i in 1:24){
rs1=raster(nrow=2,ncol=2)
rs1[]=rnorm(4)
rs[i]=rs1
}
rs=stack(rs)
##save plot as png
png("out.png")
spplot(rs)
dev.off()
img = readPNG("out.png")
## create example GUI plot area
win = gwindow("Graph test")
nb = gnotebook(container=win,expand=T)
plots = ggraphicsnotebook(container=nb)
##plot
par(mar=rep(0,4))
plot(1, type="n", axes=F, xlab="", ylab="")
usr = par("usr")
rasterImage(img, usr[1], usr[3], usr[2], usr[4])

Use wordlayout results for ggplot geom_text

The R package wordcloud has a very useful function which is called wordlayout. It takes initial positions of words and their respective sizes an rearranges them in a way that they do not overlap. I would like to use the results of this functions to do a geom_text plot in ggplot.
I came up with the following example but soon realized that there seems to be a big difference betweetn cex (wordlayout) and size (geom_plot) since words in graphics package appear way larger.
here is my sample code. Plot 1 is the original wordcloud plot which has no overlaps:
library(wordcloud)
library(tm)
library(ggplot2)
samplesize=100
textdf <- data.frame(label=sample(stopwords("en"),samplesize,replace=TRUE),x=sample(c(1:1000),samplesize,replace=TRUE),y=sample(c(1:1000),samplesize,replace=TRUE),size=sample(c(1:5),samplesize,replace=TRUE))
#plot1
plot.new()
pdf(file="plot1.pdf")
textplot(textdf$x,textdf$y,textdf$label,textdf$size)
dev.off()
#plot2
ggplot(textdf,aes(x,y))+geom_text(aes(label = label, size = size))
ggsave("plot2.pdf")
#plot3
new_pos <- wordlayout(x=textdf$x,y=textdf$y,words=textdf$label,cex=textdf$size)
textdf$x <- new_pos[,1]
textdf$y <- new_pos[,2]
ggplot(textdf,aes(x,y))+geom_text(aes(label = label, size = size))
ggsave("plot3.pdf")
#plot4
textdf$x <- new_pos[,1]+0.5*new_pos[,3]#this is the way the wordcloud package rearranges the positions. I took this out of the textplot function
textdf$y <- new_pos[,2]+0.5*new_pos[,4]
ggplot(textdf,aes(x,y))+geom_text(aes(label = label, size = size))
ggsave("plot4.pdf")
is there a way to overcome this cex/size difference and reuse wordlayout for ggplots?
cex stands for character expansion and is the factor by which text is magnified relative the default, specified by cin - set on my installation to 0.15 in by 0.2 in: see ?par for more details.
#hadley explains that ggplot2 sizes are measured in mm. Therefore cex=1 would correspond to size=3.81 or size=5.08 depending on if it is being scaled by the width or height. Of course, font selection may cause differences.
In addition, to use absolute sizes, you need to have the size specification outside the aes otherwise it considers it a variable to map to and choose the scale itself, eg:
ggplot(textdf,aes(x,y))+geom_text(aes(label = label),size = textdf$size*3.81)
Sadly I think you're going to find the short answer is no! I think the package handles the text vector mapping differently from ggplot2, so you can tinker with size and font face/family, etc. but will struggle to replicate exactly what the package is doing.
I tried a few things:
1) Try to plot the grobs from textdata using annotation_custom
require(plyr)
require(grid)
# FIRST TRY PLOT INDIVIDUAL TEXT GROBS
qplot(0:1000,0:1000,geom="blank") +
alply(textdf,1,function(x){
annotation_custom(textGrob(label=x$label,0,0,c("center","center"),gp=gpar(cex=x$size)),x$x,x$x,x$y,x$y)
})
2) Run the wordlayout() function which should readjust the text, but difficult to see for what font (similarly doesn't work)
# THEN USE wordcloud() TO GET CO-ORDS
plot.new()
wordlayout(textdf$x,textdf$y,words=textdf$label,cex=textdf$size,xlim=c(min(textdf$x),max(textdf$x)),ylim=c(min(textdf$y),max(textdf$y)))
plotdata<-cbind(data.frame(rownames(w)),w)
colnames(plotdata)=c("word","x","y","w","h")
# PLOT WORDCLOUD DATA
qplot(0:1000,0:1000,geom="blank") +
alply(plotdata,1,function(x){
annotation_custom(textGrob(label=x$word,0,0,c("center","center"),gp=gpar(cex=x$h*40)),x$x,x$x,x$y,x$y)
})
Here's a cheat if you just want to overplot other ggplot functions on top of it (although the co-ords don't seem to match up exactly between the data and the plot). It basically images the wordcloud, removes the margins, and under-plots it at the same scale:
# make a png file of just the panel
plot.new()
png(filename="bgplot.png")
par(mar=c(0.01,0.01,0.01,0.01))
textplot(textdf$x,textdf$y,textdf$label,textdf$size,xaxt="n",yaxt="n",xlab="",ylab="",asp=1)
dev.off()
# library to get PNG file
require(png)
# then plot it behind the panel
qplot(0:1000,0:1000,geom="blank") +
annotation_custom(rasterGrob(readPNG("bgplot.png"),0,0,1,1,just=c("left","bottom")),0,1000,0,1000) +
coord_fixed(1,c(0,1000),c(0,1000))

Save the orientation of a RGL plot3d() plot

I have a 3D plot using RGL. I would like to make identical plots using color to highlight the distribution of some variable. To do this I would like to have identical plots, how do I find and set the orientation of a plot?
Once I make a preliminary plot, I move it around to find a nice display angle and I would like to save that angle and incorporate it into future plotting scripts. Anyone have a suggestion on how to do this?
library(rgl)
plot3d(iris)
#play with the plot to find a good angle
#save the angle for future plots
Ben's comment basically answers your question; this just applies expand.dots to what he wrote ;)
## In an inital session:
library(rgl)
plot3d(iris)
## Now move the image around to an orientation you like
## Save RGL parameters to a list object
pp <- par3d(no.readonly=TRUE)
## Save the list to a text file
dput(pp, file="irisView.R", control = "all")
.......
## Then, in a later session, to recreate the plot just as you had it:
library(rgl)
pp <- dget("irisView.R")
plot3d(iris)
par3d(pp)

Resources