<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/create-an-interactive-web-map-with-geotagged-photos/"></div></div><div><a data-url="https://www.r-bloggers.com/create-an-interactive-web-map-with-geotagged-photos/" data-counturl="https://www.r-bloggers.com/create-an-interactive-web-map-with-geotagged-photos/" data-count="horizontal" data-text="Create an interactive web map with geotagged photos" class="twitter-share-button" data-via="rbloggers" href="https://twitter.com/share"></a></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="http://www.seascapemodels.org/bluecology_blog/index.html/rstats/2016/11/23/mapping-abundance-photos.html"> Bluecology blog</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<h2>Part 2: Create an interactive web map with geotagged photos</h2>
<p>See the other <a target="_blank" rel="nofollow" href="http://www.seascapemodels.org/rstats/2016/11/14/photos-to-spatialstat.html">parts in this series of blog posts</a>.</p>
<p>In part 1 we looked at making a simple interactive map using locations from our geotagged photos. Those photos have data associated with them (counts of oysters in quadrats) so here we will look at how you would plot that data on your map.</p>
<p>We will also add a geo-referenced pop-up that includes a picture of our study site. You might be familiar with this idea from Google Earth or Flickr.</p>
<p>To get you excited, here is the end result (try clicking on things! If you are viewing this blog on Rbloggers you will need to go <a target="_blank" rel="nofollow" href="http://www.seascapemodels.org/data/hornby_oysters_map.html">here</a> to see the map):</p>
<p><iframe src="http://www.seascapemodels.org/data/hornby_oysters_map.html"> It no map appears here your browser doesn’t support iframes. Try <a target="_blank" rel="nofollow" href="http://www.seascapemodels.org/data/hornby_oysters_map.html">this link instead</a></iframe></p>
<h3>Getting started</h3>
<p>First up here are the packages we need:</p>
<div>
<pre><code>library(leaflet)  
library(exifr)  
</code></pre>
</div>
<p>The next list of packages is optional, but I will use here to make data processing more convenient:</p>
<div>
<pre><code>library(readr) #for the updated version of read.csv  
library(dplyr) #for data wrangling  
library(stringr) #for wrangling strings  
</code></pre>
</div>
<p>Finally to get some nice colours:</p>
<div>
<pre><code>library(RColorBrewer)  
</code></pre>
</div>
<p>Now load in the data. I am using <code>read_csv</code> which comes from the <code>readr</code> package. <code>read_csv</code> is a modernised version of the base R function <code>read.csv</code>. Here are the <a target="_blank" rel="nofollow" href="http://www.seascapemodels.org/data/Exifdata.csv">exif data</a> and associated <a target="_blank" rel="nofollow" href="http://www.seascapemodels.org/data/oysters_data.csv">oyster counts</a> if you are repeating this example.</p>
<div>
<pre><code>edat &lt;- read_csv('Exifdata.csv')  
odat &lt;- read_csv('oyster_data.csv')  
n &lt;- nrow(odat) #number of sample sites   
</code></pre>
</div>
<h3>Joining the locations to the counts</h3>
<p>Now we need to join our counts of oysters to the locations. We can match by the picture numbers, which I recorded when I counted the oysters.<br>
First up we need to clean the clean the picture numbers in the exif data to remove the leading ‘DSC_’. We do this using <code>mutate</code> from <code>dplyr</code> and <code>str_extract</code> from <code>stringr</code> to extract the first four digits in each picture’s filename.</p>
<div>
<pre><code>edat&lt;- edat %>%  
mutate(pic_num =  
	as.numeric(  
		str_extract(SourceFile, '\\d\\d\\d\\d')  
		))  
