Skip to content

Commit d941349

Browse files
committed
update lab 6 instruction
1 parent 8298d08 commit d941349

File tree

1 file changed

+74
-109
lines changed

1 file changed

+74
-109
lines changed

module6/lab6/README.md

+74-109
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,19 @@
11
# Module 6, Lab 6
22

3-
<!-- ## Before the Lab
4-
We need to install new packages for this lab. Install packages could take time. It is highly suggest that you do before the lab.
3+
## Before the Lab
54

6-
```bash
7-
conda activate asm591
8-
conda install -c conda-forge geopandas
9-
conda install pyarrow
10-
conda install geojson
5+
We need to install new packages for this lab.
116

12-
```
13-
It may be possible that these packages will have difficulty being installed in the environment you have been using for previous labs. If this is the case, you will need to create a new environment. To do so, follow these steps:
14-
1. Go to the base environment, either by deactivating your asm591 environment or by restarting your miniconda prompt.
15-
2. Create a new environment by typing the following (replace the name with one of your choosing):
16-
```bash
17-
conda create --name example_name
18-
```
19-
3. Activate your new environment.
20-
4. Set the channel priorities to favor Conda Forge installation:
21-
```bash
22-
conda config --add channels conda-forge
23-
conda config --set channel_priority strict
24-
```
25-
5. Install geopandas:
26-
```bash
27-
conda install -c conda-forge geopandas
28-
```
29-
6. Then, install django:
30-
```bash
31-
conda install django
32-
```
33-
7. Then, install pyarrow:
347
```bash
35-
conda install pyarrow
36-
```
37-
8. Then, install geojson:
38-
```bash
39-
conda install geojson
8+
pip install pyarrow
9+
pip install geojson
10+
4011
```
41-
Once these are installed, you should be able to complete lab 6 with this environment. If you are still having trouble with the package installation, please let us know ASAP. -->
4212

4313
### Leaflet
4414

4515
In this lab, we will use Leaflet as a map tool. Leaflet is an open-source interactive map library. It is written in JavaScript. Therefore, it can be used in web platform including Django. More information about Leaflet and documents is here: https://leafletjs.com/index.html.
4616

47-
### Lab Submission Folder Structure
48-
49-
You will be submitting a few different things. Create a folder called **'lab6'** and copy over acrelog (including the acre folder) from lab 5.
50-
51-
```
52-
lab6/
53-
acre/ # Copy over your previous project, you'll be building on it.
54-
README.md
55-
```
56-
5717
## Embed Leaflet Map in Django
5818

