<p><div><div><div><div data-width="100" data-show-faces="false" data-send="true" data-layout="button_count" data-height="21" data-href="https://www.r-bloggers.com/metro-systems-over-time-part-3/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="https://datascienceplus.com/metro-systems-over-time-part-3/"> DataScience+</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p>Note, at the time of this writing using the packages <code>ggplot2</code> and <code>ggmap</code> from CRAN will result in an error. To avoid the error be sure to install both packages from GitHub with the package <code>devtools</code> and restart R if the problem persists.</p>
<pre>
devtools::install_github(&quot;dkahle/ggmap&quot;)
devtools::install_github(&quot;hadley/ggplot2&quot;)
</pre>
<p>Note, at the time this writing the package <code>gganimate</code> requires the package <code>cowplot</code>. Be sure to install and load the package before continuing.</p>
<pre>
install.packages(&quot;cowplot&quot;)
library(cowplot)
</pre>
<h2>Introduction</h2>
<p>In <a target="_blank" rel="nofollow" href="https://datascienceplus.com/metro-systems-over-time-part-1/">Part 1</a> and <a target="_blank" rel="nofollow" href="https://datascienceplus.com/metro-systems-over-time-part-2/">Part 2</a> of this series we made maps of metro systems across four European cities, and then computed Delaunay triangulations and centroids for each city. In the third and final part, we’ll do these same steps but at multiple time points to make a .gif of how metro systems change over time.</p>
<h2>Data</h2>
<p>As a reminder, our data is the hand corrected values of the data we pulled down from Google. To see how we got the data go back to <a target="_blank" rel="nofollow" href="https://datascienceplus.com/metro-systems-over-time-part-1/">Part 1: Data</a>.</p>
<h2>Maps with Change Over Time</h2>
<p>We now have a good sense of what each city’s current metro system looks like, but how did these systems come to be this way? Now we’ll look at how these systems have changed and grown over time. That’s why at the beginning we made a column for <code>opened_year</code>. At this point the code gets less elegant but we’ll go through it step by step. It’s all the same principles as when we made our figures earlier.</p>
<p>The main idea of the following code is that we’re going to create unique triangulations for each year within each city. As more metro stations get added each year the triangulation will change. Just as we had <code>data_deldir_delsgs</code> and <code>data_deldir_cent</code>, we’re going to start by creating two empty data frames <code>time_deldir_delsgs</code> and <code>time_deldir_sum</code> (remember that our centroid data frame was based on the summary data). With our empty data frames initialized we can make a <code>for loop</code>. We want to go through each year, but for each city separately, so our first <code>for loop</code> goes through each city, filtering our data to only the city in question. Next we have our second <code>for loop</code> going through each year starting with the minimum year in the data for that city and up to 2015, the maximum year for the full data set. For a given year we <code>filter()</code> to include only metro stops that were opened that year or earlier. We do equal to or less than because we don’t want to ignore metro stops from earlier years, we want the whole metro system as it exists for a given year. Note, we need at least three points to make a triangle, and you may think that a city wouldn’t ever have only one or two metro stops but you would be wrong (<em>cough</em> Barcelona <em>cough</em>), so we’re going to put a stop gap saying if the number of data points is less than three the loop should skip that year and move to the next one.</p>
<p>Okay, assuming there are at least three data points though we’re going to run the <code>deldir()</code> call and then save it in <code>year_deldir</code>. Then we create two new data frames. the first is <code>year_deldir_delsgs</code> which contains the <code>delsgs</code> information from <code>deldir</code>. We’re going to add two columns too, <code>city</code> and <code>opened_year</code>, so we know which city and year this data comes from. We then add this information to our existing <code>time_deldir_delsgs</code> data frame with a <code>bind_rows()</code> call. We then do the same thing to create <code>year_deldir_sum</code>, only we pull out the <code>summary</code> information from <code>year_deldir</code> instead of the <code>delsgs</code> information. We also add our <code>city</code> and <code>opened_year</code> columns and then <code>bind_rows()</code> it with <code>time_deldir_sum</code>. The loop does this for every city from the minimum year in the data up to 2015. See below the head of the two data frames we created.</p>
<pre>
time_deldir_delsgs = data.frame()

time_deldir_sum = data.frame()