</code></pre>
</div>
<p>If you haven’t seen <code>%>%</code> before it is a ‘pipe’ that puts the dataframe <code>edat</code> into the first argument of our <code>mutate</code> function. The pipe isn’t essential, but I think it improves readibility. See <a target="_blank" rel="nofollow" href="http://r4ds.had.co.nz/pipes.html">Wickham’s book</a> for more guidance on pipes.</p>
<p>Now we can join the oysters and pictures. <code>left_join</code> will automatically identify <code>pic_num</code> to join on, because it is the common column across both dataframes:</p>
<div>
<pre><code>dat &lt;- odat %>%  
  left_join(edat)  
</code></pre>
</div>
<h3>Create the content for the pop-up image</h3>
<p>To create the pop-up you need to know a little bit of html. There is plenty of helpful guides on the web and html is pretty simple to learn. The pop-up will show an image and some text. Here we define the content:</p>
<div>
<pre><code>content &lt;- paste(sep = &quot;&lt;br/>&quot;,  
  	&quot;&lt;img src='http://www.seascapemodels.org/Images/intertidal_scene.JPG'   
   style='width:230px;height:300px;'>&quot;,  
  	&quot;The intertidal zone&quot;,  
  	&quot;at Hornby Island&quot;  
)
</code></pre>
</div>
<p>In short we have specified a string with some html code. <code>&lt;br/></code> html tag creates a new line. The <code>&lt;img></code> tag specifies the insertion of an image (the link gives the image’s location, which is on my webpage. We have also set the width and height of the image. Then we follow with a bit of text explaining the image.</p>
<p>We will use <code>content</code> in our <code>leaflet</code> map below.</p>
<p>We also need the location to place our pop-up. Because the image is gps tagged, we can extract the gps locations from the exif data. Download the image from the link given above in <code>content</code> then you can get the exif data associated with it like this:</p>
<div>
<pre><code>scene &lt;- exifr('intertidal_scene.JPG')  
x1 &lt;- scene $GPSLongitude  
y1 &lt;- scene $GPSLatitude  
</code></pre>
</div>
<p>We now have coordinates for the pop-up in our <code>leaflet</code> map.</p>
<h3>Colour scale for the oyster counts</h3>
<p><code>leaflet</code> has some pretty convenient functions for creating nice colour scales. Here we use <code>colourBin</code> to bin counts of oysters into different categories that we set in the vector <code>brks</code>:</p>
<div>
<pre><code>brks &lt;- c(0,1, 5, 10, 20, 70)  
ncol &lt;- length(brks)-1  
oystercols &lt;- c('grey20',brewer.pal(ncol-1, 'Purples'))  
pal &lt;- colorBin(oystercols, dat$oysters_live, bins = brks)  
</code></pre>
</div>
<p>The end result <code>pal</code> is a function that will generate a colour palette when some data is input to it.</p>
<h3>Make a map with images</h3>
<p>We have prepped our data, so now the fun bit, making the map!<br>
This map is somewhat complicated so I will step you through it using our friend ‘pipes’ (the full code without text breaks is below if you want to cut and paste). Note how convenient pipes are here, we can essentially just layer up our map data in an intuitive fashion.</p>
<div>
<pre><code>mapout &lt;- leaflet(dat) %>%  
</code></pre>
</div>
<p>We name our map and set the dataframe it will use.</p>
<div>
<pre><code>addProviderTiles(&quot;Esri.WorldImagery&quot;) %>%  
</code></pre>
</div>
<p>Set’s the background (a satellite image)</p>
<div>
<pre><code>setView(lng = x1, lat = y1, zoom = 16) %>%
</code></pre>
</div>
<p>Chooses the region to zoom into. <code>leaflet</code> will guess the zoom level from our dataframe, but we have more control if we choose the region. The default here was a higher zoom level where the tiles don’t render when using Esri.WorldImagery.</p>
<p>Now we add some markers, setting their colours using oyster counts:</p>
<div>
<pre><code>addCircleMarkers(~ GPSLongitude, ~ GPSLatitude,  
	color = 'white',opacity =1, weight = 1,  
 	fillColor = ~pal(oysters_live),  
popup = as.character(dat$oysters_live),  
 	fillOpacity = 0.8,  
 	radius = 6) %>%
</code></pre>
</div>
<p>This looks complex, but it is just a series of simple commands. <code>~ GPSLongitude</code> tells leaflet which column of <code>dat</code> is longitude. <code>color</code>, <code>opacity</code> and <code>weight</code> refer to the colour, opacity (solid in this case) and width of the border of the markers. <code>fillColor</code> uses our palette and applies it the <code>oysters_live</code> column of <code>dat</code>. <code>popup</code> creates a popup when we click on a marker, which gives the number of oysters. <code>fillOpacity</code> and radius refer to the fill of the markers.</p>
<p>We will also add a marker for the picture I took of the shoreline. Note that this time I use our <code>content</code> data created above to specify what goes in the popup. We also change some of the marker options with <code>options</code>. See <code>?markerOptions</code> for other options:</p>
<div>
<pre><code>addMarkers(x1, y1, popup = content,  
	options = markerOptions(opacity = 0.9, draggable=T)) %>%   
</code></pre>
</div>
<p>Now let’s add a legend:</p>
<div>
<pre><code>addLegend(&quot;topright&quot;, pal = pal,  
values = brks,   
title = &quot;Number of live oysters
&lt;a href = 'https://en.wikipedia.org/wiki/Pacific_oyster' target = '_blank'> (Crassostrea gigas)&lt;/a>&quot;,  
opacity = 1)  
</code></pre>
</div>
<p>the nice thing about using <code>colorBin</code> to create our colours is we can map them directly to the legend, as we have done here with <code>pal = pal</code> (telling leaflet to use our <code>pal</code> function for the colour palette). Note in the <code>title</code> command we have also inserted some more html, this time a <code>&lt;a></code> tag which just turns the species name ‘(Crassostrea gigas)’ into a link to the Wikipedia page for the Pacific oyster.</p>
<p>And that’s it. Run that code then type <code>mapout</code> to print your map.<br>
Next up we will look at how to build a <a target="_blank" rel="nofollow" href="http://www.seascapemodels.org/rstats/2016/11/14/photos-to-spatialstat.html">spatial model using this data</a>.</p>
<h3>Extra task: Getting the map on your webpage</h3>
<p>If you want to save the map to use on your own page, you can do so with the <code>htmlwidgets</code> package, like this:</p>
<div>
<pre><code>htmlwidgets::saveWidget(mapout, file = 'hornby_oysters_map.html', selfcontained = F, libdir = &quot;leafletmap_files&quot;)
</code></pre>
</div>
<p>I recommend using “ so that the javascript files that create the map are stored in a seperate folder, rather than the javascript code being included within the html page (which makes it a very long file). Also, if you set the <code>libdir</code> command the javascript files will be saved in the folder specified by <code>libdir</code> and all the references to the javascript on the html page (which has the map) will be to that folder (in this case: ‘/leafletmap_files/’). If you are putting multiple maps on your webpage, always use the same libdir and you will only need one copy of the leaflet javascript (under libdir) in your page’s data files. Poke around in <a target="_blank" rel="nofollow" href="https://github.com/cbrown5/cbrown5.github.io">github.com/cbrown5/cbrown5.github.io</a> if you want to see how this works. I keep the leaflat maps in the <a target="_blank" rel="nofollow" href="https://github.com/cbrown5/cbrown5.github.io/tree/master/data">data</a> folder.</p>
<h3>Map code as one block for cutting and pasting</h3>
<div>
<pre><code>mapout &lt;- leaflet(dat) %>%  
#Use satellite image as base  
addProviderTiles(&quot;Esri.WorldImagery&quot;) %>%  
setView(lng = x1, lat = y1, zoom = 16) %>%  
#Add markers for oyster quadrats  
addCircleMarkers(~ GPSLongitude, ~ GPSLatitude,  
	color = 'white',opacity =1, weight = 1,  
	fillColor = ~pal(oysters_live),  
	popup = as.character(dat$oysters_live),  
	fillOpacity = 0.8,  
	radius = 6) %>% # add a popup for number of oysters  
	#Add marker showing a picture of the survey site  
	addMarkers(x1, y1, popup = content,  
		options = markerOptions(opacity = 0.9, draggable=T)) %>%  
		#Add a legend  
		addLegend(&quot;topright&quot;, pal = pal,  
		values = brks,   
		title = &quot;Number of live oysters
		&lt;a href = 'https://en.wikipedia.org/wiki/Pacific_oyster' target = '_blank'> (Crassostrea gigas)&lt;/a>&quot;,  
		opacity = 1)  
</code></pre>
</div>
<p><div><div><div><div data-width="55" data-show-faces="false" data-send="true" data-layout="box_count" data-height="62" data-href="https://www.r-bloggers.com/create-an-interactive-web-map-with-geotagged-photos/"></div></div><div><a data-url="https://www.r-bloggers.com/create-an-interactive-web-map-with-geotagged-photos/" data-counturl="https://www.r-bloggers.com/create-an-interactive-web-map-with-geotagged-photos/" data-count="vertical" data-text="Create an interactive web map with geotagged photos" class="twitter-share-button" data-via="rbloggers" href="https://twitter.com/share"></a></div><div></div></div><div></div></div>
<div>
<div>To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="http://www.seascapemodels.org/bluecology_blog/index.html/rstats/2016/11/23/mapping-abundance-photos.html"> Bluecology blog</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/?s=tutorial">tutorials</a> on topics such as: <a title="Data science" rel="nofollow" href="https://www.r-bloggers.com/?s=data%20science">Data science</a>, <a title="Big Data" rel="nofollow" href="https://www.r-bloggers.com/?s=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/?s=ggplot2">ggplot2</a>, <a title="Boxplots using lattice and ggplot2 tutorials" rel="nofollow" href="https://www.r-bloggers.com/?s=boxplot">Boxplots</a>, <a title="Maps and gis" rel="nofollow" href="https://www.r-bloggers.com/?s=map">maps</a>, <a title="Animation in R" rel="nofollow" href="https://www.r-bloggers.com/?s=animation">animation</a>), programming (<a title="RStudio IDE for R" rel="nofollow" href="https://www.r-bloggers.com/?s=RStudio">RStudio</a>, <a title="Sweave and literate programming" rel="nofollow" href="https://www.r-bloggers.com/?s=sweave">Sweave</a>, <a title="LaTeX in R" rel="nofollow" href="https://www.r-bloggers.com/?s=LaTeX">LaTeX</a>, <a title="SQL and databases" rel="nofollow" href="https://www.r-bloggers.com/?s=SQL">SQL</a>, <a title="Eclipse IDE for R" rel="nofollow" href="https://www.r-bloggers.com/?s=eclipse">Eclipse</a>, <a title="git and github, Version Control System" rel="nofollow" href="https://www.r-bloggers.com/?s=git">git</a>, <a title="Large data in R using Hadoop" rel="nofollow" href="https://www.r-bloggers.com/?s=hadoop">hadoop</a>, <a title="Web Scraping of google, facebook, yahoo, twitter and more using R" rel="nofollow" href="https://www.r-bloggers.com/?s=Web+Scraping">Web Scraping</a>) statistics (<a title="Regressions and ANOVA analysis tutorials" rel="nofollow" href="https://www.r-bloggers.com/?s=regression">regression</a>, <a title="principal component analysis tutorial" rel="nofollow" href="https://www.r-bloggers.com/?s=PCA">PCA</a>, <a title="Time series" rel="nofollow" href="https://www.r-bloggers.com/?s=time+series">time series</a>, <a title="finance trading" rel="nofollow" href="https://www.r-bloggers.com/?s=trading">trading</a>) and more...
<img height="1" alt="" width="1" src="http://feeds.feedburner.com/~r/RBloggers/~4/GDdL_VauGO8"></a></div>