Introduction to Ag Informatics

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

Outline for Today

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

Leaflet

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

Django Recap


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

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

            
          

Import Leaflet to template file


           <!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 leaflet script and stylesheet

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]]);
          
static/leaflet-map.css

            html, body {
              height: 100%;
              margin: 0; }
            #map {
              height: 100%;
              width: 100%; }
        

Adding map 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>
                <link rel="stylesheet" type="text/css" href="{% static 'leaflet-map.css' %}" />
                <script src="{% static 'leaflet-map.js' %}" defer></script>
              </head>
              <body>
                <div id="map"></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]]);

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

Adding markers from Django side

views.py

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

            # Create your views here.

            def render_map(request):
                point = geo.Point(([-86.99269856365936, 40.470060621973026]))
                marker = geojson.Feature(geometry=point, properties={"message": "Hello World"})
                data = geojson.FeatureCollection(marker)
                return render(request, "index.html", {"data": data})
              
          

Passing data to the template file

index.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>
                <link rel="stylesheet" type="text/css" href="{% static 'leaflet-map.css' %}" />
                <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] });

            const data = JSON.parse(document.getElementById("data_geojson").textContent);
            let feature = L.geoJSON(data.features)
              .bindPopup(function (layer) {
                return layer.feature.properties.message;
              })
              .addTo(map);

            map.fitBounds(feature.getBounds());
            
          

GeoJSON


          {
            "type": "FeatureCollection",
            "features": [{
                "type": "Feature",
                "geometry": {
                    "type": "Point",
                    "coordinates": [102.0, 0.5]
                },
                "properties": {
                    "prop0": "value0"
                }
            }, {
              "type": "Feature",
              "geometry": {
                  "type": "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": {
                      "this": "that"
                  }
              }
          }]
      }
        

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.