5919
First, we will import Leaflet script to our html page by adding the script below into the head section of your template file (.html).
@@ -62,112 +22,97 @@ First, we will import Leaflet script to our html page by adding the script below
6222
<!DOCTYPE html>
6323
<html lang="en">
6424
<head>
65-
...
25+
<!-- Other lines in your head section -->
26+
27+
<!-- Add the section below -->
28+
<!-- First, add Leaflet stylesheet -->
6629
<link
6730
rel="stylesheet"
6831
type="text/css"
6932
href="https://unpkg.com/leaflet/dist/leaflet.css"
7033
crossorigin=""
7134
/>
35+
<!-- Second, add Leaflet stylesheet -->
7236
<script
7337
src="https://unpkg.com/leaflet/dist/leaflet.js"
7438
crossorigin=""
7539
></script>
76-
<link
77-
rel="stylesheet"
78-
type="text/css"
79-
href="{% static 'leaflet-map.css' %}"
80-
/>
40+
<!-- Last, add our JavaScript file -->
8141
<script src="{% static 'leaflet-map.js' %}" defer></script>
82-
...
42+
<!-- End of section you need to add -->
43+
44+
<!-- Other lines in your head section -->
8345
</head>
8446
<body>
85-
...
47+
<!-- Other lines in your body section -->
8648
</body>
8749
</html>
8850
```
8951

90-
There are 4 scripts that we import here. The fisrt two are Leaflet's stylesheet and JavaScript modules. There two keep all functionalities for runing Leaflet.
91-
92-
```html
93-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
94-
<link
95-
rel="stylesheet"
96-
type="text/css"
97-
href="https://unpkg.com/leaflet/dist/leaflet.css"
98-
crossorigin=""
99-
/>
100-
<script src="https://unpkg.com/leaflet/dist/leaflet.js" crossorigin=""></script>
101-
```
102-
103-
Another two scripts are `leaflet-map.css` and `leaflet-map.js` which are our custom style sheet and JavaScript that we will create later.
104-
105-
```html
106-
<link rel="stylesheet" type="text/css" href="{% static 'leaflet-map.css' %}" />
107-
<script src="{% static 'leaflet-map.js' %}" defer></script>
108-
```
52+
There are 3 scripts that we import here. The first two are Leaflet's stylesheet and JavaScript modules. The last file is the JavaScript that we will create and define our map's behaviors.
10953

110-
Note that we import with `static` in front of the custom script. In Django, Javascript and stylesheets files will be kept in `static` folder in your application. We also need to tell Django that we will use `static` folder by adding one line at the top of html file as below.
54+
Note that we import with `static` in front of the custom script. In Django, Javascript (and stylesheet) files will be kept in `static` folder in your application. We also need to tell Django that you will use `static` folder by adding one line at the top of html file as below.
11155

11256
```html
113-
{% load static %} <-- add this line
57+
{% load static %}
58+
<!-- add this line -->
11459
<!DOCTYPE html>
11560
<html lang="en">
11661
...
11762
</html>
11863
```
11964

120-
Let's create a static folder in your application folder. Then create `leaflet-map.js` and `leaflet-map.css`. Copy the following code in `leaflet-map.js`
65+
Let's create a static folder (if you have not done already) in your application folder. Then create `leaflet-map.js`. Copy the following code in `leaflet-map.js`
12166

12267
```javascript
68+
// Giving credit to people who make Leaflet
12369
const copy =
12470
"&copy; <a href='https://www.openstreetmap.org/copyright'>OpenStreetMap</a>";
71+
// Choosing a background tile. There are many other options to choose from
72+
// if you like. Check this
73+
// https://leaflet-extras.github.io/leaflet-providers/preview/
12574
const url = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png";
75+
// Create a layer on the map
12676
const layer = L.tileLayer(url, { attribution: copy });
77+
// Finally, we create a map.
78+
// This map will be placed on a HTML tag that has id "map"
12779
const map = L.map("map", { layers: [layer] });
12880

81+
// We will tell the map to show the following location as a default.
82+
// Otherwise, the starting view will be somewhere in Atlantic ocean
12983
map.fitBounds([
13084
[40.470060621973026, -86.99269856365936], // Somewhere in ACRE
13185
// You can add more coordinates
13286
]);
13387
```
13488

135-
We will be using OpenStreetMap layer. So, ther first line is to declear the source of our data. The second line is the URL of the default OpenStreetMap. There are many more options that you can use from [here](https://leaflet-extras.github.io/leaflet-providers/preview/). The third line will load the layer from providing URL. Then the forth line will put that layer into our map.
89+
We will be using OpenStreetMap layer. So, the first line is to declare the source of our data. The second line is the URL of the default OpenStreetMap. There are many more options that you can use from [here](https://leaflet-extras.github.io/leaflet-providers/preview/). The third line will load the layer from providing URL. Then the forth line will put that layer into our map.
13690

13791
One last thing for the JavaScript file is to choose the default view. That is when `map.fitBounds()` comes to play. You can pass coordinate or a list of coordinates that the map will show when you reload it.
13892

139-
Next is the stylesheet. Open `leaflet-map.css` and copy the following code. For now, we will display `body` tag with 100% screen height. Then the tag with id=`map` will also be 100% of height and width. You can change this configuration later.
140-
141-
```css
142-
html,
143-
body {
144-
height: 100%;
145-
margin: 0;
146-
}
147-
#map {
148-
height: 100%;
149-
width: 80vw;
150-
}
151-
```
152-
15393
Now, we are ready to show the map. Choose one of your existing html files (besides the template) or create a new one to place the map in. Add the following line into the body part.
15494

15595
```html
15696
<body>
157-
...
158-
<div id="map"></div>
159-
<-- add this line ...
97+
<!-- Other lines in your body -->
98+
99+
<!-- Add this line in to the body part of your html -->
100+
<!-- You can change the width and height -->
101+
<div id="map" style="height: 100%; width: 100%"></div>
102+
103+
<!-- Other lines in your body -->
160104
</body>
161105
```
162106

163-
Lastly, you will need to config `url.py` and `views.py` to point to the template file we just created. The following snippet assumes you have placed it in the index.html file, so swap out the references to the index with your page if you chose elsewhere.
107+
Lastly, you will need to config `url.py` and `views.py` to point to the template file we just created. The following snippet assumes you have placed it in the new page called `map.html`.
164108

165109
```python
166110
# views.py
167111
from django.shortcuts import render
168112

