Introduction to Ag Informatics

Module 6, Lecture 2
Tam Bureetes, tbureete@purdue.edu

Outline for Today

  • Spatial data
  • Introduction to geometry in Python
  • From geometry to spatial data
  • Putting spatial data to map in Django

Django Recap


            # urls.py
            urlpatterns = [
            path("", views.render_map, name="map"),
            ]
          

            # views.py
            def render_map(request):
            message = "Hello World"
            return render(request, "map.html", {"message": message})
          

            
          

Recap Geospatial Tools

ACRE Map

Leaflet

an open-source JavaScript library for mobile-friendly interactive maps

What are website made of?

HTML
CSS
JavaScript

What is Django?

Import Leaflet to template file (HTML)

           <!DOCTYPE html> 
            <html lang="en">
              <head> 
                <title>Leaflet Map</title>
                <meta name="viewport" content="width=device-width, initial-scale=1.0" />
                
                <link 
                  rel="stylesheet"
                  type="text/css"
                  href="https://unpkg.com/leaflet/dist/leaflet.css"
                  crossorigin=""
                />
                
                <script
                  src="https://unpkg.com/leaflet/dist/leaflet.js"
                  crossorigin=""
                ></script>
              </head>
              <body>
                {{message}}
              </body>
            </html>
          
Create JavaScript file to control the map

Create a file static/leaflet-map.js


            // Display copyright sign
            const copy =
              "© OpenStreetMap";
            // Define the URL for the map's background layer
            const url = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png";
            // Create a map layer 
            const layer = L.tileLayer(url, { attribution: copy });
            // Create a map that will show in tag "map" in HTML file
            const map = L.map("map", { layers: [layer] });
            // Fit the map to the bounds a.k.a. starting location
            map.fitBounds([[40.470060621973026, -86.99269856365936]]);
          
Import JavaScript file into template file

            {% load static %}  
            <!DOCTYPE html>  
            <html lang="en">
              <head>
                <title>Leaflet Map</title>
                <meta name="viewport" content="width=device-width, initial-scale=1.0" />
               
               <link 
               rel="stylesheet"
               type="text/css"
               href="https://unpkg.com/leaflet/dist/leaflet.css"
               crossorigin=""
              />
             
              <script
               src="https://unpkg.com/leaflet/dist/leaflet.js"
               crossorigin=""
              ></script>
              
              <script src="{% static 'leaflet-map.js' %}" defer></script>
              </head>
              <body>
              
                <div id="map" style="width:480px; height:480px"></div>
              </body>
            </html>
           
Adding geometry to the map

static/leaflet-map.js


            const copy =
              "© OpenStreetMap";
            const url = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png";
            const layer = L.tileLayer(url, { attribution: copy });
            const map = L.map("map", { layers: [layer] });
            map.fitBounds([[40.470060621973026, -86.99269856365936]]);
            // Add a marker to the map (a point)
            let marker = L.marker([40.470060621973026, -86.99269856365936])
              .addTo(map)
          
Adding geometry to the map

static/leaflet-map.js


            const copy =
              "© OpenStreetMap";
            const url = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png";
            const layer = L.tileLayer(url, { attribution: copy });
            const map = L.map("map", { layers: [layer] });
            map.fitBounds([[40.470060621973026, -86.99269856365936]]);

            let marker = L.marker([40.470060621973026, -86.99269856365936])
              .addTo(map)
              .bindPopup("This is a popup"); // Add a popup to the marker
          

GeoJSON: Link Django and website


          {
            "type": "FeatureCollection", <- This is the top level of GeoJSON
            "features": [ <- This is an array of features
                "type": "Feature", <- This is a feature object
                "geometry": { <- This is the geometry of the feature
                    "type": "Point",
                    "coordinates": [102.0, 0.5]
                },
                "properties": { <- This is the properties of the feature
                    "prop0": "value0"
                }
            }, {
              "type": "Feature", <- This is another feature object
              "geometry": {
                  "type": "Polygon", <- This time geometry is a polygon
                  "coordinates": [
                      [
                          [100.0, 0.0],
                          [101.0, 0.0],
                          [101.0, 1.0],
                          [100.0, 1.0],
                          [100.0, 0.0]
                      ]
                  ]
              },
              "properties": {
                  "prop0": "value0",
                  "prop1": { <- properties can be nested
                      "this": "that"
                  }
              }
          }]
        }
        
Adding markers from Django side

views.py


            # import libraries
            import geojson
            import shapely.geometry as geo
            from django.shortcuts import render

            # Create your views here.

            # This is the function that will render the map
            def render_map(request): 
              # create a point (geometry)
              point = geo.Point(([-86.99269856365936, 40.470060621973026]))
              # create a geojson feature 
              marker = geojson.Feature(geometry=point, properties={"msg": "Hello World"})
              # add the feature(s) to a feature collection
              data = geojson.FeatureCollection(marker)
              return render(request, "map.html", {"data": data})
              
          
Passing data to the template file

map.html


            {% load static %}
            <!DOCTYPE html>
            <html lang="en">
              <head>
                <title>Leaflet Map</title>
                <meta name="viewport" content="width=device-width, initial-scale=1.0" />
                <link
                  rel="stylesheet"
                  type="text/css"
                  href="https://unpkg.com/leaflet/dist/leaflet.css"
                  crossorigin=""
                />
                <script
                  src="https://unpkg.com/leaflet/dist/leaflet.js"
                  crossorigin=""
                ></script>
                <script src="{% static 'leaflet-map.js' %}" defer></script>
              </head>
              <body>
                
                
                {{ data|json_script:"data_geojson" }}
                <div id="map"></div>
              </body>
            </html>
            
          
Update JavaScript file

static/leaflet-map.js


            const copy =
              "© OpenStreetMap";
            const url = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png";
            const layer = L.tileLayer(url, { attribution: copy });
            const map = L.map("map", { layers: [layer] });
            // Parse the data from Django and call it data
            const data = JSON.parse(document.getElementById("data_geojson").textContent);
            // create features from the data
            let features = L.geoJSON(data.features)
              .bindPopup(function (layer) { // Add a popup to the marker
                // The popup message is from the properties of the feature
                return layer.feature.properties.msg;
              })
              .addTo(map); // Add the features to the map

            map.fitBounds(feature.getBounds()); // Fit the map to the features
            
          

Questions?

License

This course is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0) license. This is a human-readable summary of (and not a substitute for) the license. Official translations of this license are available in other languages.

You are free to:

  • Share — copy and redistribute the material in any medium or format
  • Adapt — remix, transform, and build upon the material

Under the following terms:

  • Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
  • NonCommercial — You may not use the material for commercial purposes.
  • ShareAlike — If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original.
  • No additional restrictions — You may not apply legal terms or technological measures that legally restrict others from doing anything the license permits.