20

I was wondering if there is any package in R that could use x, y coordinates and shape sizes to draw something like this:

enter image description here

I have the coordinates of vehicles' front centers and their sizes (length and width).

Edit

This is what the original data set looks like:

> head(df)
  Vehicle.ID Frame.ID Global.X Global.Y Vehicle.Length Vehicle.width Lane Preceding.Vehicle.ID Following.Vehicle.ID Spacing Headway
1          2       43  6451214  1873261           14.5           4.9    2                    0                   13       0       0
2          2       44  6451217  1873258           14.5           4.9    2                    0                   13       0       0
3          2       45  6451220  1873256           14.5           4.9    2                    0                   13       0       0
4          2       46  6451223  1873253           14.5           4.9    2                    0                   13       0       0
5          2       47  6451225  1873250           14.5           4.9    2                    0                   13       0       0
6          2       48  6451228  1873247           14.5           4.9    2                    0                   13       0       0

For any given frame, I want to visualize the gaps, e.g., for frame no. 500:

ff <- subset(df, Frame.ID==500)
qplot(x=Global.X, y=Global.Y, data=ff)

enter image description here

All these dots are the front center coordinates of vehicles. I don't know how to display the length and width of each vehicle and label the gap values.

Dason
  • 60,663
  • 9
  • 131
  • 148
umair durrani
  • 5,597
  • 8
  • 45
  • 85
  • 6
    I'm sure you *could*, but I'd strongly recommend using another tool for this job. My choice would be tikZ if you want it programmatic, or some WYSIWYG drawing program if you only need a handful of diagrams. – Gregor Thomas Mar 03 '14 at 23:01
  • I have thousands of vehicles and each vehicle's movement (in terms of changing coordinates) was recorded for several time frames. I want to be able to plot this type of diagram at any instant of time (i.e. at any given frame). The vehicle like view from top is not important, simple rectangle (drawn using length and width) is fine – umair durrani Mar 03 '14 at 23:23
  • 5
    While this task may strike people as interesting (which is the only way I can imagine anyone would up vote it, let alone 6 people), it is not a suitable question for SO in its current form. Asking for package/library recommendations is generally off topic here, and beyond that you have not provided any concrete example data for people to work with. If you have a specific attempt, with some actual data that you'd like feedback on, that would be fine. Otherwise, this should be closed. – joran Mar 03 '14 at 23:29
  • it sounds like the `rect()` function will probably do everything you want ... – Ben Bolker Mar 03 '14 at 23:30
  • I'd concur with @shujaa and recommend something like [Processing](http://processing.org/) as a much better tool for this kind of thing. – geotheory Mar 03 '14 at 23:53
  • @joran I've now included what I tried – umair durrani Mar 04 '14 at 00:12
  • this might help http://journal.r-project.org/archive/2009-1/RJournal_2009-1_Murrell.pdf – baptiste Mar 04 '14 at 00:53
  • This is a good question now! What a difference from the original where it looked like you wanted to reproduce a diagram illustrating what terminology means. – Gregor Thomas Mar 04 '14 at 01:17
  • Where is the lane info? Your sample `df` does not appear to show what lane vehicles are in. Presumably `Global.Y` is not it, at least based on my understanding of freeways. – BrodieG Mar 04 '14 at 03:07
  • @BrodieG df updated with lane number – umair durrani Mar 04 '14 at 03:23

1 Answers1

76

So, I don't advocate you rely on ggplot to do this as most likely some of the other suggested solutions are better, but this problem got me interested as I've been meaning to dig into the guts of ggplot for a while. This is what I managed to come up with:

ggplot(df, aes(x=x, y=y, length=length, width=width, fill=label)) +
  geom_hline(yintercept=seq(5, 35, by=10), color="white", size=2, linetype=2) +
  geom_car() +
  coord_equal() +
  theme(panel.background = element_rect(fill="#555555"), 
    panel.grid.major = element_blank(),
    panel.grid.minor = element_blank())

enter image description here

You can also add arrows with geom_segment or explicit labels with geom_text, but we leave that as an exercise for the reader.

