interaction with grob using grid and gridSVG - r

I actually have no idea with this does not work!
library(grid)
library(gridSVG)
grid.newpage()
vp <- viewport(width=0.7, height=0.7)
pushViewport(vp)
grid.rect(x = unit(0.5, "npc"), y = unit(0.5, "npc"),
width = unit(0.5, "npc"), height = unit(0.5, "npc"),
just = "centre", hjust = NULL, vjust = NULL,
default.units = "npc", name = "grid.rect.1",
gp=gpar(), draw = TRUE)
this works:
grid.garnish("grid.rect.1",onmousedown="alert('alert 1!')","pointer-events"="all")
grid.export("gridSVG1.svg")
this doesn't work
grid.garnish("grid.rect.1", onmouseover="allwhite()", redraw = TRUE)
grid.script("allwhite = function() {
anobject = document.getElementById('grid.rect.1.1');
anobject.setAttribute('style', 'fill:red');
}", name="allwhite")
grid.export("gridSVG2.svg") # saved to your current working directory
What I'm trying to achieve, is that the rectangle is filled with red if I'm hovering over the rectangle with my mouse.
Due to the fact, that this is my first encounter with js, I have to ask maybe this silly question. I'm aware of the fact, that I name the spline "grid.rect.1" but use "grid.rect.1.1" in the script part. This is just a matter of despair, due to the fact, that I realize that rect has this id, if I inspect the SVG object with Google Chrome.
I'm using Google Chrome (36.0.1985.125 m) to watch the SVG object and it seems that a somewhat simpler thing works
As always, any hint is appreciated.

I looks like you can't add attributes, so your rect needs a fill gpar. You'll also need to fix the id of the rect element. If you look at the source, you'll see that "grid.rect.1.1" is actually the grouping tag.
library(grid)
library(gridSVG)
grid.newpage()
vp <- viewport(width=0.7, height=0.7)
pushViewport(vp)
grid.rect(x = unit(0.5, "npc"), y = unit(0.5, "npc"),
width = unit(0.5, "npc"), height = unit(0.5, "npc"),
just = "centre", hjust = NULL, vjust = NULL,
default.units = "npc", name = "grid.rect.1",
gp=gpar(fill='white'), # add fill parameter
draw = TRUE)
grid.garnish("grid.rect.1", onmouseover="allwhite()", `pointer-events`='all')
grid.script("allwhite = function() {
anobject = document.getElementById('grid.rect.1.1.1');
anobject.setAttribute('style', 'fill:red');
}", name="allwhite")
grid.export("gridSVG2.svg")

Related

Using grid to create and save a small png file

I am using R to create a number of small graphics that will be saved as PNG files, typically at 50x50 pixels, which for eventual use in a much larger image as icons or markers. As the content changes frequently, it is desirable that these be created programmatically rather than manually.
Because the content is also simple - a few characters of text and some numbers - the grid functions seemed like a straightforward way to tackle this. I don't know grid at all well as I typically use higher-level libraries such as ggplot2. The MRE below lays out what I have already achieved.
This generates output, but I am having problems linking the sizes and scales of viewport and the various grobs to the ultimate PNG file. What I get is the below, which is fine at first glance, but is a 480x480 pixel image, most of which is unused, with the central graphic taking up only a third of the width and height.
That seems logical given the viewport sizing (=.3), but if I enlarge the viewport, then presumably I have to enlarge the text and so on. (I know how to change the png() parameters to adjust the density, number of pixels and so on, but at this point the image itself is the issue.)
The question boils down to how to best generate a decent-quality 50x50 pixel PNG or SVG file from a graphic such as this, created in R, either using grid or some other approach.
library(grid)
grid.newpage()
png(bg = "transparent")
pushViewport(viewport(width=.3, height=.3, clip="off"))
grid.rect(gp=gpar(lty=0, fill="#008000"))
grid.text("15.5", x = unit(0.5, "npc"), y = unit(0.75, "npc"),
just = "center", hjust = NULL, vjust = NULL, rot = 0,
check.overlap = FALSE, default.units = "npc",
name = NULL, gp = gpar(fontsize=48), draw = TRUE, vp = NULL)
grid.text("13h 20m", x = unit(0.5, "npc"), y = unit(0.25, "npc"),
just = "center", hjust = NULL, vjust = NULL, rot = 0,
check.overlap = FALSE, default.units = "npc",
name = NULL, gp = gpar(fontsize=32), draw = TRUE, vp = NULL)
lg <- linesGrob(x = unit(c(0, 1), "npc"),
y = unit(c(0.5, 0.5), "npc"),
gp = gpar(lwd=2))
grid.draw(lg)
dev.off()
magic library may be helpful for that. I used your starting codes to create an empty png file.
library(grid)
grid.newpage()
png(bg = "transparent")
pushViewport(viewport(width=.3, height=.3, clip="off"))
dev.off()
Then I read that png file to put inside the magic codes as below. Actually, there may exist a way to put the png file directly into the magic in your R session without making temporary write - read works. However ,if you have got a lot of files to create and save as png, it is not so important to read an empty png file once. Since it can be used as for all new outputs.
library(magick)
img <- image_read("./desktop/Rplot001.png")
output <- img %>% image_background("#008000") %>% image_resize("50x50") %>%
image_annotate("15.5", size = 17, gravity = "north", location = "+1+4",color = "black", boxcolor = NULL) %>%
image_annotate("13h 20m", size = 11, gravity = "south", location = "+0+7",color = "black", boxcolor = NULL)
image_write(output, path = "./desktop/output.png", format = "png")
It gives a 50x50 png file,

