{"id":4439,"date":"2019-11-06T16:11:16","date_gmt":"2019-11-06T14:11:16","guid":{"rendered":"https:\/\/engel-wolf.com\/?p=4439"},"modified":"2019-11-06T17:31:15","modified_gmt":"2019-11-06T15:31:15","slug":"3d-gps-data-animation-virtually-climb-the-alps","status":"publish","type":"post","link":"https:\/\/engel-wolf.com\/?p=4439","title":{"rendered":"3D GPS data animation &#8211; virtually climb the Alps"},"content":{"rendered":"\n<h3 class=\"wp-block-heading\">Using the amazing package rayshader I wanted to render a video of my tour to Alpe d&#8217;Huez. Now I created an R package that can use any GPX file and return a 3D video animation from it.<\/h3>\n\n\n\n<p>In July 2019 my friend Tjark and I went to France to cycle the 21 hairpin bends to Alpe d&#8217;Huez. The climb has a distance to the summit (at 1,860\u00a0m (6,102\u00a0ft)) of 13.8\u00a0km (8.6\u00a0mi), with an average gradient of 8.1% and a maximum gradient of 13%. Two years before we climbed up the amazing Mont Ventoux in Provence, and now we wanted to do Alpe d&#8217;Huez. Due to a lack of Hotels, we stayed up at the village itself. We started our tour facing down the Col de Sarenne, via Mizo\u00ebn and through the valley up the 21 hairpins. It was hot, it was steep, it was exhausting.<\/p>\n\n\n\n<p>I was not at my best fitness. But I am a data scientist and I wanted to know how &#8220;slow&#8221; was I? There are several ways to find out. I could look at my average speed, a line chart or do a <strong>video<\/strong>. Even <a href=\"https:\/\/www.strava.com\/athletes\/33683886\">Strava<\/a>, the app I used for tracking, has a built-in app to make a video called <a href=\"https:\/\/labs.strava.com\/flyby\/\">FlyBy<\/a>. This tool is just two- dimensional. But on <a href=\"https:\/\/twitter.com\/tylermorganwall\">twitter <\/a>and github I found the amazing package <a href=\"http:\/\/rayshader.com\/\">rayshader<\/a>. It allows creating a 3D landscape out of any elevation data. Moreover, you can overlay your landscape with different maps or light conditions.  So I thought, why don&#8217;t I put my GPS data on top of it? Said and done:  <\/p>\n\n\n\n<figure style=\"text-align:center\"><iframe loading=\"lazy\" width=\"350\" height=\"400\" src=\"https:\/\/www.youtube.com\/embed\/iEqoR-HpKeU\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen=\"\"><\/iframe><\/figure>\n\n\n\n<p>In the next chapters, I will explain how you can create your own video from any .gpx file with my package <a href=\"https:\/\/github.com\/zappingseb\/rayshaderanimate\">rayshaderanimate<\/a>.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Downloading Elevation data<\/h4>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/engel-wolf.com\/wp-content\/uploads\/20191029_rayshader_1-1024x843.png\" alt=\"\" class=\"wp-image-4449\" width=\"350\" height=\"288\" srcset=\"https:\/\/engel-wolf.com\/wp-content\/uploads\/20191029_rayshader_1-1024x843.png 1024w, https:\/\/engel-wolf.com\/wp-content\/uploads\/20191029_rayshader_1-300x247.png 300w, https:\/\/engel-wolf.com\/wp-content\/uploads\/20191029_rayshader_1-768x633.png 768w, https:\/\/engel-wolf.com\/wp-content\/uploads\/20191029_rayshader_1-364x300.png 364w, https:\/\/engel-wolf.com\/wp-content\/uploads\/20191029_rayshader_1.png 1213w\" sizes=\"(max-width: 350px) 100vw, 350px\" \/><figcaption>rayshader 3D graphic of the landscape around Alpe d&#8217;Huez<\/figcaption><\/figure><\/div>\n\n\n\n<p>My first problem was getting the elevation data around Alpe d&#8217;Huez. Thus I found the great package <a href=\"https:\/\/cran.r-project.org\/web\/packages\/raster\/index.html\">raster<\/a>. You can download elevation data for a boundary box all over the world by calling:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: r; title: ; notranslate\" title=\"\">\nraw_data &lt;- raster::getData(&quot;SRTM&quot;, lon = bbox&#91;1, 1], lat = bbox&#91;2, 2]))\ndata_cropped &lt;- raster::crop(raw_data, raster::extent(bbox))\n<\/pre><\/div>\n\n\n<p>I wrapped this function inside my package <a href=\"https:\/\/github.com\/zappingseb\/rayshaderanimate\">rayshaderanimate<\/a>. It would allow you to download the data. It then filters the data for the boundary box (not done by raster). Afterward, you can transform it into a rayshader readable format:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: r; title: ; notranslate\" title=\"\">\ndevtools::install_github(&quot;zappingseb\/rayshaderanimation&quot;)\nlibrary(rayshader)\nlibrary(rayshaderanimation)\n\nbbox &lt;- data.frame(min = c(6.022108, 45.012030),\n  max = c(6.179801, 45.11066))\nel_mat &lt;- get_elevdata_from_bbox()\nelmat_rayshade &lt;- el_mat %&gt;% unlabel_elevdata()\n\nelmat_rayshade %&gt;%\n    sphere_shade(texture = &quot;desert&quot;) %&gt;%\n    plot_3d(elmat_rayshade, zscale = 22,\n     fov = 0, theta = 135, zoom = 0.75,\n     phi = 45, windowsize = c(1000, 800))\n<\/pre><\/div>\n\n\n<p>Please note that the SRTM data has a resolution of about 250m. If you would like a higher resolution you would need to register at the EU-DEM portal at:  <a href=\"https:\/\/land.copernicus.eu\/imagery-in-situ\/eu-dem\/eu-dem-v1.1?tab=downloada\">https:\/\/land.copernicus.eu\/imagery-in-situ\/eu-dem\/eu-dem-v1.1?tab=downloada<\/a> . <\/p>\n\n\n\n<p>There you can download large GEOTiff data. I also wrapped loading this data inside my package:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: r; gutter: false; title: ; notranslate\" title=\"\">\nel_mat_eudem &lt;- get_elevdata_from_bbox(bbox = bbox,\n  type =&quot;EUDEM&quot;,\n  file = &quot;eu_dem_v11_E40N20\/eu_dem_v11_E40N20.TIF&quot;)\n<\/pre><\/div>\n\n\n<p>The difference between EU-DEM and SRTM data can be visualized using this code:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: r; title: ; notranslate\" title=\"\">\nplot_2d_elevdata(el_mat %&gt;% unlabel_elevdata)\nplot_2d_elevdata(el_mat_eudem %&gt;% unlabel_elevdata)\n<\/pre><\/div>\n\n\n<div class=\"row\">\n<div class=\"col-md-6\">\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"773\" height=\"555\" src=\"https:\/\/engel-wolf.com\/wp-content\/uploads\/el_mat_srtm.png\" alt=\"\" class=\"wp-image-4481\" srcset=\"https:\/\/engel-wolf.com\/wp-content\/uploads\/el_mat_srtm.png 773w, https:\/\/engel-wolf.com\/wp-content\/uploads\/el_mat_srtm-300x215.png 300w, https:\/\/engel-wolf.com\/wp-content\/uploads\/el_mat_srtm-768x551.png 768w, https:\/\/engel-wolf.com\/wp-content\/uploads\/el_mat_srtm-418x300.png 418w\" sizes=\"(max-width: 773px) 100vw, 773px\" \/><figcaption>SRTM  elevation profile around Alpe d&#8217;Huez <\/figcaption><\/figure>\n<\/div>\n<div class=\"col-md-6\">\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"773\" height=\"555\" src=\"https:\/\/engel-wolf.com\/wp-content\/uploads\/el_mat_eu_dem.png\" alt=\"\" class=\"wp-image-4482\" srcset=\"https:\/\/engel-wolf.com\/wp-content\/uploads\/el_mat_eu_dem.png 773w, https:\/\/engel-wolf.com\/wp-content\/uploads\/el_mat_eu_dem-300x215.png 300w, https:\/\/engel-wolf.com\/wp-content\/uploads\/el_mat_eu_dem-768x551.png 768w, https:\/\/engel-wolf.com\/wp-content\/uploads\/el_mat_eu_dem-418x300.png 418w\" sizes=\"(max-width: 773px) 100vw, 773px\" \/><figcaption>EU-DEM elevation profile around Alpe d&#8217;Huez<\/figcaption><\/figure>\n<\/div><\/div>\n\n\n\n<h4 class=\"wp-block-heading\">Reading in GPX files<\/h4>\n\n\n\n<p>The next task for me was to read in my gps data. The <a href=\"https:\/\/cran.r-project.org\/web\/packages\/plotKML\/index.html\">plotKML<\/a> package has a function for that. I wrapped it inside my package. It outputs my GPX file as a table with longitudinal, latitudinal coordinates and a time vector. The table gets stored in the <code>gpx_table<\/code> variable and the boundary box gets stored inside the <code>bbox<\/code> variable.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: r; title: ; notranslate\" title=\"\">\ngpx_file_loc &lt;- system.file(&quot;Alpe_d_Huez.gpx&quot;, package=&quot;rayshaderanimate&quot;)\n\ngpx_table &lt;- get_table_from_gpx(gpx_file_loc) %&gt;%\n  get_enriched_gpx_table()\n\nbbox &lt;- get_bbox_from_gpx_table(gpx_table) \n<\/pre><\/div>\n\n\n<h4 class=\"wp-block-heading\">Making a ggplot video from elevation data and GPS data<\/h4>\n\n\n\n<p>Animating the line of the GPS data means painting it on top of the landscape. I came to the conclusion that I need to paint every video scene image by image. Meaning if the line should move for two seconds, I would need 48 images to get a frame-rate of 24 images per second.<\/p>\n\n\n\n<p>I did not find any better way than creating a 2D graphic of the elevation data and rendering it as a 3D ggplot. Meaning each step of the video has to be rendered as a ggplot. Afterward, using rayshader I make a 3D image out of this. I take a snapshot and continue the process with a longer line of my GPS data.<\/p>\n\n\n\n<p><strong>The trouble with GPS data<\/strong> is that it does not get captured in equally distributed time frames. Sometimes my phone would capture my position every second, sometimes every 30 seconds. So first I needed to create a function that equally distributes the time from my GPX table. The function is inside my package:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: r; gutter: false; title: ; notranslate\" title=\"\">\nvideo_indeces &lt;- get_video_indeces(time_data = gpx_table$time_right,\n number_of_screens = number_of_screens)\n<\/pre><\/div>\n\n\n<p>where <em>number_of_screens<\/em> is the number of frames going into the video. In my case, I wanted to capture ~300 screens to make it a ten second video. <br>For each screen, I needed to paint a ggplot. Ggplot needs the elevation data in a long format. This call will transform the elevation data to a ggplot format:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: r; gutter: false; title: ; notranslate\" title=\"\">\nelmat_long &lt;- get_elevdata_long(el_mat)\n<\/pre><\/div>\n\n\n<p>From the elevation data, the gpx table and the video indeces I can create every snapshot by rendering a ggplot:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: r; title: ; notranslate\" title=\"\">\nmy_plot &lt;- ggplot() +\n  geom_tile(\n    data = elevdata_long,\n    aes_string(\n      &quot;as.numeric(as.character(variable))&quot;,\n      &quot;deg_elmat_lat&quot;,\n      fill = &quot;value&quot;),\n    alpha = 0.75) +\n\n  scale_x_continuous(\n    paste0(&quot;Longitude | &quot;,\n      gpx_table$time&#91;video_indx]),\n      expand = c(0,0)) +\n\n  scale_y_continuous(&quot;Latitude&quot;, expand = c(0,0)) +\n  scale_fill_gradientn(&quot;Elevation&quot;,\n    colours = terrain.colors(10)) +\n  coord_fixed() +\n\n  geom_path(\n    data = gpx_table&#91;1:video_indx, ],\n    aes_string(x = &quot;lon&quot;, y = &quot;lat&quot;,\n      color = &quot;-rel_speed&quot;),\n    shape = 15, size = 1, stroke = 0) +\n\n  scale_color_viridis_c(option = &quot;A&quot;) +\n  guides(colour=FALSE)\n<\/pre><\/div>\n\n\n<p>As you can see I inserted a column <code>rel_speed<\/code> inside the gpx table to make faster pieces of the track darker. The x-axis label will show the real time of each image being captured.<\/p>\n\n\n\n<p>To render this plot as a 3D graphic rayshader provides the function <em>plot_gg<\/em>. The image changes by tweeking angles and zooms. To take a picture from  the 3D graphic I used the <em>render_snapshot<\/em> function.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: r; title: ; notranslate\" title=\"\">\nplot_gg(my_plot, shadow_intensity = 0.7, width = 5, height = 5,\n  multicore = TRUE, scale = 350, raytrace = TRUE)\nrender_snapshot(filename = file.path(tempdir(),\n    paste0(&quot;video&quot;, video_indx, &quot;.png&quot;)),\n  clear = TRUE)\n<\/pre><\/div>\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"719\" height=\"675\" src=\"https:\/\/engel-wolf.com\/wp-content\/uploads\/20191029_rayshader_2.png\" alt=\"\" class=\"wp-image-4464\" srcset=\"https:\/\/engel-wolf.com\/wp-content\/uploads\/20191029_rayshader_2.png 719w, https:\/\/engel-wolf.com\/wp-content\/uploads\/20191029_rayshader_2-300x282.png 300w, https:\/\/engel-wolf.com\/wp-content\/uploads\/20191029_rayshader_2-320x300.png 320w\" sizes=\"(max-width: 719px) 100vw, 719px\" \/><figcaption>rayshader image of a 3D landscape with a GPS data overlay and time label on the x-axis<\/figcaption><\/figure>\n\n\n\n<p>The difficult part is rendering all 300 images into a video. <a href=\"https:\/\/www.ffmpeg.org\/\">ffmpeg <\/a>provides a simple API under Windows for this task. The links to all images get stored inside a txt file. From this text file ffmpeg can render the video as an mp4.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nffmpeg -y -f concat -r 24 -safe 0 -i &quot;video_path.txt&quot; -vf &quot;fps=24,format=yuv420p&quot; output.mp4\n<\/pre><\/div>\n\n\n<p>I also added functionality to render videos as gifs inside my package. Although I do not recommend rendering them as a gif. The gif files can become rather large. For more details on creating the video, please read the package vignette of <a href=\"https:\/\/zappingseb.github.io\/rayshaderanimate\/articles\/create_video.html\">rayshaderanimate package<\/a>.<\/p>\n\n\n\n<figure style=\"text-align:center\"><iframe loading=\"lazy\" width=\"560\" height=\"315\" src=\"https:\/\/www.youtube.com\/embed\/8gMSC-H_xWM\" allowfullscreen=\"\"><\/iframe><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">How about a storytelling video?<\/h3>\n\n\n\n<p>The video rendered up-to-now does not look like the video I showed at the top. I wanted to use the rayshader sphere shade with a map overlay for the video, too. Therefore I read the article at  <a href=\"https:\/\/wcmbishop.github.io\/rayshader-demo\/\">https:\/\/wcmbishop.github.io\/rayshader-demo\/<\/a> . While trying an image overlay with my data from Alpe d&#8217;Huez I noticed, that just the EUDEM data has a resolution that is high enough to render a sphere shade. <\/p>\n\n\n\n<p>But there were certain tweeks needed. I&#8217;ll not describe them in detail, but the major problem was rayshader beeing programmed for having data from the US, meaning west of Greenich Meridian. My data points are located east of Greenich Meridian. I created the function <em><a href=\"https:\/\/zappingseb.github.io\/rayshaderanimate\/reference\/get_elevdata_list.html\">get_elevdata_list<\/a><\/em><a href=\"https:\/\/zappingseb.github.io\/rayshaderanimate\/reference\/get_elevdata_list.html\"> <\/a>to overcome this problem.<\/p>\n\n\n\n<p>My function <em><a href=\"https:\/\/zappingseb.github.io\/rayshaderanimate\/reference\/get_image_overlay.html\">get_image_overlay<\/a><\/em><a href=\"https:\/\/zappingseb.github.io\/rayshaderanimate\/reference\/get_image_overlay.html\"> <\/a>can be used to derive an overlay image for a certain area. Adding the overlay image can simply be done by using the functionalities of rayshader, meaning <em><a href=\"https:\/\/www.rayshader.com\/reference\/add_overlay.html\">add_overlay<\/a><\/em><a href=\"https:\/\/www.rayshader.com\/reference\/add_overlay.html\"> <\/a>and <em><a href=\"https:\/\/www.rayshader.com\/reference\/plot_3d.html\">plot_3d<\/a><\/em>.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: r; title: ; notranslate\" title=\"\">\n# Format elevation data for west of Greenich\nelevation_data_list &lt;- get_elevdata_list(el_mat_eudem)\nelevation_matrix &lt;- elevation_data_list$elevation_matrix\n\n# Calculate shadow and water\nelevation_matrix %&gt;%\n    sphere_shade(texture = &quot;desert&quot;) %&gt;%\n    add_water(detect_water(elevation_matrix), color = &quot;desert&quot;) %&gt;%\n    add_shadow(ray_shade(elevation_matrix,\n      zscale = 3, maxsearch = 300), 0.5)\n\n# Receive Overlay Image from arcgis with a specific boundary box\nbbox &lt;- get_bbox_from_gpx_table(gpx_table, arcgis = TRUE) \noverlay_img &lt;- get_image_overlay(bbox_arcgis)\n\n# Plot 3D with overlay image\nelev_elem &lt;- elev_elem %&gt;% add_overlay(overlay_img, alphalayer = 0.5)\nelev_elem %&gt;%\n    plot_3d(elevation_matrix, zscale = 15, fov = 1, theta = 280,\n     zoom = 1.5, phi = 60, windowsize = c(1200, 800))\n<\/pre><\/div>\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"683\" src=\"https:\/\/engel-wolf.com\/wp-content\/uploads\/file534d82cf22968-1024x683.png\" alt=\"\" class=\"wp-image-4493\" srcset=\"https:\/\/engel-wolf.com\/wp-content\/uploads\/file534d82cf22968-1024x683.png 1024w, https:\/\/engel-wolf.com\/wp-content\/uploads\/file534d82cf22968-300x200.png 300w, https:\/\/engel-wolf.com\/wp-content\/uploads\/file534d82cf22968-768x512.png 768w, https:\/\/engel-wolf.com\/wp-content\/uploads\/file534d82cf22968-450x300.png 450w, https:\/\/engel-wolf.com\/wp-content\/uploads\/file534d82cf22968.png 1200w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><figcaption>3d rayshader landscape with image overlay in the French Alps<\/figcaption><\/figure>\n\n\n\n<p>Now the only things missing are the place markers and the route. Both can be added from the <em>gpx_table<\/em>. To do this I needed to map the latitude and longitude of the <em>gpx_table<\/em> to my elevation matrix resulting in <em>lat_idx <\/em>and <em>lon_idx<\/em>. Additionally, I added a label to some places, as you can see in this case it is place number 100.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: r; auto-links: false; title: ; notranslate\" title=\"\">\nfor (i in 1:100) {\n  render_label(elevation_matrix,\n    x = gpx_table&#91;1, &quot;lon_idx&quot;],\n    y = gpx_table&#91;1, &quot;lat_idx&quot;],\n    z = 100, zscale = 15,\n    text = NULL, textsize = 15,\n    linewidth = 6, freetype = FALSE,\n    color = &quot;#0f9ad1&quot;)\n}\nrender_label(elevation_matrix,\n   x = gpx_table&#91;100, &quot;lon_idx&quot;],\n   y = gpx_table&#91;i, &quot;lat_idx&quot;],\n   z = 2200, zscale = 15,\n   text = gpx_table&#91;100, &quot;label&quot;],\n   textsize = 1, linewidth = 7, freetype = FALSE,\n   color = &quot;#0f9ad1&quot;, family = &quot;mono&quot;, antialias = TRUE)\n<\/pre><\/div>\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"683\" src=\"https:\/\/engel-wolf.com\/wp-content\/uploads\/gpx_animation113-1024x683.png\" alt=\"\" class=\"wp-image-4499\" srcset=\"https:\/\/engel-wolf.com\/wp-content\/uploads\/gpx_animation113-1024x683.png 1024w, https:\/\/engel-wolf.com\/wp-content\/uploads\/gpx_animation113-300x200.png 300w, https:\/\/engel-wolf.com\/wp-content\/uploads\/gpx_animation113-768x512.png 768w, https:\/\/engel-wolf.com\/wp-content\/uploads\/gpx_animation113-450x300.png 450w, https:\/\/engel-wolf.com\/wp-content\/uploads\/gpx_animation113.png 1200w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><figcaption> 3d rayshader landscape with route and label in the French Alps <\/figcaption><\/figure>\n\n\n\n<p>I perform this process for each single point of the <em>gpx_table.<\/em> At each point I take a snapshot by <em>rayshader::render_snapshot.<\/em> All snapshots will be stored and converted to a video by <em>ffmpeg.<\/em> I added some additional features as an elevation profile or a title image. Those were added to the snapshots using <em>magick::image_append. <\/em>All these features went into my function <em><a href=\"https:\/\/zappingseb.github.io\/rayshaderanimate\/reference\/video_animation_rayshade.html\">video_animation_rayshade<\/a><\/em>. This function will create a whole video with a flyover over the map, adding the points and the elevation profile.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Why the video?<\/h4>\n\n\n\n<p>Two-dimensional animations cannot really describe the loss of speed uphill. The human perception of mountains is not represented by elevation lines. But elevation lines are the only way to visualize them in two-dimensional plots. The rayshader package allows a way better impression height and steepness. This is why I wanted to use it to visualize my climb to Alpe d&#8217;Huez.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/engel-wolf.com\/wp-content\/uploads\/IMG_1533-1024x768.jpg\" alt=\"\" class=\"wp-image-4440\" width=\"768\" height=\"576\" srcset=\"https:\/\/engel-wolf.com\/wp-content\/uploads\/IMG_1533-1024x768.jpg 1024w, https:\/\/engel-wolf.com\/wp-content\/uploads\/IMG_1533-300x225.jpg 300w, https:\/\/engel-wolf.com\/wp-content\/uploads\/IMG_1533-768x576.jpg 768w, https:\/\/engel-wolf.com\/wp-content\/uploads\/IMG_1533-400x300.jpg 400w, https:\/\/engel-wolf.com\/wp-content\/uploads\/IMG_1533.jpg 2000w\" sizes=\"(max-width: 768px) 100vw, 768px\" \/><figcaption>Hairpin bends at the mid range of the Alpe d&#8217;Huez climb<\/figcaption><\/figure><\/div>\n\n\n\n<p>Now please enjoy watching the video of my cycling climb. You can truly see at the end of the video how I was suffering from the heat at the 21 hairpins. The last passage of the video describes me being slow. The color of the GPS line is bright and it takes long until it reaches the mountain top. Just to give you an impression I added a photo of the lowest 8 hairpins.<\/p>\n\n\n\n<figure style=\"text-align:center\"><iframe loading=\"lazy\" width=\"560\" height=\"315\" src=\"https:\/\/www.youtube.com\/embed\/iEqoR-HpKeU\" allowfullscreen=\"\"><\/iframe><\/figure>\n\n\n\n<h4 class=\"wp-block-heading\">Final words<\/h4>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"652\" src=\"https:\/\/engel-wolf.com\/wp-content\/uploads\/IMG_4564-e1572362522519-1024x652.jpg\" alt=\"\" class=\"wp-image-4470\" srcset=\"https:\/\/engel-wolf.com\/wp-content\/uploads\/IMG_4564-e1572362522519-1024x652.jpg 1024w, https:\/\/engel-wolf.com\/wp-content\/uploads\/IMG_4564-e1572362522519-300x191.jpg 300w, https:\/\/engel-wolf.com\/wp-content\/uploads\/IMG_4564-e1572362522519-768x489.jpg 768w, https:\/\/engel-wolf.com\/wp-content\/uploads\/IMG_4564-e1572362522519-471x300.jpg 471w, https:\/\/engel-wolf.com\/wp-content\/uploads\/IMG_4564-e1572362522519.jpg 1500w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><figcaption>me cycling up to Alpe d&#8217;Huez<\/figcaption><\/figure>\n\n\n\n<p>The package to create such videos is open-source and available on:<\/p>\n\n\n\n<ul><li>     <a href=\"https:\/\/github.com\/zappingseb\/rayshaderanimate\">github\/zappingseb\/rayshaderanimate<\/a><\/li><\/ul>\n\n\n\n<p>I track my cycling trips on STRAVA<\/p>\n\n\n\n<ul><li>    <a href=\"https:\/\/www.strava.com\/athletes\/33683886\">Sebastian Wolf&#8217;s STRAVA profile<\/a><\/li><\/ul>\n\n\n\n<p>More videos are available at my YouTube channel:<\/p>\n\n\n\n<ul><li>     <a href=\"https:\/\/www.youtube.com\/user\/mailwolfgermany\">https:\/\/www.youtube.com\/user\/mailwolfgermany<\/a><\/li><\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Using the amazing package rayshader I wanted to render a video of my tour to Alpe d&#8217;Huez. Now I created an R package that can use any GPX file and [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":4442,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"ngg_post_thumbnail":0,"footnotes":""},"categories":[1],"tags":[430,431,433,435,434,436,384,432,423,422,381,388],"_links":{"self":[{"href":"https:\/\/engel-wolf.com\/index.php?rest_route=\/wp\/v2\/posts\/4439"}],"collection":[{"href":"https:\/\/engel-wolf.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/engel-wolf.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/engel-wolf.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/engel-wolf.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=4439"}],"version-history":[{"count":58,"href":"https:\/\/engel-wolf.com\/index.php?rest_route=\/wp\/v2\/posts\/4439\/revisions"}],"predecessor-version":[{"id":4511,"href":"https:\/\/engel-wolf.com\/index.php?rest_route=\/wp\/v2\/posts\/4439\/revisions\/4511"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/engel-wolf.com\/index.php?rest_route=\/wp\/v2\/media\/4442"}],"wp:attachment":[{"href":"https:\/\/engel-wolf.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=4439"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/engel-wolf.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=4439"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/engel-wolf.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=4439"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}