Now, for this to work, we had to create geom_car, though if you don't require detailed pictures, you could just use geom_rect. Here is geom_car (note: also now available as part of the ggbg package):

# Generate a car 'grob' using a baseline PNG

car.raster <- png::readPNG("~/Downloads/car2.png")

# The `grid` grob actually responsible for rendering our car, 
# combines our transparent car elements with a background rectangle
# for color/fill.

carGrob <- function(x, y, length, width, gp) {
  grid::grobTree(
    grid::rectGrob(
      x, y, hjust=.5, height=width, width=length,
      gp = gp
    ),
    grid::rasterGrob(
      car.raster, x=x, y=y, hjust=.5, height=width, width=length
) ) }
# The `ggproto` object that maps our data to the `grid` grobs

GeomCar <- ggplot2::ggproto("GeomCar", ggplot2::Geom,
  # Generate grobs from the data, we have to reconvert length/width so
  # that the transformations persist

  draw_panel=function(self, data, panel_params, coords) {
    with(
      coords$transform(data, panel_params),
      carGrob(
        x, y, length=xmax-xmin, width=ymax-ymin,
        gp=grid::gpar(
          col = colour, fill = alpha(fill, alpha),
          lwd = size * .pt, lty = linetype, lineend = "butt"
  ) ) ) },
  # Convert data to coordinates that will get transformed (length/width don't
  # normally).

  setup_data=function(self, data, params) {
    transform(data,
      xmin = x - length / 2, xmax = x + length / 2,
      ymin = y - width / 2, ymax = y + width / 2
  ) },
  # Required and default aesthetics

  required_aes=c("x", "y", "length", "width"),
  default_aes = aes(
    colour = NA, fill = "grey35", size = 0.5, linetype = 1, alpha = NA
  ),
  # Use the car grob in the legend

  draw_key = function(data, params, size) {
    with(
      data,
      carGrob(
        0.5, 0.5, length=.75, width=.5,
        gp = grid::gpar(
          col = colour, fill = alpha(fill, alpha),
          lwd = size * .pt, lty = linetype, lineend = "butt"
  ) ) ) }
)
# External interface

geom_car <- function(
  mapping=NULL, data=NULL, ..., inherit.aes=TRUE, show.legend=NA
) {
  layer(
    data=data, mapping=mapping, geom=GeomCar, position="identity",
    stat="identity", show.legend = show.legend, inherit.aes = inherit.aes,
    params=list(...)
  )
}

The car:

enter image description here

The data:

df <- read.table(h=T, t="vehicle  x y   length  width   label
1   150 10  14  5   other
2   180 8   12  5   other
3   220 10  18  5   other
4   145 20  15  5   target
5   250 18  14  5   other
6   160 30  13  5   autonomous
7   200 33  15  5   other
8   240 31  22  5   other
")
BrodieG
  • 51,669
  • 9
  • 93
  • 146
  • 1
    @BrodieG Hadley asked if he could share this in the next ggplot2 book on twitter https://twitter.com/hadleywickham/status/609456138472394752 – Tyler Rinker Jun 13 '15 at 20:07
  • 1
    @TylerRinker, thanks for the heads up; might have been a while before I noticed otherwise. – BrodieG Jun 13 '15 at 20:20
  • This is great, but it needs more frogs. :) – jbaums Jun 18 '15 at 21:07
  • When I run the `GeomCar` part, it gives me: `Error in eval(expr, envir, enclos) : could not find function "eval"`. Why is that? The only thing I did different was using another top view for car.png – umair durrani Feb 01 '17 at 20:07
  • @umairdurrani it is possible that ggplot has changed enough since I wrote this answer that it no longer works. I don't have time to look into it now, but I'll try at some point later. – BrodieG Feb 01 '17 at 21:12
  • 2
    It almost certainly is a Ggplot2/prooto changes issue. A lot has changed, particularly how to do extensions. I'm afraid I don't have time to devote to this, but perhaps you can ask this question again in the form "how can I replicate this answer with the newer versions of Ggplot2" and someone will be willing to take a crack at it. – BrodieG Feb 02 '17 at 12:00
  • 2
    @umairdurrani should now work with new version of ggplot2. – BrodieG May 07 '18 at 01:41