How can I make the legend numbers and text in bold?

I am plotting 2 rasters using this:
spplot(r, colorkey = list(space = "bottom", height = 1)) +
spplot(merged, cex=0.5, col.regions="green")
grid.text('Test', y=unit(0.025, "npc"),
rot=360, x=unit(0.5, "npc"))
How can I make the following things in bold and/or increase the size - a) Tick Numbers b) Legend Title
I am unsure about this answer. But, would setting the gp argument work in this case?
grid.text('Test', y=unit(0.025, "npc"),
rot=360, x=unit(0.5, "npc"),
gp=gpar(fontsize = 20, fontface="bold"))
For the tick numbers, try adding font = 2?
colorkey = list(space = "bottom", height = 1, labels = list(font = 2))
Damiano Fantini's solution works for me for the legend title.

Get aspect ratio of viewport at draw time with grid

I need to develop a new grid grob that is a customisation of segmentsGrob, but allows termination of the drawing at a specified length (i.e. cut 1 cm of the segment from the end). As the computations are a function of both the angle of the segment as well as the aspect ratio of the viewport (in absolute measures). The calculations needs to be pushed until drawing time using the drawDetails hook.
My question is how to get the absolute aspect ratio of the viewport in which the grob is being drawn? The context I'm using this in is ggplot2, and what I get if I query current.viewport().width or current.viewport().width is 1npc (thus not in absolute measures).
Example code
segmentsGrob2 <- function(x0 = unit(0, "npc"), y0 = unit(0, "npc"), x1 = unit(1, "npc"), y1 = unit(1, "npc"), startAdjust = unit(0, 'npc'), endAdjust = unit(0, 'npc'), default.units = "npc", arrow = NULL, name = NULL, gp = gpar(), vp = NULL) {
if (!is.unit(x0))
x0 <- unit(x0, default.units)
if (!is.unit(x1))
x1 <- unit(x1, default.units)
if (!is.unit(y0))
y0 <- unit(y0, default.units)
if (!is.unit(y1))
y1 <- unit(y1, default.units)
grid.draw(grob(x0 = x0, y0 = y0, x1 = x1, y1 = y1, startAdjust=startAdjust, endAdjust=endAdjust, arrow = arrow, name=name, gp=gp, vp=vp, cl="segments2"))
}
drawDetails.segments2 <- function(x, ...) {
asp <- getVpAspect() ### <-THIS IS WHAT I NEED
# Do some modifications to x relative to asp
grid:::drawDetails.segments(x, ...)
}

How to use grid.gradientFill

