2

I would like to create a plot with segements or arrows.

Let's say I have this toy example

temp <- data.frame(posi=c(1,2,3,3,2,1,5), from=c("A", "B", "C", "D", "D", "B", "A"), 
   to=c( "C", "D", "D", "C", "A", "A", "B"))

posi from to
  1    A  C
  2    B  D
  3    C  D
  3    D  C
  2    D  A
  1    B  A
  5    A  B

And I want to plot segments or arrows from the points defined by "from" and its starting position to the points defined by "to" and position+1.

I got to create the plot with ggplot

ggplot() + geom_point(data=temp, aes(x=posi, y=from, size=10),show.legend = FALSE) + 
geom_point(data=temp, aes(x=posi+1, y=to, size=10),show.legend = FALSE) + 
geom_segment(data=temp, aes(x=posi, y=from, xend=posi+1, yend=to), 
arrow=arrow(type="closed", angle=10), size=1.5, color="blue") + theme_bw()

But I would like to do it with Lattice because my real dataset is much bigger (millions of rows) and lattice works faster. I know I can reduce the number of lines removing duplicates but that's another story.

How can I do it with lattice?

I've been researchig and I think I need to use a panel.segments or lsegments, but things seem to be much more complicated and it's difficult to find examples.

 xyplot(from ~ posi , type="p", col="black",  data=temp, pch=16, 
     panel = function(x, y, ...){  panel.segments(x,y,)  })

I don't know what parameters to write inside function nor inside panel.

enter image description here

skan
  • 7,423
  • 14
  • 59
  • 96

1 Answers1

2

You could use the following code:

xyplot(from ~ posi , type="p", col="black",  data=temp, pch=16, xlim = c(0,7),
       panel = function(...){
         panel.dotplot(x = (temp$posi+1), y = temp$to, col="black", cex=1.4)
         panel.dotplot(x = temp$posi, y = temp$from, col ="black", cex=1.4)
         panel.arrows(x0 = temp$posi, y0 = temp$from, x1 = temp$posi+1, y1 = temp$to, lwd=3, col="blue", )
       }
)

yielding the following graph:

enter image description here

Please let me know whether this is what you want.

UPDATE

I posted a question concerning the problem that @skan identified and described in the comments: when a "extreme" level (like "D") is not present in temp$from then the "D" will not part of the graph, even when "D" will be needed later for temp$to. The question with answer from @Konn may be found here.

As I understand it now, we need a factor that is ordered, and we need an addition to the code specifying drop.unused.levels = FALSE in the call to xyplot. In the example we show the full set with "extremes" in "from" and as subset where the extreme "D" is absent: The full code is:

l <- c("A", "B", "C", "D")
temp <- data.frame(posi = c(1, 2, 3, 3, 2), 
                   from= factor(c("A", "B", "C", "D", "D"), levels = l, ordered = TRUE),
                   to = factor(c("C", "D", "D", "C", "A"), levels = l, ordered = TRUE)
                   ) 


xyplot(from ~ posi , type="p", col="black",  data=temp, pch=16, xlim = c(0,7), 
       drop.unused.levels = FALSE,  ## the added code
       panel = function(...){
         panel.dotplot(x = temp$posi, y = temp$from, col ="green", cex=1.6)
         panel.dotplot(x = (temp$posi+1), y = temp$to, col="black", cex=1.)
         panel.arrows(x0 = temp$posi, y0 = temp$from, x1 = temp$posi+1, y1 = temp$to, lwd=2, col="blue" )
       })

temp <- temp[1:3, ]
xyplot(from ~ posi , type="p", col="black",  data=temp, pch=16, xlim = c(0,7), 
       drop.unused.levels = FALSE,  ## the added code
       panel = function(...){
         panel.dotplot(x = temp$posi, y = temp$from, col ="green", cex=1.6)
         panel.dotplot(x = (temp$posi+1), y = temp$to, col="black", cex=1.)
         panel.arrows(x0 = temp$posi, y0 = temp$from, x1 = temp$posi+1, y1 = temp$to, lwd=2, col="blue" )
       })

yielding the following pics:

enter image description here

enter image description here

I think we have solved this question.

KoenV
  • 4,113
  • 2
  • 23
  • 38
  • Yes, thank you. What about plotting arrows instead?. Is there any shorter way of doing it?, maybe using LatticeExtra? – skan Jun 22 '17 at 13:12
  • OK, I got to do it modyfying this line: panel.xyplot(x=c(temp$posi,temp$posi+1), y=unlist(temp[,c("from", "to")], use.names = FALSE), col="black", cex=1.4, pch=16) though I don't know wheter I would ever need to use "unique" to avoid problems – skan Jun 22 '17 at 13:26
  • Strangely sometimes your solution doesn't work (nor my modification). Please, try this example with ggplot and with lattice: temp <- data.frame(posi=c(1,2,3,3,2), from=c("A", "B", "C", "D", "D"), to=c( "C", "D", "D", "C", "A")). Don't we need to modify the first "xyplot(from ~ posi " formula adding information about "to"? – skan Jun 22 '17 at 13:35
  • You may use `panel.arrows` in stead of `panel.segments`. – KoenV Jun 22 '17 at 13:45
  • I think I've found the reason of one of the problems. "from" 's factor levels can be different from "to" 's factor levels. I'm trying to solve the problem. You can notice the problem with temp <- data.frame(posi=c(1,2,3), from=c("A", "B", "C"), to=c( "C", "D", "D")) – skan Jun 22 '17 at 14:18
  • I think you might be right. I also think we need to find a way to (pre-)define the Y-axis as an axis with four character labels (A--D) upfront. I haven't been able to solve this yet. – KoenV Jun 22 '17 at 19:08
  • @skan I posted a related question [here](https://stackoverflow.com/questions/44718072/lattice-xyplot-does-not-show-all-levels-of-factor-on-y-axis-incomplete-plot) – KoenV Jun 23 '17 at 09:38
  • Great. Thank you. – skan Jun 28 '17 at 10:45
  • I've also created a continuation for this question https://stackoverflow.com/questions/46695651/how-to-have-two-different-size-legends-in-one-ggplot where I ask how to create legends for the size of both the points and the arrows (width). Could you provide a solution for lattice, please? – skan Oct 24 '17 at 10:48