Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Align different plot shapes

Background:

I have a kind of Gantt chart, composed of horizontal segments with different events marked by symbols of different shapes. I want the symbols to have exactly the same height as the segment (potential topic for next question!), and symbols should be center aligned within each segment.

Issue:

The problem is that different shapes seem to have different alignment. In my small example, shape 0, 3, 4, 5 are center aligned (four first symbols from left). In contrast, the circle and the two triangles are offset.

d1 <- data.frame(x = -1, xend = 7, y = 1, yend = 1)
d2 <- data.frame(x = 0:6, y = 1)

library(ggplot2)
ggplot(data = d1, aes(x = x, y = y)) +
  geom_segment(aes(xend = xend, yend = yend), size = 8, color = "grey80") +
  geom_segment(aes(xend = xend, yend = yend), color = "red") +
  geom_point(data = d2, shape = c(0, 3, 4, 5, 1, 2, 6), size = 8) +
  theme_void()

enter image description here

Zoom in on PDF output: enter image description here


I have also desperately tried a geom_text equivalent with unicode symbols. However, the alignment is now even harder to fathom.

geom_text(data = d2,
          label = c("\u25A1", "\uFF0B","\u2715","\u25C7", "\u25CB", "\u25B3", "\u25BD"),
          size = 8, vjust = "center") 

No obvious hints in ?geom_point, ?aes_linetype_size_shape or ?pch. I have googled "r plot align center justify symbol shape pch" - have I missed any keywords?


Question: How can I align different shapes without hardcoding?

like image 226
Henrik Avatar asked Apr 02 '17 11:04

Henrik


People also ask

How do you align and distribute objects in Word?

Hold the Shift (or Ctrl) key and click the objects you want to distribute. On the Format tab, click the Align command, then select Distribute Horizontally or Distribute Vertically. The objects will be evenly spaced from one another.

How do I snap a shape in Excel?

Turn on the snap-to optionsClick the shape or other object, and then on the Shape Format tab, under Arrange, click Align. Do one or both of the following: To snap shapes or other objects to the closest intersection of the grid, click Snap to Grid. Gray highlighting indicating the option is selected turns on.


2 Answers

It's not really an answer, but didn't fit in a comment.

To me, the circle isn't worse than the square, and looking at all first 26 symbols (pch = 0:25), it seems that (theoretically, not sure about various devices) only the triangles wouldn't fit your purpose.
I think it's generally reasonable that the point they represent sits at their mass center, because that's where the eye would expect it with the most common use cases of such symbols.

Proof for the mass center is here: https://github.com/wch/r-source/blob/91dda45a5e4e418d0efed17db858736a973d4996/src/main/engine.c

void GESymbol(...

case 2: /* S triangle - point up */
        xc = RADIUS * GSTR_0;
        r = toDeviceHeight(TRC0 * xc, GE_INCHES, dd);
        yc = toDeviceHeight(TRC2 * xc, GE_INCHES, dd);
        xc = toDeviceWidth(TRC1 * xc, GE_INCHES, dd);
        xx[0] = x; yy[0] = y+r;
        xx[1] = x+xc; yy[1] = y-yc;
        xx[2] = x-xc; yy[2] = y-yc;
        gc->fill = R_TRANWHITE;
        GEPolygon(3, xx, yy, gc, dd);
        break;

So you could of course modify the source here to say:

yy[0] = y + (r+yc)/2;

yy[1] = y - (r+yc)/2;

yy[2] = y - (r+yc)/2;

like image 184
RolandASc Avatar answered Oct 04 '22 05:10

RolandASc


I have a feeling that this problem doesn't have a solution (at least not one that is reasonably feasible). The issue itself seems to be rooted in grid which is what ggplot2 is built upon. For example:

library(grid)
grid.newpage()
vp <- viewport()
pushViewport(vp)
grid.rect(x = 0.5 , y = 0.5 , width= 1 , height = 0.14)
grid.points(x = 0.1 , y = 0.5, pch = 0 ,size = unit(1,"in"))
grid.points(x = 0.3 , y = 0.5, pch = 24 ,size = unit(1,"in"))
grid.points(x = 0.5 , y = 0.5, pch = 25  ,size = unit(1,"in"))

enter image description here

Because of this I think it is highly unlikely that there will be any ggplot2 options that will fix it. As RolandASc points out I think your best bet is to modify the source data to adjust for the offset of the symbols though I believe this in practice is very risky and personally wouldn't advise doing it.

like image 34
gowerc Avatar answered Oct 04 '22 03:10

gowerc