Django and LeafletJS - Interactive Maps, Map Events, and Finding Closest Points with GeoPy

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
in this video we're going to learn how to integrate leaflet JS with Django and we're going to learn how to display maps and add markers to Maps Based on data from the server that we expose in our Json script template we're also going to learn how to dynamically add markers to maps on user click events and we're going to learn how to send coordinates to the server to find the closest point to where the user has clicked in other words the closest station to where the user has clicked and then draw a line between where the user clicked and that station so a very simple mapping application using leaflet JS and Django let's get started now there's some starter code here on GitHub on this repository so I'll link this below the video and you can clone that repository and I have that open in vs code here it's a Django application and what we're going to do is go to the base.html template and we're going to clear out what's in here and we're going to add the import for leaflet.js at the top so let's go to the leaflet JS documentation here and as you can see it's an open source JavaScript library for mobile friendly Maps that's the leading open source mapping library in JavaScript and if we go to the download section of this page we can scroll down and we get our CDN linked to the CSS and JavaScript for leaflet so let's copy these into our base.html template within the head tag at the top we can paste the style sheet and we're also going to grab the Javascript file and paste that in at the top as well now we want to render our map so what we've got here is a base template and there's an index.html and this is a Django template that extends That Base template and what I'm going to do is in here I'm going to remove the text and paste in a div and it has an ID of map and it has height and width and that's where the map is going to be filled in so we have this empty div what we're now going to do is go to leaflets Quick Start documentation again I'll link this below the video This is how to get started with leaflet in a basic way and if you scroll down here we can get not only the Imports but we get our getting started section you can see they've defined a div with the ID of map and they're using CSS to give that map height of 100 pixels now to set the map up that's this section here we need to write some JavaScript code so what we're going to do is we're going to go to index.html and I'm going to Define our script tag very simple script tag here and normally you would extract this maybe to a Javascript file but for this video we're just going to write the code inline and if you go back to the documentation you can see that it's creating a variable called mapier and we have access to this object called L it's just the letter L it's very similar in some ways to how jQuery is exposed through the dollar sign leaflet's object is represented by this l so I'm going to copy this line here and we're going to paste that here in the script tag and you can see that the leaflet object L has a function called map and we pass to that our parameter that's the ID of the element where we want the map to be placed and in our case it's just the ID of map and then we call the set view function on that map and we can set it to a center location and give it a zoom level so that's the map object if we go back to the documentation what we need to do next is basically copy this code here now leaflet Maps they need a tile layer and in the case of this code it's an open street map tile there so what we're going to do is just paste that below the map call and then we can go to our page so first of all let's run the server and once Django's development server is running we can go to localhost 8000 and you can see we have this map that's centered on the city of London and it has a zoom level of 13 and that's the second parameter to the set view function so this is working fine we have a leaflet map and a Django application now what we're going to do is a continuation of two previous videos that I did and this is a self-contained video you just need to get the starter code from GitHub and you don't need to follow the previous videos what we're going to do is we're going to plot marker data for electric vehicle stations in the US state of Connecticut so we have in our Django starter code a directory here called data and that contains a CSV file and we also have a management command here called load stations that is going to load in that data and it creates a bunch of rows based on this model called EV charging location so we're going to stop the server and we're going to run the pythonmanage.pi migrate and that's going to create the database from the migration files once we've done that we can then call our custom management command and that's loadstations.pi we don't need the dot Pi at the end actually so we'll just call load stations and that's going to bring all that data into our database so now we have a bunch of these electric vehicle charging locations in the database what we're now going to do is plot them on our leaflet map now this is a map of London what we need is a map of Connecticut and we also need a different zoom level for this to be most effective so what we're going to do is go back to the index.html and in this JavaScript this call to this set view function I'm going to replace that with these coordinates here and you can Google the center location of the US state of Connecticut if you'd like to get that for me it was these two here and we also set a zoom level of 8. so if we save that file and we run the Django development server again if we go back to the page and refresh we should now see that this city of London map is now centered on the U.S state of Connecticut so let's now get around to plotting the markers that we have in a database in this map let's go to the views.pi fill and at the top from the core dot models we're going to bring in that electric vehicle charging location model and if we look at that model you can see that we have three different fields we have a station name latitude and a longitude now what we're going to do is go back to views.pi and we're going to fetch all of these objects from the database so let's create a variable here called stations and it's going to be equal to EV charging location.objects.values and the dot values function basically gives us back a query set of dictionaries rather than model objects and the two keys that we need in that dictionary are the latitude and the longitude from the model so this gives us a query set of dictionaries let's say that we only want the first 100 dictionaries and let's say that we want to convert the query set to a list of dictionaries instead and the reason that we convert the query set to a list is because a list is well understood by Jason and we're going to serialize this data to Json using the Json script template tag and then pass it to the leaflet map so just to be clear what this station's variable actually represents let's print it out to the terminal or rather let's print the first two of these out and if we now go back to our page and refresh we should see in the terminal that we have a list of dictionaries that contain two keys the latitude and the longitude for each model so let's remove this print statement and we're going to redefine the context here rather than an empty dictionary we're going to add a key called stations that maps to this list of dictionaries so now we have a list of dictionaries in the context let's go to index.html and just below the div tag at the top we're going to use the Json script template filter to take the stations that we've just added to the context and convert that data to Json data within our HTML and we can give that an ID of stations Json now if you're not familiar with this Json script template tag I did a video on this and there was also a very good blog post on this topic by Adam Johnson so I'll link those below the video but what this is going to do if we go back to the page and refresh if we inspect the HTML that's generated on this page we should now see that there is a script so let me expand this and within our div we can expand and you can see that we have this script with an ID of stations Json and it's all type application slash Json and this script contains the Json data for all of our EV charging stations the latitude and the longitude so what we can now do is within the JavaScript we can get a reference to this ID and we can parse the Json and then access this data within our JavaScript code so let's close the console and we'll go back to our index.html and at the bottom here what I'm going to do is we're going to create another variable and let's call this variable stations and it's going to be equal to the document.getelement by ID function and the ID that we want to get is the station's Json and that's what this is here it provides an ID to the script tag and then we can call the dot text content to get the actual text content and all all we need to do then is wrap that in Brackets and call the Json dot parse function that will take that text content and it will pass it into JavaScript objects that we can then use in this JavaScript code once we have the stations what we can then do is I'm going to leave a comment here for each station we're going to add a marker to the leaflet map let me tab this over so that it looks a little bit better and what we're going to do is we're going to call the stations dot for each function and the for each function will iterate over that collection of stations and for each station it encounters it's going to perform an arrow function and then we can do anything we want within that function for the station now for each station the leaflet object also has a marker function and that will add a marker to the leaflet map and the marker function takes one required argument and that's JavaScript array of the latitude and longitude so I'm going to paste that in here and this is coming from our data the station.latitude and the station dot longitude once we've created that marker object we can call the add to function and we can pass the map that we created up here on line 11 and that will then add the marker to that map so let's now save this JavaScript and we'll go back to the page and refresh you can now see that the first 100 markers from our database are now present on this leaflet map so that's the first step in this tutorial to get the markers from the database onto our leaflet map using Django and we're not using folium in this case we're directly using the underlying JavaScript library and that gives us a bit more flexibility over how we can operate with the map for example we can click the map and we can reference The Click event to perform actions when the map is clicked so let's see how to do that now if we go back to the index.html what we're going to do now is add a click event to the map so that when it's clicked it adds a marker to that map so let's reference the leaflet map variable and that has a function called dot on and then we can pass a named event to that function and in our case that's going to be the click event the second parameter to the dot on function is a callback function and that can take the event as a parameter and then within the body of the function what we're going to do is add a marker at the location but first of all let's console.log the event and it has a property called lat long and what that should hopefully give us is the latitude and longitude of the position that has been clicked on the map so let's go back to our web page I'm going to refresh this page and bring up the browser console so the browser console is at the bottom of this page what we're going to do is zoom in and I'm going to click a particular location here and you can see that when we reference the events lat long property what it's doing is printing out a JavaScript object containing the latitude and the longitude so that will happen for any area in the map that we click if we zoom out and go to the middle of the ocean we get a very different latitude than longitude but it is different each time that you click so what we're going to do now is we're going to add a marker to the leaflet map at the position that the user has clicked and after that we're going to then draw a line from that position to the nearest electric vehicle station so let's now go back to vs code and on the click event rather than console logging what we're going to do is add a marker at this position again it's very similar to what we did before we call the leaflet dot marker object and to that we pass a JavaScript array and it's going to be the event.lat long dot lat and then the event dot lat long dot long it's a bit of a mouthful but that will basically take the latitude and longitude from that JavaScript object and it will position the marker at that location and of course we need to call the add to function and pass the map to that if we now save this we can go back to our page and refresh this page if we now click a spot on this map you can see we get an error and that's the E is not defined and that's my mistake here the parameter to this callback function should be event not e so if we paste in event instead of e hopefully this will fix itself let's refresh the page and let's put a marker here you can see that every time we click this map a marker is being placed on the map so that's working quite well we have a dynamic come up here we can click locations on the map and add markers to the map what we're now going to do is something a bit more advanced when we click this map what we want to do is take the list of electric vehicle stations on the back end and we want to calculate the closest station to where we have clicked on the map now this is going to involve sending an Ajax request to our Django server and then performing some calculations to find the nearest station so let's get started implementing that now if we go back to index.html on the click event rather than just adding the marker we're now also going to send a fetch request to our Django server and we're going to send that to a particular URL and that URL is going to be slash get nearest station and we're going to attach two query parameters to that so that the back end can pick up these values the first one is going to be the latitude and what I'm going to do here is actually change the string to a JavaScript template string and you can do that by replacing the standard quote with a forward tick like this and don't forget to close that off as well and what I this means is that you can refer to variables directly within the string similar to format strings in Python so let's use the dollar sign and then the curly brackets here we're going to reference a variable called lat and we're going to create that in a second but let's now attach a different query parameter and we'll attach the longitude so that the server can pick up that as well and here we're going to pass another variable called longitude so let's Now set up these variables latitude and longitude we'll go above the marker call here and we're going to create the latitude and that's going to be equal to the event.lat long dot lat so let's cut that out of there and paste it here and we can then reference the variable name within that JavaScript array and we're going to do the same for the longitude here we'll call the variable longitude and we'll paste that in here so now we should be sending on the click event a fetch request to the URL and attaching the latitude and longitude here as query parameters let's go to our front end and refresh this page if we now click this link you can see that it's trying to send a request to the get nearest station URL in Django and it's attaching the latitude and the longitude as query parameters so that part is working what we now need to do is Define the Django view that's going to accept this request and calculate the nearest station to that so let's go back to Django and we're going to go to our urls.pi first of all and underneath this we're going to create another path and this is going to be the path for our Ajax request and it's going to be the get nearest station URL and we're going to create a view now called nearest station within the views.pi file so just underneath this index let's create that new view it will take the request as an argument and before we write this View at the top I'm going to import from Django's HTTP module the Json response that we're going to use in a second what we want to do to start with is just get the latitude and the longitude from the request get parameters so let's start with the latitude and that's going to be equal to request.get and then we can call Dot get on that that's a dictionary.get method and get the latitude key from the query parameter and I'm going to copy that line and paste it just below and we're going to change the key to longitude in this case and we can copy that key name and paste that here so we now should be getting the latitude and the longitude from the URL if we print these out to the terminal we can test that out and from this view at the moment we're just going to return an empty Json response dictionary so let's save the view and go back to our page and we can refresh this page now when we click the map a request is being sent to our backend if we go to the back end here let's make the terminal a little bit bigger you can see the request has come in and you can see here that we have a latitude and a longitude being extracted from the URL and printed to the terminal so this section is working here we have the latitude and the longitude now the hard part is to calculate the nearest electric vehicle station to this latitude and longitude so how do we approach this task now what I'm going to do is use a library called geopy if we go to the documentation for this Library you can see that it's a python client for popular geocoding website services and among other things if we scroll down here you can see that we have a measuring distance section and there's a distance module within this geopy library and we can use that as you can see here to calculate the distance the geodesic distance between two latitude longitude Pairs and that will give you back distances and named Tuple of distances in either kilometers or miles or other values as well so we're going to use geopy to use it we need to actually go to the terminal and install it so let's install that with Pip it's going to be pip install geopy now this is a python library for Geographic data it's not particular to Django so we don't need to add it to installed apps or anything like that but at the top of the view file what we're going to do is from geopy dot distance we're going to import that geodesic function that is calculating the distance and if we go back down to the nearest station view what we're going to do is we're going to put the latitude and the longitude from the URL into our Tuple and we're going to call that user location so this is the location that the user has clicked as a tuple a two Tuple of latitude and longitude and below that we're going to create an empty dictionary here called station distances and that's going to track the distance from each station in our database to the user's location and below that we're going to create a for Loop and we're going to say for station in and we're going to use a statement here from the orm it's going to be electric vehicle charging location Dot objects.org and we're going to index into the first 100 as we did above here so for each one of those stations we're going to perform some logic to calculate the distance from the user location to that station and we're going to store that within this dictionary here now let's start by extracting the station's latitude and longitude and we'll store that in a variable called station location and this is a tuple with a latitude and longitude it's the same structure as the user location above what we now want to do in the for Loop is calculate the distance between the user's location and the station's location so let's create a variable here called distance and that's going to be equal to calling the geodesic function and we passed it about two locations that we want to calculate the distance between and it's the user location and the station location now the geodesic function gives us back a named Tuple and that has a property called dot km that will give us the distance in kilometers so that gives us a number back we can then use that number as a key in our station distances dictionary so let's add the distance as the key and the value here we're going to add is the station location so what we can do later on is we can order the keys by the distance and we can get the key that has the smallest distance in that dictionary and then that will give us back a value where the nearest station is located so that completes a for Loop what we're going to now do is get the nearest station and we're going to set that equal to the Min function over the station distances that will give us the key that is the smallest value in those keys in that dictionary in other words the key of the minimum distance and actually I'm going to rename this variable I think in beta name for that is minimum distance now once we have that minimum distance we can then use it to index into the station distances dictionary if we index in at that minimum distance we get the coordinates of the closest station to the point where the user clicked we can then store that in a variable called station coordinates and the final thing to do in this view is replace this Json response and add the two keys the coordinates which will map to these station coordinates and also the distance from that station to the user's location so we're returning two bits of data as Json we can then accept those in our JavaScript code if we go back to index.html when we send the fetch request we can then call the dot then function because fetch returns a promise and the way that this works with fetch is that we get back our response we then convert that response to Json data and that will return another promise once that has been converted we get back a result and again there's a callback function and that's what's executed on that result so what we're going to do is we're going to add a marker or rather a line between the Point that's been clicked and this nearest station that's being returned let's start by simply console logging the result to the terminal just to see what we're getting back from the server of course we need to run the Django development server again so let's run that and go back to our page if we now refresh this page when we click a particular point on the map we get back this data from the server and that data has two Fields the first one is the coordinates of the nearest station to where we have clicked and we also get back the distance in kilometers to that station from the point we have clicked so what we're going to do now is use this data to draw a line between where we clicked and that station so let's go back to our code and within the fetch we're going to extract the coordinates from this result so let's call this station coordinates and we'll set that equal to the result dot coordinates and again that just simply maps to this here it gives us back an array of two values the latitude and the longitude for the nearest station once we have that what we're going to do is we're going to reference the latitude and longitude that the user clicked and we're going to draw a line between the two points so let's go to the documentation for leaflet at the top here we have a section for the docs and here we have a bunch of options for leaflets documentation if we scroll down we have a section on Vector layers one of them is the polyline we're going to draw a polyline between the two stations so what we're going to do is reference this documentation and you can see that the top level leaflet object L has a function called polyline which is used to draw a line between different points so we're going to reference that here within the results of the fetch call let's create a variable called polylink and that's going to be equal to the l dot polyline function now before we write the parameters to that I'm actually going to extract the latitude and longitude with the user clicked and that's going to be called user coordinates and we'll say that's equal to lat and longitude and these are variables coming from line 25 and 26. now the first parameter to the polyline function is going to be the user coordinates and the station coordinates in a list so we have a list of two in our lists and we're going to draw a line between the two points once we have that we can then as we did with the marker called the add to function and pass the map to that now that we've done that we can save our JavaScript and we can go back to the page here and if we refresh this page now if we scroll in a little bit we see that when we click a particular point it's now adding the marker and drawing a line between that marker and the nearest electric vehicle charging station and it's correctly calculating that and if we go up here a little bit and click round about here we get the nearest station drawn to that and this will work no matter how far away you are if we click up here we get the link to the nearest station in Connecticut so this is now working we can click anywhere on the leaflet map and we're taken to the nearest station so this is not going to replace Google Maps anytime soon but it's not a bad representation of how you can use leaflet and how you can use back-end server Technologies in order to create these maps and create cool effects such as calculating the distance and adding dynamic atomically to the map so let's refresh this page and we're going to do one last thing in this video now you might have noticed that we're also in the view in the Django view returning the distance to that station from the user's location what we can do is add a pop-up to the leaflet map and we can display how far away the user is from the nearest station so let's see how to do that we can go back to index.html and the code we're going to add is in the click event and that's going to be within the fetch call here so we're going to add some new lines here and let's go back to leaflets documentation and you can see there's a section here for UI layers and we're going to click the pop-up and what we can do is basically copy this code here and we're going to amend this in our function so let's paste that in and fix the formatting and again the pop-up function is defined on the top level leaflet object and we're calling set long and we're going to set this equal to the user's latitude and longitude location basically where they clicked on the map and then what we're going to do is we're going to change the content that's being rendered in this pop-up and I'm again we're going to use a JavaScript template string here and we're going to say neatest station as result dot distance kilometers away so remember result contains not just the coordinates of the nearest station but it also contains from our back end the distance to that station so we can reference that in our JavaScript code and we say that the nearest station is X kilometers away so let's see if that works if we save that and go back to the page and refresh what happens if we scroll in here and we click we get this pop-up saying that the nearest station is 12 kilometers away now you might want to round this number it's not particularly user friendly that's up to you you can also close the pop-up and we still get the line drawn between the two points and that's going to work no matter how many times we click this map we always get the line to the nearest station and that's calculated by geopy and we're getting the pop-up and the line that's being drawn by leaflet.js so we're integrating a lot of different things in this video and there's a lot of different things that you can can do with this if you're interested in any follow-up videos you can even draw shortest paths between two points using Road networks that's possible with some python libraries so you can actually calculate the road Network's shortest path from your current location to the nearest electric vehicle charging station and you can imagine this being useful in a real world application and if you're interested in finding out about a library that can help you with that this one here called osmnx is one that could be useful for you and if you're interested I can make a follow-up video on this topic this Library basically integrates openstreetmap with network X in order to find shortest paths between locations using Road networks and also Bank networks and other networks that can be used with openstreetmap so that's all for this video thank you for watching I hope you've learned something if you have please like And subscribe to the channel and we'll see you in the next video
Info
Channel: BugBytes
Views: 17,045
Rating: undefined out of 5
Keywords:
Id: E2bhoCOMlsA
Channel Id: undefined
Length: 25min 49sec (1549 seconds)
Published: Mon Feb 06 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.