Showing posts with label ggplot2. Show all posts
Showing posts with label ggplot2. Show all posts

Monday, 6 August 2018

SWDChallenge - Dot Plot

Eurocontrol's CODA team publishes regular stats on airline punctuality in Europe, based on data provided directly by airlines.

Some of the graphics are showing their age, so the dot plot challenge was a good excuse to try something slightly different.

I picked the 'punctuality' graph. CODA doesn't name individual airlines, because this is about performance benchmarking, not pointing the finger. Airlines are told their own punctuality, then the graph allows them to compare against the other largest airlines. 


I wanted to achieve two things:
1) Make it easier to compare quarters (currently an airline will be in one horizontal position in one quarter, and another in the other).
2) Highlight the airlines with the most flights. Each airline's punctuality challenges are different, depending on where they fly, their fleet, whether they offer connecting flights etc. Improving punctuality provides a better service to passengers, whatever the size of airline - but larger airlines have more effect on the average performance of the whole network.

The data look something like this (with airline names anonymised..), after some ranks have been added, with a mutate_at(vars(Flt1,Punc1), funs(rank = min_rank(desc(.)))).  I fiddled with the data a bit to get some good tests (of decline, improvement, and stable), but in any case they are not final or official.


I tried two options. 

In both, I went for using triangles and tails to indicate the change since the previous quarter. But the triangles tend to point to the wrong place. Rather than work out how to nudge the triangles, I used a dot to emphasise the actual value.

The first option used size to distinguish larger airlines from smaller. I tried various options for dot, triangle size and transparency (alpha), but in the end, felt that there was just too much going on, and the big airlines did not stand out.


So I switched to using colour instead. It's still quite busy, but I think the result is better, and a step forward from the current 'legacy' graphs.


For the record, this was the code.

#calculate some values for the plot
w <- punc %>% 
  #edit some values to get good test
  mutate(Punc0 = if_else(Punc1_rank %in% c(14, 32,44), Punc1, Punc0)) %>% 
  #calculate shapes and size
  mutate(col = if_else(Flt1_rank <= bigRank, "black", "cyan3"),
         shape = case_when(
           Punc1 == Punc0 ~ 1, #circle
           Punc1 >= Punc0 ~ 24, #up arrow
           TRUE           ~ 25))

#where to label
annoX <- min(w$Punc1)

ggplot(w) + 
  #last quarter
  geom_segment(aes(x = Punc1_rank, y=Punc0, xend= Punc1_rank, yend=Punc1, colour = col), alpha=0.5)+ 
  #this quarter - direction triangles
  geom_point(aes(x = Punc1_rank, y=Punc1, shape = shape, colour = col), size = 3) +
  #this quarter - points
  geom_point(aes(x = Punc1_rank, y=Punc1, colour = col), size = 0.7) +
  annotate("text", x = 1, y = annoX, size = 2.5, 
           hjust = 0, vjust = 0,
           label = paste("Black = Top 10 airlines by flights in",q1,
                          "\nArrow tail = punctuality in",q0)) +
  scale_shape_identity() + #use the value directly as a shape
  scale_colour_identity() + #use the value directly as a size
  labs(x="Rank of airline by punctuality (best to worst). Top 50 airlines by flights are shown.",
       y=paste("Arrival Punctuality in",q1,"(Delay < 15 minutes)")) +
  scale_x_continuous(breaks = c(1, seq(5, maxRank, by = 5)),
                     minor_breaks = NULL) +
  scale_y_continuous(labels= scales::percent) +
  theme_minimal()


Sunday, 25 September 2016

Thorn Plot, for visualising head winds, final version

Continuing the short series on plotting headwinds, perhaps you prefer the 'thorn plot' version, in which the relative frequency of wind from a particular direction is represented both by transparency of colour and also by the width of the triangle.


For this version, I finally remembered to normalise the number of observations between locations. There are more records for some airports than others, but this is irrelevant for the graph, so I rescale.


Saturday, 24 September 2016

Final daisy plot for visualising head wind when cycling.

Got there in the end. I know he guidance is that colour is not the best way to show variation, but this 'daisy plot' works for me, and is less untidy than the 'thorn' variation.

The curved line comes from those explicitly drawn by ggplot in the geom_poly statement, so repeating the start point of the poly gave me a balanced curve on both sides (which gives a clue as to how to get straight lines, but I'm sticking with this version).

Quite a lot of ggplot in the end:

ggplot(y8p , aes(x, y, group = windHead, alpha = numObs)) + 
  scale_alpha(range = c(0.3, 1), breaks = seq(0, 24000, by = 4000)) + 
  geom_polygon(fill = "blue") +
  xlab("Angle = Wind heading (deg) ") + 
  ylab("Mean wind speed (km/h)") +
  labs(alpha = "Observations") +
  coord_polar(start = -pi/8) + 
  scale_y_reverse(limits = c(maxKMH, 0)) + 
  scale_x_continuous(limits = c(-22.5,337.5), breaks = NULL) +
  geom_label(aes(x=0, y = maxKMH, label = station), colour = "black",
             show.legend = FALSE) +
  #theme(legend.position = c(1,0), legend.justification = c(1,0)) + 
  theme(strip.background = element_blank(),
        strip.text.x = element_blank()) +
  facet_wrap( ~ station)

For which, the y8p data looks like this. Note that I've created 4 lines for each real line of data - and x and y give the 4 points used in the polygon for each real point of data.

  station windHead   windKPH numObs     x         y
    <chr>   <fctr>     <dbl>  <int> <dbl>     <dbl>
1    EBBR        0  9.167982   7190   0.0  9.167982
2    EBBR        0  9.167982   7190  22.5  0.000000
3    EBBR        0  9.167982   7190 -22.5  0.000000
4    EBBR        0  9.167982   7190   0.0  9.167982
5    EBBR       45 10.177946   7358  45.0 10.177946
6    EBBR       45 10.177946   7358  67.5  0.000000

More Pies, Roses and Thorns

Continuing the hunt for ways to show headwind, rather prettier are these version, using an explicit geom_polygon to construct triangles.

In the first version, I'm using both transparency and thickness to code the number of observations (frequency that the wind was in this direction). I think this looks like thorns. Haven't worked out why the axis transform should put the twist on the triangles. Suggestions welcome!

In the second version, I've stuck to fixed width. This is more like the diaphragm of a camera, or a daisy.