for(c in c(&quot;Paris&quot;, &quot;Berlin&quot;, &quot;Barcelona&quot;, &quot;Prague&quot;)) {
  data_city = filter(data, city == c)
  for(year in min(data_city$opened_year):2015) {
    data_year = filter(data_city, opened_year &lt;= year)
    
    # Add condition to skip if number of stops less than 3
    if(dim(data_year)[1] &lt; 3) next

      year_deldir = deldir(data_year$lon, data_year$lat)

      year_deldir_delsgs = year_deldir$delsgs %>%
        mutate(city = c) %>%
        mutate(opened_year = year)
    
      time_deldir_delsgs = bind_rows(time_deldir_delsgs, year_deldir_delsgs)
    
      year_deldir_sum = year_deldir$summary %>%
        mutate(city = c) %>%
        mutate(opened_year = year)
    
      time_deldir_sum = bind_rows(time_deldir_sum, year_deldir_sum)
  }
}

head(time_deldir_delsgs)
head(time_deldir_sum)
<em> x1 y1 x2 y2 ind1 ind2 city opened_year
1 2.358279 48.85343 2.369510 48.85302 11 2 Paris 1900
2 2.374377 48.84430 2.369510 48.85302 9 2 Paris 1900
3 2.374377 48.84430 2.358279 48.85343 9 11 Paris 1900
4 2.414484 48.84640 2.369510 48.85302 16 2 Paris 1900
5 2.414484 48.84640 2.374377 48.84430 16 9 Paris 1900
6 2.386581 48.84732 2.369510 48.85302 18 2 Paris 1900
x y n.tri del.area del.wts n.tside nbpt dir.area dir.wts city opened_year
1 2.289364 48.87577 4 1.9e-05 0.012510 4 2 0.000066 0.009329 Paris 1900
2 2.369510 48.85302 5 7.0e-05 0.047518 4 2 0.000520 0.073787 Paris 1900
3 2.290121 48.86685 5 3.7e-05 0.024907 5 0 0.000074 0.010541 Paris 1900
4 2.313310 48.86750 4 3.7e-05 0.024692 3 4 0.000388 0.054946 Paris 1900
5 2.294900 48.87393 5 1.6e-05 0.010551 3 2 0.000061 0.008594 Paris 1900
6 2.347301 48.85869 4 1.1e-05 0.007359 3 4 0.000392 0.055588 Paris 1900</em>
</pre>
<p>As you may recall though we’re not necessarily interested in all the summary information, we just want it to compute our centroid. So, we make a new data frame <code>time_deldir_cent</code>. The code is the same as our earlier code for computing centroids, the only difference is that we’ll also group by <code>opened_year</code>, not just <code>city</code>, since we want unique centroids for each year for each city. See part of the data frame of the centroids below.</p>
<pre>
time_deldir_cent = time_deldir_sum %>%
  group_by(city, opened_year) %>%
  summarise(cent_x = sum(x * del.wts),
            cent_y = sum(y * del.wts)) %>%
  ungroup()
head(time_deldir_cent)
<em># A tibble: 6 × 4
city opened_year cent_x cent_y
&lt;chr> &lt;int> &lt;dbl> &lt;dbl>
1 Barcelona 1924 2.116839 41.38132
2 Barcelona 1925 2.120019 41.37782
3 Barcelona 1926 2.121921 41.37834
4 Barcelona 1927 2.121921 41.37834
5 Barcelona 1928 2.122325 41.37384
6 Barcelona 1929 2.113628 41.37543</em>
</pre>
<p>There’s still one more thing I want to do before we make our figures. Right now the figures will have different start dates depending on when the first metro stop was built in a given city. Instead, I want all figures to start at the same year so we see them change over time with the same start date for each city. To do this we’ll make a new data frame called <code>years</code> that simply lists the years 1900 to 2015 four times, once for each city. We then do a <code>left_join()</code> with our data. As a result any time the <code>opened_year</code> in question is not found in the data frame for a given city an empty row will be added, empty except for the <code>opened_year</code> and <code>city</code> values. You’ll also notice that I <code>filter()</code>ed to only include decade years (1900, 1910, 1920, etc.), and the year 2015 so it includes the last year of our data. This is because if we include every year our gif will be very large and non-portable. Also it’s more dramatic to see changes every 10 years.</p>
<pre>
years = data.frame(opened_year = rep(seq(1900, 2015), 4),
                   city = c(rep(&quot;Paris&quot;, 116), rep(&quot;Berlin&quot;, 116),
                            rep(&quot;Barcelona&quot;, 116), rep(&quot;Prague&quot;, 116)))