113+
# Add this function
169114
def render_map(request):
170-
return render(request, "index.html")
115+
return render(request, "map.html")
171116
```
172117

173118
```python
@@ -176,13 +121,16 @@ from django.urls import path
176121
from . import views
177122

178123
urlpatterns = [
179-
path("", views.render_map, name="index"),
124+
# Your other patterns
125+
path("map", views.render_map, name="map"), # add new one
180126
]
181127
```
182128

129+
Now, when you go to `127.0.0.1:8000/acrelog/map`, you should see the map.
130+
183131
## Putting Features on the Map
184132

185-
Leaflet allows us to modify the map freely. One of the common things to put into the map is a marker. Techically speaking, a marker is a point (geometric object) on the map. To add a marker, first add the following line into `leaflet-map.js`.
133+
Leaflet allows us to modify the map freely. One of the common things to put into the map is a marker. Technically speaking, a marker is a point (geometric object) on the map. To add a marker, first add the following line into `leaflet-map.js`.
186134

187135
```javascript
188136
let marker = L.marker([40.470060621973026, -86.99269856365936]).addTo(map);
@@ -208,23 +156,30 @@ def render_map(request):
208156
point = geo.Point(([-86.99269856365936, 40.470060621973026]))
209157
marker = geojson.Feature(geometry=point, properties={"message": "Hello World"})
210158
data = geojson.FeatureCollection(marker)
211-
return render(request, "index.html", {"data": data})
159+
return render(request, "map.html", {"data": data})
212160
```
213161

214-
First, we import `geojson` and `shapely.geometry`. We will use `shapely.geometry` to create geometry objects. In this case, we want to create a marker that is a point. Then we create a geoJSON feature object by passing the geometry and properties. The properties parameter accepts a dictionary. Therefore, you can have multiple key-value properties. Next, we wrap the marker into a geoJSON feature collection. A GeoJSON feature collection is a list of geoJSON feature. You can pass a list of geoJSON features. However, in this example, we only pass one marker. Lastly, we return the render page with additional information going back to the HTML side.
162+
First, we import `geojson` and `shapely.geometry`. We will use `shapely.geometry` to create geometry objects. In this case, we want to create a marker that is a point. Then we create a geoJSON feature object by passing the geometry and properties. The `properties` parameter accepts a dictionary. Therefore, you can have multiple key-value properties. Next, we wrap the marker into a geoJSON feature collection. A geoJSON feature collection is a list of geoJSON feature. You can pass a list of geoJSON features. However, in this example, we only pass one feature (a marker). Lastly, we return the render page with additional information going back to the HTML side.
215163

216-
Open `index.html` file and modify as below. We interpolate date from Django by wrapping it with double curly brackets. Then we give HTML a clue that this is a JSON data. Lastly, we name this data "data_geojson" for HTML and JavaScript side.
164+
Open `map.html` file and modify as below. We interpolate date from Django by wrapping it with double curly brackets. Then we give HTML a clue that this is a JSON data. Lastly, we name this data `data_geojson` for HTML and JavaScript side.
217165

218166
```html
219167
<body>
168+
<!-- Add the line below -->
220169
{{ data|json_script:"data_geojson" }}
221-
<div id="map"></div>
170+
<div id="map" style="height: 100%; width: 100%"></div>
222171
</body>
223172
```
224173

225-
Next we need to process the geoJSON data in JavaScript file. Open `leaflet-map.js` then add the code below. First, we parse the data from HTML. As the data is in geoJSON format, we can use Leaflet built-in function to display all features in the geoJSON feature collection. We can also bind a popup box with message that we want to show. In this case, it is a `message` property that we embed from Python side (`view.py`). Finally, we add the feature to the map.
174+
Next, we need to process the geoJSON data in JavaScript file. Open `leaflet-map.js` then add the code below. First, we parse the data from HTML. As the data is in geoJSON format, we can use Leaflet built-in function to display all features in the geoJSON feature collection. We can also bind a popup box with message that we want to show. In this case, it is a `message` property that we embed from Django side (`view.py`). Finally, we add the feature to the map.
226175

227176
```javascript
177+
// You can delete this part. We move this marker creation to Django's side.
178+
let marker = L.marker([40.470060621973026, -86.99269856365936])
179+
.addTo(map)
180+
.bindPopup("This is a popup");
181+
182+
// New part. Add these lines below
228183
const data = JSON.parse(document.getElementById("data_geojson").textContent);
229184

