I am trying to plot a Rgraphviz object with two edge labels. Unfortunately the labels fall outside the plot. Here is my example:
require('Rgraphviz')
set.seed(123)
g1 <- randomGraph(letters[1:10], 1:4, 0.4)
eAttrs <- list()
eAttrs$label <- c("a~g" = "I have a very long label 1", "a~i" = "and a long label 2")
plot(g1, edgeAttrs = eAttrs)
Here is my plot:
I tried several things with no success:
1.
Set a larger bounding box
z <- agopen(g1, "foo")
z#boundBox#upRight#x <- z#boundBox#upRight#x + 300
z#boundBox#upRight#y <- z#boundBox#upRight#y + 300
plot(z, edgeAttrs = eAttrs)
2.
Decrease the label fontsize (not really what I want in my application, anyways)
eAttrs$labelfontsize=c("a~g"="3")
plot(g1, edgeAttrs = eAttrs)
3.
Change par attributes:
par(oma=c(10,10,10,10))
plot(g1, edgeAttrs = eAttrs)
4.
Change node, edge and general attributes from ?Rgraphviz::GraphvizAttributes
attrs <- list(graph=list(size=c(1, 1)))
attrs$edge$fontsize<-8
plot(g1, edgeAttrs = eAttrs, attrs=attrs)
None of my attempts seem to work. Does anyone have an idea?
The problem
Calling plot() on a graph object dispatches an S4 method (shown by getMethod("plot", "graph")), which in turn calls the function shown by typing getMethod("plot", "Ragraph"). That function contains the following rather unfortunate lines which, regardless of any related parameter settings you've made, will override them to reset the left and right margins to 0. Frustrating!
oldpars <- par(mai = c(sheight, 0, mheight, 0))
on.exit(par(oldpars), add = TRUE)
A workaround
One workaround is to construct a three panel layout in which the left and right panels are just there to provide a bit of buffering space. Turn off clipping, plot your graph object in the middle panel, and it then seems to work:
layout(matrix(1:3, nrow=1), widths=c(1,5,1))
par(xpd=NA) ## turn off all clipping
plot.new() ## blank plot in Panel 1
plot(g1, edgeAttrs = eAttrs) ## graph in Panel 2
plot.new() ## blank plot in Panel 3
I found another solution: In my original question I changed the size of the bounding box in a laid out graph I got with agopen. Plotting the laid out graph showed no edge labels at all. I found that it is possible to pass the edge attributes from the graph object to agopen and then change the bounding box:
require('Rgraphviz')
set.seed(123)
g1 <- randomGraph(letters[1:10], 1:4, 0.4)
eAttrs <- list()
eAttrs$label <- c("a~g" = "I have a very long label 1", "a~i" = "and a long label 2")
z <- agopen(g1, "foo", edgeAttr=eAttrs)
z#boundBox#botLeft#x <- z#boundBox#botLeft#x - 400 ##left
z#boundBox#upRight#x <- z#boundBox#upRight#x + 200 ##right
plot(z)
The plot:
Related
When using latticeExtra:::c.trellis to combine plots, the right-side tick marks and text/numeric labels go missing, and I'd like to bring them back:
library(latticeExtra)
set.seed(1)
foo <- data.frame(x = 1:100,
y = 1:100 + rnorm(100))
foo$resid <- with(foo, x-y)
## Plot 1 -----
(p1 <- xyplot(y~x, foo))
## Plot 2 -----
(p2 <-
xyplot(resid~x, foo,
scales = list(rot = 0, tck = c(1,1), alternating = 3),
between = list(y = 1), ylab.right = "ylab.right",
# par.settings = list(axis.components =
# list(right = list(pad1 = 2, pad2 = 2)))
# Note: this padding attempt does not restore the missing ticks,
# pad arguments get ignored when using c.trellis below
))
# tick marks appear on all four sides (as desired)
## Combine -----
(p12 <- latticeExtra:::c.trellis(p2, p1,layout = c(1,2)))
# right tick marks are missing
Is there a way to restore the right-side ticks and/or labels manually, say, by modifying the combined trellis object?
From the help file ?c.trellis:
Description
Combine the panels of multiple trellis objects into one.
and later,
Note that combining panels from different types of plots does not really fit the trellis model. Some features of the plot may not work as expected. In particular, some work may be needed to show or hide scales on selected panels. An example is given below.
It looks to me that you really aren't trying to combine panels into one object. You even use between to put some separation. Rather, you are trying to combine two plots.
You can use print,
print(p1,split=c(1,1,1,2),more=TRUE)
print(p2,split=c(1,2,1,2),more=FALSE)
See ?print.trellis.
In R, using package rgl, I'd like to add the shadows of the points in plot3d(), just like in the image below.
I've added the bottom grid using grid3d(), but still have no clue on how to add the shadows. If I plot the same points changing the 3rd axis value to its minimum value (-100 in the image), the plot area automatically increases, leaving a gap between the points and the grid. Is there a better way to do that?
I think it was obvious from the question, but here is a sample code:
library(rgl)
df <- data.frame(x=rnorm(100),
y=rnorm(100),
z=rnorm(100))
plot3d(df)
grid3d('z')
The idea of setting z to the minimal value fails because rgl makes the bounding region slightly bigger. But you can grab the z value from the grid, and use that. You can also tell rgl not to expand the bounding box to include the new points. This code does both things:
library(rgl)
df <- data.frame(x=rnorm(100),
y=rnorm(100),
z=rnorm(100))
plot3d(df)
id <- grid3d('z') # Get id values for grid
gridz <- rgl.attrib(id[1], "vertices")[1,3] # Use the first z value
save <- par3d(ignoreExtent = TRUE) # Ignore points for bbox
with(df, points3d(x, y, gridz, col = "gray"))# Plot the "shadows"
par3d(save) # Restore bbox status
Here's what I get:
there is now the convenience show2d function available to produce the desired 2D projections
library(rgl)
df <- data.frame(x=rnorm(100),
y=rnorm(100),
z=rnorm(100))
plot3d(df)
grid3d('z')
show2d({
par(mar=c(0,0,0,0))
plot(x = df$x, y = df$y,
col = "black")
})
I have a plot() where multiple colour shadings represent the same thing. I would like to add a legend that conveys this by having dual-coloured boxes (see example below). Is there any way to do this using legend() or a similar command? Alternatively, is there a way to identify the precise coordinates of these boxes so I can plot a polygon() triangle over it?
Note: legend() does return the coordinates of the outer box and the top left of each labels, but I am not sure if this is sufficient to calculate where the coloured boxes are.
This is a bit of a hack, but you could put two legends on top of another. Unfortunately, there is no left triangle pch which would have been exactly as you wanted.
plot(1)
legend("bottomright",c("Label 1", "Label 2"),pch=22,col=c("red","blue"),pt.bg=c("red","blue"), pt.cex=1.8)
legend("bottomright",c("Label 1", "Label 2"),pch=21,col=c("green","orange"),pt.bg=c("green","orange"))
A slightly dirty hack can allow you to get the legend() function to give you the necessary information. A smarter person than me would probably work out how legend() calculates box positioning and replicate this outside the function. Note that editing standard R functions is probably not recommended.
If you have not edited R functions yet, an easy (and temporary) way to access it, is typing
fix(legend)
Typing
rm(legend)
later will undo your changes.
Find this section that says fill <- rep and add the lines indicated by the comments:
fillList <- NULL ## added
if (mfill) {
if (plot) {
fill <- rep(fill, length.out = n.leg)
rect2(left = xt, top = yt + ybox/2, dx = xbox, dy = ybox,
col = fill, density = density, angle = angle,
border = border)
fillList <- data.frame(left = xt, top = yt + ybox/2, dx = xbox, dy = ybox) ## added
}
xt <- xt + dx.fill
}
Find the very last line and change it to
invisible(list(rect = list(w = w, h = h, left = left, top = top),
text = list(x = xt, y = yt), fillList=fillList)) ## modified
Now call legend via
output <- legend(...) ## replace ... with whatever you want to have as inputs
and the draw triangles using the information returned by legend() like so:
with(output$fillList[1,], { ## first box
polygon(c(left, left+dx, left+dx), c(top, top, top-dy), col=myColour, border=NA)
})
The gridExtra package adds a grob of class "pattern" that lets one fill rectangles with patterns. For example,
library(gridExtra)
grid.pattern(pattern = 1)
creates a box filled with diagonal lines. I want to create a stack of panels in which each panel is filled with these diagonal lines. This is easy:
library(lattice); library(gridExtra)
examplePlot <- xyplot(
1 ~ 1 | 1:2,
panel = function () grid.pattern(pattern = 1),
layout = c(1, 2),
# Remove distracting visual detail
scales = list(x=list(draw=FALSE), y=list(draw=FALSE)),
strip = FALSE, xlab = '', ylab = ''
)
print(examplePlot)
The problem is that the diagonal lines aren't aligned across panels. That is, there is a visual "break" where the bottom of the first panel meets the top of the second panel: at that point, the lines don't line up. This is the problem that I want to fix.
I can eliminate most of the visual break by adding the argument pattern.offset = c(.2005, 0) to the grid.pattern call, and making sure that it applies only to the bottom panel. But this solution doesn't generalize. For example, if I change the pattern (e.g., by using the granularity argument to grid.pattern), this solution won't work. Is there a more general fix?
To make this work, you'll have to take charge of setting the panel.height argument used by print.trellis. (To see why, try resizing your plotting device after running your example code: as the size of the device and the panels changes, so does the matching/mismatching of the lines):
## Calculate vertical distance (in mm) between 45 degree diagonal lines
## spaced 5mm apart (the default distance for grid.pattern).
vdist <- 5 * sqrt(2)
nLines <- 8L ## can be any integer
panelHeight <- list(x = nLines*vdist, units = "mm", data = NULL)
## Plot it
print(examplePlot, panel.height=panelHeight)
I would like two plots to show up in two seperate spaces in the plot so I do:
par(mfrow=c(1,2))
plot(1:10,1:10)
Now I would like the second plot to be about 25% shorter than the first plot so I adjust omd:
tmp <- par()$omd
tmp[4] <- 0.75
par(omd=tmp)
plot(1:10,1:10)
The problem is that the second plot shows up ontop of the first plot. How do I avoid this margin issue?
Maybe try using layout instead?
layout(matrix(c(1, 1, 0, 2), ncol = 2L), widths = c(1,1),heights = c(0.5,1))
par(mar = c(3,2,2,2))
plot(1:10,1:10)
par(mar = c(3,2,2,2))
plot(1:10,1:10)
I guess maybe you'd want to set the heights to c(0.2,0.8) to get a 25% reduction?
Edit
But I don't think that omd does what you think it does. It changes the region inside the outer margins, which will always include both plot regions when setting par(mfrow = c(1,2)). What you really want to change, I think is plt, which alters the size of the current plotting region (using quartz, as I'm on a mac):
quartz(width = 5,height = 5)
par(mfrow=c(1,2))
vec <- par("plt")
plot(1:10,1:10)
par(plt = vec * c(1,1,1,0.75))
plot(1:5,1:5)