I am creating visualization of all nodes and edges involved in a shortest path between two vertices. Without giving unnecessary details, the nodes represent organisms, and the edges represent a parent-child relationship between them. The x-axis of the node indicates its birthyear, whereas the y-axis is simply the index of the node in the path (adjacent nodes are separated by a value of unity).
I will show my issue with the following training data set:
xstart=c(1966, 1967,1977,1975,1958)
ystart=c(1.1,2.1,3.1,4.1,5.1)
xend=c(1967,1977,1975,1958,1958)
yend=c(1.9,2.9,3.9,4.9,5.1)
x=c(1966,1967,1977,1975,1958)
y=c(1,2,3,4,5)
xustart=c(1964,1965,1975,1973,1956)
xuend=c(1968,1969,1979,1977,1960)
yustart=c(0.9,1.9,2.9,3.9,4.9)
yuend=c(0.9,1.9,2.9,3.9,4.9)
xostart=c(1964,1965,1975,1973,1956)
xoend=c(1968,1969,1979,1977,1960)
yostart=c(1.1,2.1,3.1,4.1,5.1)
yoend=c(1.1,2.1,3.1,4.1,5.1)
label=c("node1","node2","node3","node4","node5")
path.plot <- data.frame(label,xstart,ystart,xend,yend,x,y)
If I simply create nodes and edges (where edges enter and leave nodes at the center x-value of the text label), I find the visual looks unappealing:
ggplot(data=path.plot) +
geom_segment(aes(x=xstart, y=ystart, xend=xend, yend=yend)) +
geom_text(aes(x=x, y=y, label=label))
I think it looks a little better with underlines, but still sloppy:
ggplot(data=path.plot) +
geom_segment(aes(x=xstart, y=ystart, xend=xend, yend=yend)) +
geom_segment(aes(x=xustart, y=yustart, xend = xuend, yend = yuend)) +
geom_text(aes(x=x, y=y, label=label))
In all honesty, I thought that having the edges connect to the bottom left and write corners of the text label underline would look best (for example, incoming edge connects to the left point of underline, outgoing edge connect to the right point of underline).
However, that would not work as exampled by node1 and node2, where the edge leaving node1 would cross some of the text out, and also end up as a negative-slope edge, which can be deceiving because node2 is at a later date (1967) than node1 (1966).
So, then I tried both underlining and overlining:
ggplot(data=path.plot) +
geom_segment(aes(x=xstart, y=ystart, xend=xend, yend=yend)) +
geom_segment(aes(x=xustart, y=yustart, xend = xuend, yend = yuend)) +
geom_segment(aes(x=xostart, y=yostart, xend = xoend, yend = yoend)) +
geom_text(aes(x=x, y=y, label=label))
I think this looks the best, but if you have any suggestions for improvement, I would take it into account. In any case, my main question is how to create the width of the underlines/overlines to be in proportion to the width of the label of the nodes? Because my node titles will not always be of the same length (I just used generic titles for example). Their labels could greatly differ in lengths, so having a consistent-length underline does not work.
Another problem with the current underline/overline is that if I readjust the image size, the text label lengths will change in proportion to the underline/overline lengths, and suddenly it looks ridiculous! So, I guess I am also trying to find a way to connect the length of the underline/overline to the length of the text so that they are not only guaranteed to be in proportion, but guaranteed to stay in proportion when the image size is readjusted.
Thank you...
I took into account the strwidth option and the rectangles (from the first comment) - it looks visually appealing. However, it still has problems when I resize (the label length and rectangle length do not stay proportion when resizing image). For instance, if I make the image a bit smaller in my plots window of R studio, the labels bleed over the rectangles. I am not using a static image, so I cannot simply just save the image at the correct size.
Below is what I did as an update, but still wonder if I can keep the label/rectangle lengths proportion even when the overall image is resized:
# Made one label longer than the others
label=c("node1","node238968396849223","node3","node4","node5")
textFrame = data.frame(x = x, y = y, label = label)
textFrame = transform(textFrame,
w = strwidth(label, 'inches') + 0.25,
h = strheight(label, 'inches') + 0.25
)
ggplot(data = path.plot,aes(x = x, y = y)) +
geom_rect(data = textFrame, aes(xmin = x - strwidth(label, "inches")*1.2, xmax = x + strwidth(label, "inches")*1.2,
ymin = y-.1, ymax = y+.1), fill = "grey80") +
geom_segment(aes(x=xstart, y=ystart, xend=xend, yend=yend)) +
geom_text(data = textFrame,aes(x = x, y = y, label = label), size = 4)