230185
let feature = L.geoJSON(data.features)
@@ -236,30 +191,40 @@ let feature = L.geoJSON(data.features)
236191

237192
You can add multiple geometry objects into one geoJSON feature collection. The objects could be points, lines, or polygons. The most of the data processing will be done in `view.py`. Whatever data you embed into rendering process will be passed to HTML and JavaScript side for display into the map.
238193

239-
## Display ACRE map
194+
## Your turn: display ACRE map
240195

241196
You will see `acre_geometry.parquet` file in the data folder. Parquet file (.parquet) is a compressed file (like a zip file). Inside, you will see the geometry of fields in ACRE. You can use `geopandas` to read this file by `read_parquet("filename.parquet")`.
242197

243-
Your task is:
198+
**Your tasks are**:
244199

245200
- Create a map of ACRE with field's boundaries.
246201
- When you click on the field, the map will show a popup with a brief summary of the latest operation on that field and a link to view the full detail of that field.
247202

203+
### Lab Submission Folder Structure
204+
205+
You will be submitting a few different things. Create a folder called **'lab6'** and copy over acrelog (including the acre folder) from lab 5.
206+
207+
```
208+
lab6/
209+
acre/ # Copy over your previous project, you'll be building on it.
210+
README.md
211+
```
212+
248213
## Submitting your work
249214

250-
Make sure to save your notebook code after completing all the steps. Remember to use the git commands "add", "commit", and finally "push" to add your files, commit the changes with a comment, and push the changes to the Github website. Also remember, you should have a commit history with at least 5 commits to demostrate ongoing effort (don't just commit it all 5 mins before it's due!).
215+
Make sure to save your notebook code after completing all the steps. Remember to use the git commands "add", "commit", and finally "push" to add your files, commit the changes with a comment, and push the changes to the Github website. Also remember, you should have a commit history with at least 5 commits to demonstrate ongoing effort (don't just commit it all 5 mins before it's due!).
251216

252217
GO TO BRIGHTSPACE, submit the link to your repository. You are done!
253218

254219
## Future Learning Pathways
255220

256221
Check the lecture from previous iterations of this course
257222

258-
- Lecture 6.1: www.aginformaticslab.org/ag-informatics-course/module6/lecture6.1.html
259-
- Lecture 6.2: www.aginformaticslab.org/ag-informatics-course/module6/lecture6.2.html
260-
- Lecture 6.3: www.aginformaticslab.org/ag-informatics-course/module6/lecture6.3.html
223+
- Lecture 6.1: https://ag-informatics.github.io/ag-informatics-course/modarchive/module6/lecture6.1.html
224+
- Lecture 6.2: https://ag-informatics.github.io/ag-informatics-course/modarchive/module6/lecture6.2.html
225+
- Lecture 6.3: https://ag-informatics.github.io/ag-informatics-course/modarchive/module6/lecture6.3.html
261226

262-
You can work on `exercise.ipynp`. This is optional but highly recommended if you want to learn how to work with geospatial data.
227+
You can work on `exercise.ipynb`. This is optional but highly recommended if you want to learn how to work with geospatial data.
263228

264229
The [Shapely documentation](https://shapely.readthedocs.io/en/stable/manual.html) is actually an excellent place to explore geometric operations. You can learn more than you ever thought possible about boundaries, geometric objects and how to work with them. **Really!** It has been well written! It is less code documentation and more of an introduction to the basics of geometry. If you are in Precision Agriculture, or another field in which geometry is important, you really should understand the issues it discusses. For example, a line may "contain" a point, but it doesn't "cross" the point. Also, lines that "touch" do not "overlap" and lines that "overlap" do not "touch." We are not very precise when we discuss these ideas, but programming requires a degree of precision that can be very useful to understand. The documentation makes sure to mention these gotchas between how we think and talk about geometry.
265230

0 commit comments

Comments
 (0)