data_time = left_join(years, data) %>%
  mutate(opened_by_year = ifelse(opened_year %% 10 == 0, opened_year,
                                 opened_year + (10 - (opened_year %% 10)))) %>%
  filter(opened_by_year %
  filter(opened_year %% 10 == 0 | opened_year == 2015)

time_deldir_cent_sub = time_deldir_cent %>%
  filter(opened_year %% 10 == 0 | opened_year == 2015)
</pre>
<p>I kept saying we were going to make maps showing the change over time, but how are we going to do that? Well instead of building a single static plot for each city we’re going to build an animation where as the year changes so will the map. To do this we’ll use the package <code><a target="_blank" rel="nofollow" href="https://github.com/dgrtwo/gganimate">gganimate</a></code> which works on top of <code>ggplot2</code> (which is useful since we’re already using <code>ggmap</code> which works on top of <code>ggplot2</code>). We build our plot just as we would any other <code>ggplot2</code> figure, but for data we want to add the <code>frame</code> setting. The <code>frame</code> is the thing in the plot that changes, in our case <code>opened_year</code>. Also, while we only want to plot the triangulations and centroids specific to a given year, we want the points for the metro stops to be additive. For example, when <code>frame</code> is 2000 we still want the points from 1990 to be plotted. To do this we add <code>cumulative = TRUE</code> to the call for those points. Finally, since we updated our data to include empty rows so that all plots start on 1900, all plots will have a frame starting at 1900, even if there are no data points to plot. I’ve again made a function to make our plots. See below for the code for the Paris map as well as all four animations. Also, notice that in 1920 (actually 1912) Barcelona gets their first metro stop…but doesn’t get anymore until 1930 (actually 1924). Take a look to see if you can find any other interesting things about how the systems changed over time.</p>
<pre>
devtools::install_github(&quot;dgrtwo/gganimate&quot;)
library(gganimate)

time_plot = function(city_name, city_map){
  ggmap(city_map, extent = &quot;device&quot;) +
    geom_segment(data = subset(time_deldir_delsgs_sub, city == city_name),
                 aes(x = x1, y = y1, xend = x2, yend = y2, frame = opened_year),
                 size = 1, color= &quot;#92c5de&quot;) +
    geom_point(data = subset(data_time, city == city_name),
               aes(x = lon, y = lat, frame = opened_by_year, cumulative = TRUE),
               color = &quot;#0571b0&quot;, size = 3) +
    geom_point(data = subset(time_deldir_cent_sub, city == city_name),
               aes(x = cent_x, y = cent_y, frame = opened_year),
               size = 6, color= &quot;#ca0020&quot;) +
      theme(plot.title = element_text(hjust = 0.5))
}

paris_time.plot = time_plot(&quot;Paris&quot;, paris_map)
gganimate(paris_time.plot)
</pre>
<p>Plot for Paris:<br>
<a title="" data-rel="lightbox-0" target="_blank" rel="nofollow" href="https://i2.wp.com/datascienceplus.com/wp-content/uploads/2017/01/paris_time.gif?ssl=1"><img alt="" class="wp-image-5246" src="https://i2.wp.com/datascienceplus.com/wp-content/uploads/2017/01/paris_time.gif?resize=456%2C456&ssl=1" data-recalc-dims="1"></a></p>
<h2>Conclusion</h2>
<p>In these three post we looked at how the metro systems of four European cities changed over time. To do this we used a lot of different packages. We used the packages <code>dplyr</code>, <code>tidyr</code>, <code>purrr</code>, and <code>ggplot2</code>, which are all now a part of the package <code>tidyverse</code>. We used used two other plotting packages that build upon <code>ggplot2</code>, <code>ggmap</code> and <code>gganimate</code>. Finally we used the <code>deldir</code> package to make Delaunay triangulations and compute centroids of city metro systems over time. All of these skills can be applied to any other type of spacial data with unique shapes, and can be used to make your very own gifs. Try your city as a practice exercise!</p>
<ul></ul>
<p><strong>
<p>Related Post</p>
<p>
<ol>
<li><a title="Permanent Link toMetro Systems Over Time: Part 2" target="_blank" rel="nofollow" href="https://datascienceplus.com/metro-systems-over-time-part-2/">Metro Systems Over Time: Part 2</a></li>
<li><a title="Permanent Link toMetro Systems Over Time: Part 1" target="_blank" rel="nofollow" href="https://datascienceplus.com/metro-systems-over-time-part-1/">Metro Systems Over Time: Part 1</a></li>
<li><a title="Permanent Link toOutlier App: An Interactive Visualization of Outlier Algorithms" target="_blank" rel="nofollow" href="https://datascienceplus.com/outlier-app-an-interactive-visualization-of-outlier-algorithms/">Outlier App: An Interactive Visualization of Outlier Algorithms</a></li>
<li><a title="Permanent Link toCreating an animation using R" target="_blank" rel="nofollow" href="https://datascienceplus.com/creating-an-animation-using-r/">Creating an animation using R</a></li>
<li><a title="Permanent Link toThe importance of Data Visualization" target="_blank" rel="nofollow" href="https://datascienceplus.com/the-importance-of-data-visualization/">The importance of Data Visualization</a></li>
</ol></strong>
<div>
<a target="_blank" rel="nofollow" href="http://feeds.feedburner.com/~ff/datascienceplus?a=q__YVsfsz3I:ulaiMsUCL9I:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/datascienceplus?i=q__YVsfsz3I:ulaiMsUCL9I:D7DqB2pKExk" border="0"></a> <a target="_blank" rel="nofollow" href="http://feeds.feedburner.com/~ff/datascienceplus?a=q__YVsfsz3I:ulaiMsUCL9I:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/datascienceplus?d=qj6IDK7rITs" border="0"></a> <a target="_blank" rel="nofollow" href="http://feeds.feedburner.com/~ff/datascienceplus?a=q__YVsfsz3I:ulaiMsUCL9I:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/datascienceplus?d=yIl2AUoC8zA" border="0"></a>
</div>
<p>
<div>
<div>To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://datascienceplus.com/metro-systems-over-time-part-3/"> DataScience+</a></strong>.</div>
<hr>
<a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers.com</a> offers <strong><a rel="nofollow" href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" rel="nofollow" href="https://www.r-project.org/">R</a> news and <a title="R tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/tutorial">tutorials</a> on topics such as: <a title="Data science" rel="nofollow" href="https://www.r-bloggers.com/search/data%20science">Data science</a>, <a title="Big Data" rel="nofollow" href="https://www.r-bloggers.com/search/Big%20Data">Big Data, <a title="R jobs" rel="nofollow" href="https://www.r-users.com/">R jobs</a>, visualization (<a title="ggplot and ggplot2 tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/ggplot2">ggplot2</a>, <a title="Boxplots using lattice and ggplot2 tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/boxplot">Boxplots</a>, <a title="Maps and gis" rel="nofollow" href="https://www.r-bloggers.com/search/map">maps</a>, <a title="Animation in R" rel="nofollow" href="https://www.r-bloggers.com/search/animation">animation</a>), programming (<a title="RStudio IDE for R" rel="nofollow" href="https://www.r-bloggers.com/search/RStudio">RStudio</a>, <a title="Sweave and literate programming" rel="nofollow" href="https://www.r-bloggers.com/search/sweave">Sweave</a>, <a title="LaTeX in R" rel="nofollow" href="https://www.r-bloggers.com/search/LaTeX">LaTeX</a>, <a title="SQL and databases" rel="nofollow" href="https://www.r-bloggers.com/search/SQL">SQL</a>, <a title="Eclipse IDE for R" rel="nofollow" href="https://www.r-bloggers.com/search/eclipse">Eclipse</a>, <a title="git and github, Version Control System" rel="nofollow" href="https://www.r-bloggers.com/search/git">git</a>, <a title="Large data in R using Hadoop" rel="nofollow" href="https://www.r-bloggers.com/search/hadoop">hadoop</a>, <a title="Web Scraping of google, facebook, yahoo, twitter and more using R" rel="nofollow" href="https://www.r-bloggers.com/search/Web+Scraping">Web Scraping</a>) statistics (<a title="Regressions and ANOVA analysis tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/regression">regression</a>, <a title="principal component analysis tutorial" rel="nofollow" href="https://www.r-bloggers.com/search/PCA">PCA</a>, <a title="Time series" rel="nofollow" href="https://www.r-bloggers.com/search/time+series">time series</a>, <a title="finance trading" rel="nofollow" href="https://www.r-bloggers.com/search/trading">trading</a>) and more...
<img height="1" alt="" width="1" src="http://feeds.feedburner.com/~r/RBloggers/~4/HL_aszZ7se4"></a></div>