I'm trying to use the function grid.gradientFill from the gridSVG package, but unfortunately I'm not able to see a gradient in my SVG output.
I'm not sure if my code is correct or my Browser does not work (Chrome: 35.0.1916.153 m), can you please give some advise?
Here is my R code:
library(grid)
library(gridSVG)
lg <- linearGradient(col = c("black", "white", "black"))
x <- c(0.2,0.2,0.35,0.5,0.65,0.8,0.8,0.65,0.5,0.35)
y <- c(0.5,0.6,0.61,0.7,0.81,0.8,0.7,0.71,0.6,0.51)
s <- c(0,0,-1,0,-1,0,0,-1,0,-1)
grid.newpage()
vp <- viewport(width=0.75, height=0.75)
pushViewport(vp)
grid.rect(gp=gpar(col="blue"))
pushViewport(viewport(layout.pos.col=1, layout.pos.row=1))
grid.rect(x = unit(0.5, "npc"), y = unit(0.5, "npc"),
width = unit(1, "npc"), height = unit(1, "npc"),
just = "centre",
default.units = "npc",
gp=gpar(col="green", fill = "blue"), draw = TRUE, name = "tom")
grid.xspline(x = x, y = y,shape=s, open=FALSE, gp=gpar(col=NA, fill="darkred"), name="spline")
grid.gradientFill("spline", lg)
grid.gradientFill("tom", lg)
grid.export("c:/#temp/somekindofgradient.SVG")
I'm very interested in giving the spline a gradient ...
Any hint is appreciated :-)
So, finally I found the solution :-)
If you want to use
grid.gradientFill(object, ...)
The object, in my question the grid.xspline(...) object called "spline" does not have to have a fill parameter, meaning ...
Replacing
grid.xspline(x = x, y = y,shape=s, open=FALSE, gp=gpar(col=NA, fill="darkred"), name="spline")
with
grid.xspline(x = x, y = y,shape=s, open=FALSE, gp=gpar(col=NA), name="spline")
And there is some beautiful gradient :-)

Control font thickness without changing font size

I'm looking for a way to control the line thickness of text plotted in R without having the dimensions of the characters change. Here's an example (not using R):
The middle word has a thickness of twice the top, yet the dimensions are the same (so no scaling happened). The bottom word is actually two words: a red word overlain on a heavy white word, to create color separation (especially useful for annotating a busy plot).
Here's a set of commands I threw together to try and replicate the figure above:
png("font.png",width=1.02, height=1.02, units="in", res=150)
par(ps=10, font=1, bg="light gray", col="black", mai=rep(0.02,4), pin=c(1,1))
plot.new()
box()
text(0.5,0.85,"FONT",cex=1)
text(0.5,0.6,"FONT",cex=2)
text(0.5,0.3,"FONT",cex=2,col="white")
text(0.5,0.3,"FONT",cex=1,col="red")
text(0.5,0.1,"FONT",cex=1, font=2, col="white")
text(0.5,0.1,"FONT",cex=1, font=1, col="red")
dev.off()
giving:
So the effect is the same as changing the font-face to bold, but the size difference is not big enough to be noticeable when overlain. The par help page doesn't appear to have a specific setting for this. Anyone have any ideas?
Note changing size in ggplot2 doesn't produce the effect I want either, last time I checked.
You could try adding multiple versions of the text slightly shifted in a circular pattern,
library(grid)
stextGrob <- function (label, r=0.02, x = unit(0.5, "npc"), y = unit(0.5, "npc"),
just = "centre", hjust = NULL, vjust = NULL, rot = 0, check.overlap = FALSE,
default.units = "npc", name = NULL, gp = gpar(), vp = NULL){
let <- textGrob("a", gp=gp, vp=vp)
wlet <- grobWidth(let)
hlet <- grobHeight(let)
tg <- textGrob(label=label, x=x, y=y, gp=gpar(col="red"),
just = just, hjust = hjust, vjust = vjust, rot = rot,
check.overlap = check.overlap,
default.units = default.units)
tgl <- c(lapply(seq(0, 2*pi, length=36), function(theta){
textGrob(label=label,x=x+cos(theta)*r*wlet,
y=y+sin(theta)*r*hlet, gp=gpar(col="white"),
just = just, hjust = hjust, vjust = vjust, rot = rot,
check.overlap = check.overlap,
default.units = default.units)
}), list(tg))
g <- gTree(children=do.call(gList, tgl), vp=vp, name=name, gp=gp)
}
grid.stext <- function(...){
g <- stextGrob(...)
grid.draw(g)
invisible(g)
}
grid.newpage()
grid.rect(gp=gpar(fill="grey"))
grid.stext("Yeah", gp=gpar(cex=4))
There's a version using base graphics lurking in the archives of R-help, from which this is inspired.
Another option using a temporary postscript file, converted to a shape by grImport,
library(grImport)
cat("%!PS
/Times-Roman findfont
100 scalefont
setfont
newpath
0 0 moveto
(hello) show", file="hello.ps")
PostScriptTrace("hello.ps", "hello.xml")
hello <- readPicture("hello.xml")
grid.rect(gp=gpar(fill="grey"))
grid.picture(hello,use.gc = FALSE, gp=gpar(fill="red", lwd=8, col="white"))
I imagine something similar could be done with a temporary raster graphic file, blurred by some image processing algorithm and displayed as raster below the text.
You could try:
text(...,"FONT", vfont = c('serif','bold'))
Although I'm not sure how you'd do the third version of FONT.

Resources