How to plot segments or arrows with Lattice in R?

2019-02-20 01:17发布

问题:

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.

回答1:

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:

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:

I think we have solved this question.