-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathindex.html
More file actions
1249 lines (1218 loc) · 108 KB
/
Copy pathindex.html
File metadata and controls
1249 lines (1218 loc) · 108 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head>
<meta charset="utf-8">
<meta name="generator" content="quarto-1.9.38">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<meta name="author" content="Arno Timmer, Jan Verbesselt, Jorge Mendes de Jesus, Aldo Bergsma, Johannes Eberenz, Dainius Masiliunas, David Swinkels, Judith Verstegen, Corné Vreugdenhil">
<meta name="dcterms.date" content="2026-07-23">
<title>Python Environments</title>
<style>
/* Default styles provided by pandoc.
** See https://pandoc.org/MANUAL.html#variables-for-html for config info.
*/
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
div.columns{display: flex; gap: min(4vw, 1.5em);}
div.column{flex: auto; overflow-x: auto;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
ul.task-list li input[type="checkbox"] {
width: 0.8em;
margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */
vertical-align: middle;
}
/* CSS for syntax highlighting */
html { -webkit-text-size-adjust: 100%; }
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
.sourceCode { overflow: visible; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
}
pre.numberSource { margin-left: 3em; padding-left: 4px; }
div.sourceCode
{ }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
</style>
<script src="index_files/libs/clipboard/clipboard.min.js"></script>
<script src="index_files/libs/quarto-html/quarto.js" type="module"></script>
<script src="index_files/libs/quarto-html/tabsets/tabsets.js" type="module"></script>
<script src="index_files/libs/quarto-html/popper.min.js"></script>
<script src="index_files/libs/quarto-html/tippy.umd.min.js"></script>
<script src="index_files/libs/quarto-html/anchor.min.js"></script>
<link href="index_files/libs/quarto-html/tippy.css" rel="stylesheet">
<link href="index_files/libs/quarto-html/quarto-syntax-highlighting-15634bcf2e68342d4ad2dfa704d543f6.css" rel="stylesheet" id="quarto-text-highlighting-styles">
<script src="index_files/libs/bootstrap/bootstrap.min.js"></script>
<link href="index_files/libs/bootstrap/bootstrap-icons.css" rel="stylesheet">
<link href="index_files/libs/bootstrap/bootstrap-efbb37e9afcc02144ebbc7afd12a776f.min.css" rel="stylesheet" append-hash="true" id="quarto-bootstrap" data-mode="light">
</head>
<body class="fullcontent quarto-light">
<div id="quarto-content" class="page-columns page-rows-contents page-layout-article">
<main class="content" id="quarto-document-content">
<header id="title-block-header" class="quarto-title-block default">
<div class="quarto-title">
</div>
<div class="quarto-title-meta">
<div>
<div class="quarto-title-meta-heading">Author</div>
<div class="quarto-title-meta-contents">
<p>Arno Timmer, Jan Verbesselt, Jorge Mendes de Jesus, Aldo Bergsma, Johannes Eberenz, Dainius Masiliunas, David Swinkels, Judith Verstegen, Corné Vreugdenhil </p>
</div>
</div>
<div>
<div class="quarto-title-meta-heading">Published</div>
<div class="quarto-title-meta-contents">
<p class="date">July 23, 2026</p>
</div>
</div>
</div>
</header>
<div class="cell">
<style type="text/css">
@import url("https://netdna.bootstrapcdn.com/bootswatch/3.0.0/simplex/bootstrap.min.css");
.main-container {max-width: none;}
pre {color: inherit; background-color: inherit;}
code[class^="sourceCode"]::before {
content: attr(class);
display: block;
text-align: right;
font-size: 70%;
}
code[class^="sourceCode r"]::before { content: "R Source";}
code[class^="sourceCode python"]::before { content: "Python Source"; }
code[class^="sourceCode bash"]::before { content: "Bash Source"; }
</style>
</div>
<p><font size="6"><a href="https://geoscripting-wur.github.io/">WUR Geoscripting</a></font> <img src="https://geoscripting-wur.github.io/figs/WUR_RGB_standard_2025.svg" alt="WUR logo" style="height: 50px;"></p>
<section id="python-environments" class="level1">
<h1>Python Environments</h1>
<section id="introduction" class="level2">
<h2 class="anchored" data-anchor-id="introduction">Introduction</h2>
<p>Good afternoon and welcome to the python part of this course! Today we will introduce how we will work with Python during this course and show some alternative methods. If you are unfamiliar with Python and/or feel that you need more training, follow one of the Datacamp courses as introduction into Python.s</p>
<ul>
<li><a href="https://www.datacamp.com/courses/intro-to-python-for-data-science">Introduction to Python</a> | recommended to follow if you haven’t any scripting experience so far</li>
<li><a href="https://www.datacamp.com/courses/python-for-r-users">Python for R users</a> | recommended if you have experience already in R</li>
</ul>
</section>
<section id="todays-learning-objectives" class="level2">
<h2 class="anchored" data-anchor-id="todays-learning-objectives">Today’s Learning objectives</h2>
<ul>
<li>Know how to work with virtual environments: <em>pixi</em></li>
<li>Know how to run a Python script from the terminal</li>
<li>Get introduced to Python editors and IDEs</li>
<li>Refresh Python programming knowledge</li>
</ul>
</section>
</section>
<section id="introduction-to-python-environments" class="level1">
<h1>Introduction to Python & Environments</h1>
<p>Python is a jack-of-all-trades programming language that is free, flexible, open-source, cross-platform and has a very large community behind it. According to many rankings it’s the most popular programming language. If you ask Python programmers what they like most about Python, they will often cite its high readability, multi-purposeness and high availability of good packages. Python was developed by Guido van Rossum, a Dutch computer scientist. Python was designed to be an everyday programming language, easier to use than for example C++ or Java while still being able to do do almost everything. The thought has always been that the time of the programmer is more important than the time of the computer, therefor reading and writing Python code is relatively easy compared to compiled languages, but these compiled languages are sometimes quicker. Luckily there are lots of very quick functions available in Python that might be programmed in different languages.</p>
<p>Because of the popularity and the large community, there are many packages available for geoscripting, data wrangling, visualization, machine learning and for almost everything else. Additionally, there is a giant community present at for example <a href="https://stackoverflow.com/questions/tagged/python">stackoverflow</a> where you can find help if you are stuck. Also, since there is so many python code online, generative AI is relatively good at writing Python. Be careful though, a lot of the code is not written for spatial applications, so large language models might behave like a data scientist without GIS knowledge…</p>
<p>Relevant packages for this course are for example:</p>
<ul>
<li>Geoscripting
<ul>
<li>GeoPandas (Vector Processing)</li>
<li>Shapely (The core of Vector representation)</li>
<li>Rasterio (Raster Processing)</li>
<li>GDAL/OGR (Vector and Raster Processing)</li>
<li>QGIS plugins (Open Source GIS)</li>
<li>ArcPy (Propietary GIS)</li>
</ul></li>
<li>Data Handling
<ul>
<li>Pandas (Dataframes and Data Analysis)</li>
<li>NumPy (Scientific Computing)</li>
</ul></li>
<li>Visualization
<ul>
<li>Matplotlib (General Graphics)</li>
<li>Seaborn (Statistical Graphics)</li>
<li>LeafMap (Interactive Maps)</li>
</ul></li>
<li>Machine Learning
<ul>
<li>scikit-learn (Machine Learning)</li>
<li>Keras + TensorFlow (Deep Learning)</li>
<li>PyTorch (Deep Learning)</li>
</ul></li>
</ul>
<section id="python-package-management" class="level2">
<h2 class="anchored" data-anchor-id="python-package-management">Python package management</h2>
<p>The high availability of packages is also a threat sometimes. Packages make use of code and functionality from other packages. We call this “software dependency”. If a piece of software is developed depending on a package, but this packages changes later on, the initial piece of software might not work anymore. Different packages require different dependencies that they are built upon. See for example the <a href="https://github.com/geopandas/geopandas/blob/main/pyproject.toml#L22">dependencies of GeoPandas</a>. It is important to make sure all these dependencies are working together and that the right versions of the dependencies are used. Luckily, a set of tools exist for installing and managing Python packages. It is possible to install packages on your main Python installation (This main python is called the <strong>base</strong> python interpreter), but sooner or later you will get conflicting Python packages since packages have varying dependencies and you might have installed several versions of the same package. It can even break your system Python interpreter.</p>
<p>Therefore, we strongly recommend to use a Python package manager that uses virtual environments. This way, you can create a separate environment on your machine for each project you are working on. In these environments, any dependency of the project, such as python packages, other software or C libraries can be installed. We will use them here for installing Python packages. Packages installed in one environment do not interfere with your base Python interpreter or with other environments. Additionally, it is possible to export and share a complete list of the requirements for your (open source) project with collaborators or users of your code. In this way, collaborators can install the dependencies and start working with your code right away, instead of struggling with dependecies first (this is called <a href="https://en.wikipedia.org/wiki/Dependency_hell">Dependency Hell</a>.</p>
</section>
<section id="pixi" class="level2">
<h2 class="anchored" data-anchor-id="pixi">Pixi</h2>
<p>Pixi is a cross-platform package management tool written in rust by the company <strong>prefix.dev</strong>. Pixi packages 3 features. <strong>Virtual environment management</strong>, <strong>Package Management</strong> and <strong>Task Management</strong>. For us, the environment and package management are the most important. Pixi allows you to create virtual environments per project, isoluating packages from other projects. For installing packages in these environments, and making sure the packages use the right dependencies, it uses both <strong>pip</strong> and <strong>conda</strong>. Pip is a installer for python packages. Pip by itself is good in installing python packages, but not very good in protecting you from dependency hell. Pip installs packages from <a href="https://pypi.org/">PyPi</a>, a large repository of python packages. Conda allows you to install software packages in general, so for example python packages but also C++ tools. It installs from binary packages, making it a lot faster than having to build packages from the source code. It also means that it has a selected list of packages and therefor a bit lower availability of packages than pip. These lists are called channels, and we can choose from which channel to install. Combining conda and pip was a pain for a very long time. A package installed by pip was sometimes also installed as a dependency by conda, since these two tools were not communicating with eachother. It often resulted in packages clashing and making environments break easily. Pixi makes it easy and fast to install packages using both conda and pip. Additionally, <strong>prefix.dev</strong> wrote conda from the ground up using rust, including a lot of features that make the same experience a lot faster. Also they use <strong>UV</strong> (also written in Rust) to handle some pip functionality, allowing for better integration and, most importantly, a lot faster environment solving and installation than conda allowed before.</p>
</section>
<section id="installing-pixi" class="level2">
<h2 class="anchored" data-anchor-id="installing-pixi">installing pixi</h2>
<p>To install, run the following line in the bash shell.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="fu">wget</span> <span class="at">-qO-</span> https://pixi.sh/install.sh <span class="kw">|</span> <span class="fu">sh</span></span></code></pre></div><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></div>
</div>
</section>
<section id="pixi-installation" class="level2">
<h2 class="anchored" data-anchor-id="pixi-installation">Pixi installation</h2>
<p>Creating a project that uses pixi starts with a <a href="https://pixi.prefix.dev/latest/reference/pixi_manifest/">manifest</a> file called <code>pixi.toml</code>. In this file all the configuration information is stored, including the dependencies. Pixi can read this document, resolve the dependencies and install all necessary packages. A pixi project, called example in this case, can be initiated with the following command:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="ex">pixi</span> init example</span></code></pre></div><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></div>
</div>
<p>This will install pixi in <code>~/.pixi</code>. Restart your shell to be able to use pixi in your temrinal.</p>
</section>
<section id="using-pixi" class="level2">
<h2 class="anchored" data-anchor-id="using-pixi">Using pixi</h2>
<p>After running this, a directory should be created with the name of the project that we can change into using <code>cd</code>. When listing the files (<code>ls</code>), 3 files should be present: <code>.gitattributes</code>, <code>.gitignore</code>, and <code>pixi.toml</code>. The contents of <code>pixi.toml</code> look like this:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3"><pre class="sourceCode toml code-with-copy"><code class="sourceCode toml"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">[workspace]</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="dt">authors</span> <span class="op">=</span> <span class="op">[</span><span class="st">"Arno Timmer <[email protected]>"</span><span class="op">]</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="dt">channels</span> <span class="op">=</span> <span class="op">[</span><span class="st">"conda-forge"</span><span class="op">]</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="dt">name</span> <span class="op">=</span> <span class="st">"example"</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="dt">platforms</span> <span class="op">=</span> <span class="op">[</span><span class="st">"linux-64"</span><span class="op">]</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a><span class="dt">version</span> <span class="op">=</span> <span class="st">"0.1.0"</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a><span class="kw">[tasks]</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a><span class="kw">[dependencies]</span></span></code></pre></div><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></div>
</div>
<p>The <strong>workspace</strong> defines the metadata and properties for the project, <strong>Tasks</strong> can be used to configure tasks, allowing you to for example pass environment variables and running different parts of scripts easily, (we will not use this during this course, but loook at the <a href="https://pixi.prefix.dev/latest/workspace/advanced_tasks/">pixi documentation</a> for more information), and <strong>dependencies</strong> defines the packages dependencies. It can list channels to define from which <a href="https://conda.org/learn/faq/#what-is-a-conda-channel">conda channel</a> the packages are installed.</p>
<p>Now we have an empty pixi project, let’s add some packages to it. We have entered the python week, so lets add python as a dependency. Since Pixi can use a large variety of software, we have to be specific, and install python as first thing. Installing a pyc</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="ex">pixi</span> add python</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="fu">cat</span> pixi.toml</span></code></pre></div><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></div>
</div>
<div class="cell">
<pre class="output cell-code"><code>[workspace]
channels = ["conda-forge"]
name = "example"
# This will be whatever your machine's platform is
platforms = ["linux-64"]
version = "0.1.0"
[tasks]
[dependencies]
python = ">=3.13.5,<3.14"</code></pre>
</div>
<p>If we check your project folders contents, we also see a <code>pixi.lock</code> file that has been created, together with a <code>.pixi</code> directory. After solving the environment as defined in you <code>.toml</code> file, the environment gets solved and the exact set of packages with their versions is stored in the lock file. The lock file is meant for easy recreation of the environment that was used, <strong>do not manually make changes in this file!</strong>. Updating your environment, installing packages for example, goes by adding them to the toml file or adding them through the commandline.</p>
<p>The environment is stored in the <code>.pixi</code> directory. Each project you use pixi in gets this directory and it contains all the files that the packages need, so with a lot of packages this directory gets quite big! Do not push this to git! By initializing a pixi project, the <code>.gitignore</code> that gets created will make sure that this directory does not get tracked by git.</p>
<p>Let’s add and use a package to the example environment. Use the following command:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb6"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="ex">pixi</span> add cowpy <span class="at">--pypi</span></span></code></pre></div><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></div>
</div>
<p>Now create a new python file <code>cow.py</code> containing the following code:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb7"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> cowpy.cow <span class="im">import</span> Cowacter</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>message <span class="op">=</span> Cowacter().milk(<span class="st">"Hello, my dear Geoscripter!"</span>)</span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(message)</span></code></pre></div><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></div>
</div>
<p>We can run the file using:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb8"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="ex">pixi</span> run python cow.py</span></code></pre></div><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></div>
</div>
<p>Pixi will solve the depencies, create the environment (if it did not exist yet) and run the file. Another way of running files is to enter a pixi shell and run the script from there. You can start the pixi shell using:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb9"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="ex">pixi</span> shell</span></code></pre></div><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></div>
</div>
<p>This will show the name of your environment in brackets before your curent working directory. When an environment is activated you can run a script using the command that you would normally use to run that commaned, but it will use the executables from the environment if existing. So:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb10"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="ex">python</span> cow.py</span></code></pre></div><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></div>
</div>
<p>If you want to remove a package from the environment, you can do that by simply removing it from the toml file. After running <code>pixi run</code> a new environment will be created (Pixi can spot the differences with the <code>pixi.lock</code> file) and the package will be removed.</p>
</section>
<section id="collaborating-with-others" class="level2">
<h2 class="anchored" data-anchor-id="collaborating-with-others">Collaborating with others</h2>
<p>When you are collaborating with others, or want to make your project available to other people on the internet, you need to specify what dependencies your project depend on. We already mentioned that using an environment makes this easy and doable. Adding your <code>pixi.toml</code> to your repository makes it possible to others to create a pixi environment from that definition.</p>
<p>When a toml is available, you can run <code>pixi init</code> and pixi will find that toml and create an environment from the dependencies as listed in the file. In the same way, you can create the same environment as the code from your colleague.</p>
<p>It might happen that you want to use a project that is not using pixi (yet). Since pixi is built upon conda and pip, it supports importing dependencies from those. These dependencies are usually defined in an environment.yml or env.yml (or .yaml) for conda, and requirements.txt for pip. We can import these using <code>pixi import</code>. In this course we used to define environments using an env.yml, so you might run into one of those that was supposed to be converted… You can create your pixi environment using:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb11"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="ex">pixi</span> init <span class="at">--import</span> env.yml</span></code></pre></div><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></div>
</div>
<p>Pixi will then create a <code>pixi.toml</code> from that, and the environment belonging to that <code>pixi.toml</code>.</p>
</section>
</section>
<section id="python-editors-and-ides" class="level1">
<h1>Python editors and IDEs</h1>
<p>There are many Integrated Development Environments (IDEs) for Python, and every programmer has their own preference. An IDE is a software application that provides facilities for software development. There are roughly two ways in which python developers are working with python.</p>
<ol type="1">
<li>Writing scripts and mainly working with out of the box functionality from packages in notebooks. In this way you might explore some data or do remote analysis that requires a lot of computing resources. Jupyter Notebooks and Jupyter Labs is developed for this purpose.
<ul>
<li><a href="http://jupyter.org/">Jupyter notebook</a> integrates visualization with code and is suitable for making tutorials, dashboards, data exploration, do prototype testing or run largely predefined functionality. It is not suited to do develop large projects in. Jupyter Notebook runs in a browser on a localhost server or on a web server, for example remotely on a cluster or on <a href="https://colab.research.google.com/">Google cloud</a>. In Jupyter you mix text (documentation or explanation) with code and images (plots for example). Jupyter is cell-based, meaning that code is run per cell. The variables and objects are stored in memory across cells. Since Jupyter saves the state, including the output of a cell, it does not work very well with git. Additional tools are needed for colaborating and making sure that the output from one used does not interfere with another user’s output, even if it is the same output.</li>
</ul></li>
<li>Writing python code for larger projects, requiring functions, multiple modules and multiple files. For larger projects, some additional tooling is very helpful. IDE’s come with tooling to support git, debugging, autocompletion and GenAI. In these IDE’s, in contrast to Rstudio, code is run per file instead of line by line or cell by cell as in notebooks. A file might import other files and so on. This might need some getting used to but the debugger is there to help you and inspect how the interpreter is reading your code. Two IDE’s that are good to know:
<ul>
<li><a href="https://code.visualstudio.com/">Visual Studio Code</a>: Visual Studio Code (VSCode) is a very complete IDE. It can be used to develop software in almost all languages and it has a lost of advanced functionality. VSCode is developed by Microsoft, but it is built upon an open source distribution and numerous packages exist that are open source, for example Python functionality. <em>In this course, VSCode is the recommended Python IDE, it is pre-installed. in the Linux VM.</em></li>
<li><a href="https://www.jetbrains.com/help/pycharm/install-and-set-up-pycharm.html">PyCharm Community Edition</a> is a free professional Python IDE with a lot of advanced functionality, such as integrated GIT version control, code completion, code checking, debugging and navigation. This IDE can optionally be used as an alternative to VSCode. If you have experience, you can use Pycharm instead of VSCode, but do know that you will not be assisted for solving IDE-related issues.</li>
</ul></li>
</ol>
<p>Lastly, an IDE that is good to mention is <a href="https://www.spyder-ide.org/">Spyder</a>. Spyder is a lightweight IDE, it is similar to Rstudio.</p>
<section id="visual-studio-code" class="level2">
<h2 class="anchored" data-anchor-id="visual-studio-code">Visual Studio Code</h2>
<p>Visual studio code is a complete IDE that is used by many developers, Python developers but also developers for other languages. To get started in VSCode we will set up a basic project structure and run some very basic code. There is a difference opening a file and opening a project in VSCode. Opening a file will let you edit that file and possibly run it. Opening a directory or a project consisting of multiple (sub)directories will let you set a default interpreter, search and replace throughout the project and navigate to function imports and many more advantages. We recommend you to generally use a seperate project for each tutorial, exercise and assignment. In that way you can use dedicated environments and keep a coherent folder structure throughout the course.</p>
<p>Create the following files:</p>
<pre><code> MyPackage/
├── environment.yaml
├── main.py
└── MyPackage
└── __init__.py</code></pre>
<p><img src="images/vscode/empty-vscode.png" alt="VSCode when you open it for the first time" width="100%"></p>
<p>Create an empty directory <code>MyPackage</code> and open it using the button that shows in the main screen when you open VSCode. Create the files as the file tree shows above. Open <code>main.py</code>, and write the following code:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb13"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="st">'hello world'</span>)</span></code></pre></div><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></div>
</div>
<p>VSCode directly recognizes the python file extension (.py) and does some suggestions. In the bottom right you can what type of file VSCode thinks you are working in, it also shows a number, most likely 3.12.x if you are following this course in 2025. This number is the python version of the interpreter that is now running, more on this later. In the left there is a column with some buttons. These buttons are, from top to bottom, for:</p>
<ul>
<li>Files, showing the project files. Clicking on a file opens it.</li>
<li>Search, giving the option to searching and replacing text throughout the project</li>
<li>version control, showing the git status of the project.</li>
<li>Run and debug, showing results and the state during debugging</li>
<li>Extensions, for installing and maintaining extensions.</li>
<li>Testing, for testing code (we will not use this throughout the course)</li>
</ul>
<div class="cell" type="alert alert-danger">
<div class="alert alert-danger">
<p>
<strong>Warning for students taking the course</strong>: VSCode comes with advanced integration of generative AI. It is recommended to not make use of GenAI while learning to code. Struggling through how to get a script working is how you learn, and that is what this course is about. Generating the correct result will not teach you anything.
</p>
<p>
It is recommended to turn off automatic features that copilot offers. You can do this by 1. going to File → Preferences → Settings (or press Ctrl+,). 2. In the search bar, type “Copilot”. 3. Find the settings for: GitHub Copilot: Enable (controls code completions) GitHub Copilot Chat: Enable (controls chat/agent features) Uncheck or set these to “false” to disable them globally.
</p>
</div>
</div>
<p>Open the <code>environment.yaml</code> and paste the following in there:</p>
<pre><code>name: geotest
dependencies:
- python
- numpy
- folium</code></pre>
<p><img src="images/vscode/main.py.png" alt="The main.py script" width="100%"></p>
<section id="extensions" class="level3">
<h3 class="anchored" data-anchor-id="extensions">Extensions</h3>
<p>You can run the code by pressing the play button in the top right. When you do this, a terminal pops up, showing the output of the file. As explained before, in VSCode we run code per file instead of per line as we are used to in R. As you can see, already out of the box there is some python functionality that is built into VSCode, but there is more. Open the extensions page, type python and install the extensions <em>Python</em>, <em>Python Debugger</em> and <em>jupyter</em>. These are the extensions that we will use throughout the course, more is not necessary for now, but there is a whole world out there.</p>
<p><img src="images/vscode/extentions.png" alt="Python extensions in VSCode" width="100%"></p>
<p>To show you some of this functionality, write the following code in the <code>MyPackage.__init__.py</code>:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb15"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> some_function(a_number):</span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f'I am printing the number </span><span class="sc">{</span>a_number<span class="sc">}</span><span class="ss">'</span>) <span class="co"># This is is a formatted string</span></span></code></pre></div><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></div>
</div>
<p>Now, in the <code>main.py</code> file, run the function.:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb16"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a>some_function(<span class="dv">5</span>)</span></code></pre></div><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></div>
</div>
<p>A yellow squiggly line showed up. This means something is wrong with the code. And this is right, if we would run the code python would complain that the function is not known. We forgot to import it, we defined it but did not import it yet. If you stand with your cursor in the function call, and pres <code>ctrl</code> + <code>.</code>, visual code will try to figure out how to solve the issue. In this case it proposes to import it from <code>MyPackage.MyPackage</code>. If you press enter it imports the function. You can now run the function.</p>
<p>If you press <code>ctrl</code> and click on the function in <code>main.py</code> you will open the function definition. This is very useful when navigating through a large project.</p>
</section>
<section id="environments-in-vscode" class="level3">
<h3 class="anchored" data-anchor-id="environments-in-vscode">Environments in VSCode</h3>
<p>As we mentioned before the numbers in the bottom right show the version of the python interpreter associated with the project. We learned about environments before, so let’s create an environment. VSCode comes with a bash terminal. If you ran some code before this might be open, otherwise click terminal in the top menu (in the same section as <code>File</code> and <code>Edit</code>) or press <code>ctrl</code>+<code>shift</code>+` (use the back tick, most likely on the top left of your keyboard.). Another way to open the terminal is to press <code>Ctrl</code> + <code>Shift</code> + <code>P</code> and type terminal, and click Create New Terminal (With Profile). <code>Ctrl</code> + <code>Shift</code> + <code>P</code> opens the command pallet, and by searching in here you can access almost all functionality from VSCode. It is usually a good start if you are looking for something, just start typing and see if the correct option comes up.</p>
<p>First we need to set up our environment. Activate the <em>geotest</em> environment if you created it before or create it using the yaml.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb17"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="co"># One of the following</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a><span class="ex">mamba</span> env create <span class="at">-f</span> environment.yaml</span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a><span class="co"># or </span></span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-6"><a href="#cb17-6" aria-hidden="true" tabindex="-1"></a><span class="bu">source</span> activate geotest </span></code></pre></div><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></div>
</div>
<p>If <code>(geotest)</code> is visible before the active line in the terminal the environment is successfully activated. However, this is something different than associating it to the project, if you run a file this interpreter will still not be used. To do this we are going to use the Command Palette. Click the bar in the top center or press <code>Ctrl</code> + <code>Shift</code> + <code>p</code> to open it. Type <code>>Python: select interpreter</code>. The <code>></code> sign tells VSCode your are looking for commands. Without you can search files in the project. It auto-completes, so <code>python</code> is enough. Select it. It should already show up. It also gives the option to create a new environment, more on that later.</p>
</section>
<section id="debugger-repl" class="level3">
<h3 class="anchored" data-anchor-id="debugger-repl">Debugger & REPL</h3>
<section id="debugger" class="level4">
<h4 class="anchored" data-anchor-id="debugger">Debugger</h4>
<p>Now, you might wonder how you will write code without being able to inspect what is going on. And don’t be afraid there are ways to help you. The <em>debugger</em> and the interactive <em>REPL</em> <em>(Read-Evaluate-Print Loop)</em> are tools developers use to make developing easier. Firstly the debugger. The debugger is a way of running code where you can set breakpoints and inspect the state of the code and all the variables and objects in memory. While at a checkpoint you can manipulate variables, print them and test small pieces of code on them to figure out how to proceed. From the checkpoint it is possible to proceed line by line, stepping into your function or imported packages to get a good understanding of what is happening and often identifying issues. Sounds good right?</p>
<p>You start the debugger by instead of clicking on the run arrow, click on the small drop down arrow right next to it and click Python Debugger: Debug Python File. If you didn’t set a break-point the code will run as normal, but the code will take a bit longer to run. The real magic begins if we set a break-point. Click left of the line number next the where the function <code>some function</code> is called in <code>main.py</code> and debug the file again. In the top left, where the run button was before, now some other buttons showed up. These buttons help you navigate through the code: * Continue (<code>F5</code>): continue running the script until either the next break-point or finish running * Step over (<code>F10</code>): Skip this function and continue to the next line * Step into (<code>F11</code>): step into the function * step out (<code>shift</code> + <code>F11</code>): set out of the function (in this case we are not in a function) * Restart (<code>ctrl</code> + <code>shift</code> + <code>F5</code>): Re run the script * Stop (<code>shift</code> + <code>f5</code>): Stop the debugger</p>
<p><img src="images/vscode/debugger.png" alt="The debugger in VSCode" width="100%"></p>
<p>If you step into the function we can find out the real value of the debugger. On the top left panel we can see the local variables, the variables that are known within the function, and the global variables. These are the variables for this module. In the bottom left we can switch to different modules, when clicking on <code><module> main.py</code> we can inspect the variables known in the script <code>main.py</code>. It is directly clear how python handles variables, what is known within a function and what is not. Switch to the <code>some_function</code> scope and you can see there is 1 local variable <code>a_number</code> which is the input the the function, 5 in this example. When you will start making use of more advanced objects with properties and methods this variable overview will become more elaborate.</p>
</section>
<section id="repl" class="level4">
<h4 class="anchored" data-anchor-id="repl">REPL</h4>
<p>Additionally to the debugger, you can play around with code in jupyter style notebooks. You can start the repl by opening the command palette (<code>Ctrl</code> + <code>Shift</code> + <code>P</code>) and type <em>repl</em>, and click <em>‘Python: Start Native Python REPL’</em>. A new window will show up, and if you type some python in the cell that says <em>Press Enter to execute</em>, for example <code>print('hello everybody!!')</code>. The code you ran shows up in a cell and the output in the cell below. This is how notebooks work, they contain code per cell and show the results in line.</p>
<p>Notebooks allow you to show visuals inline as well. For example we can show plots or an interactive map, directly in the notebook. Type the following Python code in the code cell:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb18"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> folium</span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a>m <span class="op">=</span> folium.Map(location<span class="op">=</span>[<span class="fl">51.9700000</span>, <span class="fl">5.6666700</span>], zoom_start<span class="op">=</span><span class="dv">13</span>)</span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a>m</span></code></pre></div><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></div>
</div>
<p>Run the code cell by selecting it and pressing the <em>Run</em> button, or press <em>CTRL + Enter</em> or <em>Shift + Enter</em>. You’ll see a map visualized below your code, similar to the one below. Try to drag the map to play around with it.</p>
<p><img src="images/WUR_Basic_Folium_Map.png" alt="Wageningen University Basic Folium map" width="100%"></p>
</section>
</section>
<section id="using-git-source-control-in-vs-code" class="level3">
<h3 class="anchored" data-anchor-id="using-git-source-control-in-vs-code">Using Git source control in VS Code</h3>
<p>You’ve already learned how to use Git in the terminal from previous courses. In this section, we’ll show you how to use Git directly within <strong>Visual Studio Code (VSCode)</strong>.</p>
<p>There are two main ways to work with Git in VSCode:</p>
<ol type="1">
<li><strong>Use the integrated terminal</strong>, just like you did in earlier exercises.<br>
</li>
<li><strong>Use VSCode’s built-in Git interface</strong>, which provides a visual way to interact with Git.</li>
</ol>
<p>In this tutorial, we will focus more on option 2, as you’re already familiar with the command-line approach.</p>
<p>Click on the <strong>Source Control</strong> icon (it looks like a branch) in the left sidebar, or press <code>Ctrl + Shift + G</code> to open the Git panel in VSCode.</p>
<p>This interface is especially helpful for beginners who prefer visual feedback or want to avoid typing commands manually — though keep in mind that it may be less efficient than using the terminal.</p>
<section id="start-from-a-git-repository" class="level4">
<h4 class="anchored" data-anchor-id="start-from-a-git-repository">Start from a Git Repository</h4>
<p>The initial state of the <strong>Source Control</strong> panel depends on whether you’ve opened a folder and whether that folder is already a Git repository:</p>
<ul>
<li>If <strong>no folder is opened</strong>, you’ll see options to:
<ul>
<li><strong>Open Folder</strong> (from your local machine)</li>
<li><strong>Clone Repository</strong> (from GitHub or other remotes)</li>
</ul></li>
<li>If a <strong>folder is opened but not initialized as a Git repository</strong>, you’ll see:
<ul>
<li><strong>Initialize Repository</strong></li>
<li><strong>Publish to GitHub</strong></li>
</ul></li>
<li>If you’ve opened a <strong>folder that is already a Git repository</strong>, the panel will show:
<ul>
<li>A blue <strong>Commit</strong> input box on top</li>
<li>A <code>Changes</code> section listing modified or new files</li>
<li>A <code>GRAPH</code> section showing the Git commit history in visual form</li>
</ul></li>
</ul>
<p><img src="images/vscode_git/git_vscode_1.png" alt="Source Control panel" width="100%"></p>
</section>
<section id="git-status-view-modified-files" class="level4">
<h4 class="anchored" data-anchor-id="git-status-view-modified-files"><code>git status</code> – View modified files</h4>
<p>Under the <code>Changes</code> section, you’ll see all modified, untracked, or staged files. Each file has a status label:</p>
<ul>
<li><code>U</code> – Untracked<br>
</li>
<li><code>M</code> – Modified<br>
</li>
<li><code>A</code> – Added (staged)</li>
</ul>
<p>You can click on any file to view the diff — i.e., what lines have been changed — in a side-by-side comparison.</p>
<p><img src="images/vscode_git/git_vscode_2.png" alt="Source Control panel, files status" width="100%"></p>
</section>
<section id="git-add-git-reset-stage-or-unstage-files" class="level4">
<h4 class="anchored" data-anchor-id="git-add-git-reset-stage-or-unstage-files"><code>git add</code> / <code>git reset</code> – stage or unstage Files</h4>
<p>To <strong>stage</strong> a file (equivalent to <code>git add</code>), hover over it and click the <strong><code>+</code></strong> icon.</p>
<p>To <strong>unstage</strong> a file (equivalent to <code>git reset HEAD</code>), hover over it again (now in the <strong>Staged Changes</strong> area) and click the <strong><code>-</code></strong> icon.</p>
<p>This allows you to control which files you want to include in your next commit.</p>
</section>
<section id="git-commit-commit-your-changes" class="level4">
<h4 class="anchored" data-anchor-id="git-commit-commit-your-changes"><code>git commit</code> – Commit your changes</h4>
<p>Once you’ve staged the desired files, you can commit them:</p>
<ol type="1">
<li>Enter a short commit message in the blue bar at the top.</li>
<li>Click the <strong>✓ (checkmark)</strong> icon to commit.</li>
</ol>
<p>VSCode may open a <code>COMMIT_EDITMSG</code> tab for a longer message if needed. You could also fill in the commit message above the commit blue bar. After committing, your changes will appear as a new node in the <code>GRAPH</code> panel, showing a visual update to the repository’s commit history.</p>
<p><img src="images/vscode_git/git_vscode_3.png" alt="Source Control panel, commit message" width="100%"></p>
</section>
<section id="git-push-push-local-commits-to-remote" class="level4">
<h4 class="anchored" data-anchor-id="git-push-push-local-commits-to-remote"><code>git push</code> – push local commits to remote</h4>
<p>To <strong>push</strong> your local commits to a remote repository (like GitHub), click the <code>...</code> (More Actions) menu in the top-right of the Source Control panel, and then select <strong>Push</strong>.</p>
<p><img src="images/vscode_git/git_vscode_5.png" alt="Source Control panel, git pull" width="100%"></p>
<p>Once done, your changes will be reflected in the remote repository.</p>
<p><img src="images/vscode_git/git_vscode_4.png" alt="Source Control panel, new push shown in GRAPH" width="100%"></p>
</section>
<section id="git-pull-download-and-merge-remote-changes" class="level4">
<h4 class="anchored" data-anchor-id="git-pull-download-and-merge-remote-changes"><code>git pull</code> – download and Merge Remote Changes</h4>
<p>To update your local repository with any changes from the remote, open the <code>...</code> menu in the Source Control panel and select <strong>Pull</strong>.</p>
<p>In this section, we demonstrate how VS Code handles <em>artificially created conflicts</em> (i.e., when the local and remote branches diverge). You don’t need to follow along step-by-step — just observe how it works in the interface. In <code>GRAPH</code>, the divergent branches will be shown quite intuitively:</p>
<p><img src="images/vscode_git/git_vscode_7_merge.png" alt="Source Control panel, divergent branches" width="100%"></p>
<p>If someone else (or you, on another machine) has pushed changes to the remote, pulling will fetch those changes and attempt to merge them into your current branch. However, if your local branch has diverged from the remote, Git requires a strategy to reconcile them — either by <strong>merging</strong> or <strong>rebasing</strong>. Unlike the terminal, <strong>VS Code does not prompt you explicitly</strong> when this happens. Instead, the pull will fail until you configure your preferred reconciliation strategy. You can set this using the terminal inside VS Code <code>git config --global pull.rebase false</code>. After configuring, subsequent pulls will proceed smoothly.</p>
<p>VS Code provides a <strong>3-way merge editor</strong> to help resolve them visually. Files with conflicts will show a <strong>Resolve in Merge Editor</strong> button at the bottom right — click it to open the editor.</p>
<p><img src="images/vscode_git/git_vscode_8_merge.editor.png" alt="Source Control panel, conflicts in two branches" width="100%"></p>
<p>The 3-way merge editor displays:</p>
<ul>
<li>Incoming changes (from remote, left side)</li>
<li>Current changes (your local edits, right side)</li>
<li>Result (the merged version, bottom)</li>
</ul>
<p>You can click buttons above each section to choose whether to accept incoming, current, or both changes.</p>
<p><img src="images/vscode_git/git_vscode_9_merge.editor2.png" alt="Source Control panel, 3 way merge editor" width="100%"></p>
<p>After resolving all conflicts and completing the merge, you’ll see the branches merged back together in the <code>GRAPH</code> panel:</p>
<p><img src="images/vscode_git/git_vscode_10_one.branch.again.png" alt="Source Control panel, merged into one branch" width="100%"></p>
</section>
<section id="more" class="level4">
<h4 class="anchored" data-anchor-id="more">More!</h4>
<p>The Git operations we covered here are just the basics. VS Code offers many more features through its Source Control panel — from viewing diffs, to switching branches, to managing stashes.</p>
<p>To go further, check out the <a href="https://code.visualstudio.com/docs/sourcecontrol/overview#_source-control-graph">tutorial</a> on using Source Control panel.</p>
</section>
</section>
<section id="extra-material" class="level3">
<h3 class="anchored" data-anchor-id="extra-material">Extra material</h3>
<p>The functionality we showed now only touch a very small tip of the iceberg of all that VSCode has to offer, but it is enough to follow the course and start writing some python code. If you want to explore more, below are some resources to get you started. It is easy to complicate the IDE a lot, it is recommended to start with some basics and only start adding more when you are comfortable with the basics.</p>
<ul>
<li><a href="https://code.visualstudio.com/docs/python/python-tutorial">Official VSCode documentation</a></li>
<li><a href="https://code.visualstudio.com/shortcuts/keyboard-shortcuts-linux.pdf">Cheat sheet with keyboard shortcuts</a></li>
<li><a href="https://www.youtube.com/watch?v=lwN4-W1WR84">A cool interactive python feature</a></li>
</ul>
</section>
</section>
<section id="different-ways-to-run-notebooks" class="level2">
<h2 class="anchored" data-anchor-id="different-ways-to-run-notebooks">Different ways to run notebooks</h2>
<p>We have seen how we can use notebooks in the REPL, but there are different ways and this is the power of notebooks. Originally, notebooks were introduced by Jupyter.</p>
<section id="jupyter-notebook" class="level3">
<h3 class="anchored" data-anchor-id="jupyter-notebook">Jupyter Notebook</h3>
<p>Jupyter Notebook is actually not a IDE but it is very useful for writing code. Jupyter stands for the languages that once can use (<em>JU</em>lia, <em>PY</em>thon and <em>R</em>) and notebooks means that they are actually files instead of an IDE (such as Rstudio or Spyder). The notebooks can be interpreted and run by varying interpreters of which we will cover two later on. Jupyter Notebook integrates code and visualization, and are therefore very helpful for demonstration purposes and to be run by online interpreters (such as Google Colab). First we will show how to run Jupyter Notebook locally. To do this install <code>jupyter</code> and the module <code>folium</code> in an existing or new environment that includes Python. To start Jupyter type in the terminal:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb19"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a><span class="ex">jupyter</span> notebook</span></code></pre></div><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></div>
</div>
<p>Jupyter should pop up in your browser. Note that although jupyter is opened in your browser, internet is not used, the code is interpreted and run locally. You will see a menu with all files in your working directory. The Jupyter Notebook will only see files that are accessible from the working directory in which you launched the notebook!</p>
<p>Make a new folder: <em>New</em> → <em>Folder</em>, rename the folder (check the box next to the new ‘Untitled Folder’ and click <strong>‘Rename’</strong> in the top) and, in this folder, create a new Python3 Jupyter Notebook <em>New</em> → <em>Python 3</em>. Give your notebook a name by clicking on <em>untitled</em>. Note that this creates a file with the extension <em>.ipynb</em>, short for ‘Interactive Python Notebook’, which is the file format of Jupyter Notebook.</p>
<p>Feel free to have a go at the user interface tour (<em>Help</em> → <em>User Interface Tour</em>), or hover over the toolbar to check out the tools. The main tools are:</p>
<ul>
<li><em>Save and checkpoint</em></li>
<li><em>Insert cell below</em></li>
<li><em>Run</em></li>
<li><em>Code/Markdown/Heading</em> (List box)</li>
</ul>
</section>
<section id="google-colab" class="level3">
<h3 class="anchored" data-anchor-id="google-colab">Google Colab</h3>
<p>As said before, Jupyter is locally opened in your browser. It does not connect to the internet, but it does show the possibilities, one could create something online that can run your notebooks for you on the cloud. This is exactly what Google does with Google Colab. Google Colab is a cloud service that allows you to run your Jupyter notebooks on the Google cloud for free. Let’s see what this looks like:</p>
<ul>
<li>Go to https://colab.research.google.com/notebooks/empty.ipynb (note the similaritie and differences between Jupyter locally and on Google Colab);</li>
<li>Type <code>!pip install folium</code> and press ctrl+enter to run and install folium;</li>
<li>In a new cell run the same python code as locally to create and show a new folium map.</li>
</ul>
<p>For this course we will rarely use Jupyter Notebook and or Google Colab, but it is good to know they exist. Especially Google Colab is being used more and more in the scientific community and you are likely to come across these during other courses.</p>
</section>
<section id="spyder" class="level3">
<h3 class="anchored" data-anchor-id="spyder">Spyder</h3>
<p>Spyder is a IDE for developing python mainly for scientific purposes. Fun fact, it is <a href="https://github.com/spyder-ide/spyder">completely written in python</a>! Spyder is a very complete IDE that looks a bit like Rstudio. It shows the variables present in the current session, it has a code editor, a console and a figures pane in the main view.</p>
<p>The <a href="https://docs.spyder-ide.org/">Spyder IDE</a> can be started in a terminal when the <em>Spyder</em> package is installed in the active conda environment. So, using <em>Mamba</em>, make an environment and install Spyder to that environment. Activate the environment. Spyder will automatically make use of the Python interpreter of the active conda environment. To start Spyder:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb20"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="ex">spyder</span></span></code></pre></div><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></div>
</div>
<p>In Spyder you should see an editor, a file explorer and a console. Have a look at the toolbar. Some important shortcuts are:</p>
<ul>
<li>F5 to run your script</li>
<li>CTRL + S to save your script</li>
<li>CTRL + 1 to comment/uncomment your code</li>
<li>TAB to indent your code</li>
<li>SHIFT + TAB to unindent your code</li>
</ul>
<p>Open a new file and save it somewhere as <code>main.py</code> (File – > New File –> Save As). Test writing a few lines of code and running the script.</p>
</section>
</section>
</section>
<section id="putting-it-to-the-test" class="level1">
<h1>Putting it to the test</h1>
<section id="setting-up-the-environment" class="level2">
<h2 class="anchored" data-anchor-id="setting-up-the-environment">Setting up the environment</h2>
<p>Now that we know how to set up an environment and run code, lets use this new knowledge and run some Python code. Again, during this course advise you to code in VSCode, as this IDE is the recommended IDE for the Python part of this course.</p>
<p>Create a directory structure for this tutorial using the terminal:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb21"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a><span class="bu">cd</span> ~/Documents/</span>
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a><span class="fu">mkdir</span> PythonRefresher <span class="co">#or give the directory a name to your liking</span></span>
<span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a><span class="bu">cd</span> ./PythonRefresher</span>
<span id="cb21-4"><a href="#cb21-4" aria-hidden="true" tabindex="-1"></a><span class="fu">mkdir</span> output</span></code></pre></div><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></div>
</div>
<p>And open it with VSCode by clicking <em>File</em> and <em>Open Folder</em>.</p>
<p>We only made a directory for output, because no input data or separate scripts are created in this tutorial. Next, we will create a conda environment from a file. First create a text file, (re)name it (to) <code>refresher.yaml</code>, and copy the following content into the file:</p>
<pre><code>name: refresher
dependencies:
- python
- numpy
- matplotlib
- geopandas
- spyder</code></pre>
<p>Now, create a new conda environment based on this file. You can do this in a ubuntu terminal, or a terminal in VSCode. To open the terminal in VSCode press <code>Ctrl</code> + <code>shift</code> + <code>P</code> and type terminal and select <em>Create New Terminal (With Profile)</em></p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb23"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true" tabindex="-1"></a><span class="ex">mamba</span> env create <span class="at">--file</span> refresher.yaml</span></code></pre></div><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></div>
</div>
<p>Once everything is installed, associate the refresher environment to this project. The easiest way is press <code>Ctrl</code> + <code>shift</code> + <code>P</code> and type <em>Python: select interpreter</em>.</p>
<p>Create a new Python script and save it.</p>
<p>Important to note: for compatibility, it is best to install packages from the same channel as much as possible. Given that packages in the file <code>refresher.yaml</code> are installed from the <code>conda-forge</code> channel, it is wise to use this same channel when you want to install additional packages in your environment.</p>
</section>
<section id="quick-refresher" class="level2">
<h2 class="anchored" data-anchor-id="quick-refresher">Quick refresher</h2>
<p>In the tutorial about R and Python we have gone over the differences and similarities of python and R. This tutorial also contains some basic python syntax, in this tutorial we assume you know this content, but we will go over a few basics here as well. The examples below are mostly meant for reference purposes, we assume you understand most of this refresher already.</p>
<section id="printing-and-basic-data-types" class="level3">
<h3 class="anchored" data-anchor-id="printing-and-basic-data-types">Printing and basic data types</h3>
<p>In Python we assign variable using the equals sign (<code>=</code>):</p>
<p>Printing in Python is done using the <code>print</code> function. We can print variables directly:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb24"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Integer</span></span>
<span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a>age <span class="op">=</span> <span class="dv">25</span></span>
<span id="cb24-3"><a href="#cb24-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-4"><a href="#cb24-4" aria-hidden="true" tabindex="-1"></a><span class="co"># Float</span></span>
<span id="cb24-5"><a href="#cb24-5" aria-hidden="true" tabindex="-1"></a>height <span class="op">=</span> <span class="fl">1.75</span></span>
<span id="cb24-6"><a href="#cb24-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-7"><a href="#cb24-7" aria-hidden="true" tabindex="-1"></a><span class="co"># String</span></span>
<span id="cb24-8"><a href="#cb24-8" aria-hidden="true" tabindex="-1"></a>name <span class="op">=</span> <span class="st">"John Doe"</span></span>
<span id="cb24-9"><a href="#cb24-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-10"><a href="#cb24-10" aria-hidden="true" tabindex="-1"></a><span class="co"># Boolean</span></span>
<span id="cb24-11"><a href="#cb24-11" aria-hidden="true" tabindex="-1"></a>is_student <span class="op">=</span> <span class="va">True</span></span>
<span id="cb24-12"><a href="#cb24-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-13"><a href="#cb24-13" aria-hidden="true" tabindex="-1"></a><span class="co"># Print a name</span></span>
<span id="cb24-14"><a href="#cb24-14" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(name)</span></code></pre></div><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></div>
</div>
<p>We can use string formatting to use flexible strings, for example for printing. to start a formatted string, we put a <code>f</code> before the string. We can use curly brackets <code>{}</code> in this formatted string. The text between these curly brackets is executed as regular Python code.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb25"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a><span class="co"># String formatting and printing </span></span>
<span id="cb25-2"><a href="#cb25-2" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="ss">f'</span><span class="sc">{</span>name<span class="sc">}</span><span class="ss"> is </span><span class="sc">{</span>age<span class="sc">}</span><span class="ss"> years old and is </span><span class="sc">{</span>height<span class="sc">}</span><span class="ss"> meters tall.'</span>)</span></code></pre></div><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></div>
</div>
</section>
<section id="basic-arithmetic-operations" class="level3">
<h3 class="anchored" data-anchor-id="basic-arithmetic-operations">Basic arithmetic operations:</h3>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb26"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a>a <span class="op">=</span> <span class="dv">10</span></span>
<span id="cb26-2"><a href="#cb26-2" aria-hidden="true" tabindex="-1"></a>b <span class="op">=</span> <span class="dv">5</span></span>
<span id="cb26-3"><a href="#cb26-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-4"><a href="#cb26-4" aria-hidden="true" tabindex="-1"></a>addition <span class="op">=</span> a <span class="op">+</span> b</span>
<span id="cb26-5"><a href="#cb26-5" aria-hidden="true" tabindex="-1"></a>subtraction <span class="op">=</span> a <span class="op">-</span> b</span>
<span id="cb26-6"><a href="#cb26-6" aria-hidden="true" tabindex="-1"></a>multiplication <span class="op">=</span> a <span class="op">*</span> b</span>
<span id="cb26-7"><a href="#cb26-7" aria-hidden="true" tabindex="-1"></a>division <span class="op">=</span> a <span class="op">/</span> b</span>
<span id="cb26-8"><a href="#cb26-8" aria-hidden="true" tabindex="-1"></a>modulo <span class="op">=</span> a <span class="op">%</span> b</span>
<span id="cb26-9"><a href="#cb26-9" aria-hidden="true" tabindex="-1"></a>exponentiation <span class="op">=</span> a <span class="op">**</span> b</span>
<span id="cb26-10"><a href="#cb26-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-11"><a href="#cb26-11" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(addition, subtraction, multiplication, division, modulo, exponentiation)</span></code></pre></div><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></div>
</div>
</section>
<section id="conditional-statements" class="level3">
<h3 class="anchored" data-anchor-id="conditional-statements">Conditional statements</h3>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb27"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a>x <span class="op">=</span> <span class="dv">15</span></span>
<span id="cb27-2"><a href="#cb27-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb27-3"><a href="#cb27-3" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> x <span class="op">></span> <span class="dv">10</span>:</span>
<span id="cb27-4"><a href="#cb27-4" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"x is greater than 10"</span>)</span>
<span id="cb27-5"><a href="#cb27-5" aria-hidden="true" tabindex="-1"></a><span class="cf">elif</span> x <span class="op">==</span> <span class="dv">10</span>:</span>
<span id="cb27-6"><a href="#cb27-6" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"x is equal to 10"</span>)</span>
<span id="cb27-7"><a href="#cb27-7" aria-hidden="true" tabindex="-1"></a><span class="cf">else</span>:</span>
<span id="cb27-8"><a href="#cb27-8" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"x is less than 10"</span>)</span></code></pre></div><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></div>
</div>
</section>
<section id="loops-for-and-while" class="level3">
<h3 class="anchored" data-anchor-id="loops-for-and-while">Loops (for and while)</h3>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb28"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb28-1"><a href="#cb28-1" aria-hidden="true" tabindex="-1"></a><span class="co"># For loop</span></span>
<span id="cb28-2"><a href="#cb28-2" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> i <span class="kw">in</span> <span class="bu">range</span>(<span class="dv">5</span>):</span>
<span id="cb28-3"><a href="#cb28-3" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(i)</span>
<span id="cb28-4"><a href="#cb28-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb28-5"><a href="#cb28-5" aria-hidden="true" tabindex="-1"></a><span class="co"># While loop</span></span>
<span id="cb28-6"><a href="#cb28-6" aria-hidden="true" tabindex="-1"></a>count <span class="op">=</span> <span class="dv">0</span></span>
<span id="cb28-7"><a href="#cb28-7" aria-hidden="true" tabindex="-1"></a><span class="cf">while</span> count <span class="op"><</span> <span class="dv">5</span>:</span>
<span id="cb28-8"><a href="#cb28-8" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(count)</span>
<span id="cb28-9"><a href="#cb28-9" aria-hidden="true" tabindex="-1"></a> count <span class="op">+=</span> <span class="dv">1</span></span></code></pre></div><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></div>
</div>
</section>
<section id="lists-and-basic-list-operations" class="level3">
<h3 class="anchored" data-anchor-id="lists-and-basic-list-operations">Lists and basic list operations</h3>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb29"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb29-1"><a href="#cb29-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Creating a list</span></span>
<span id="cb29-2"><a href="#cb29-2" aria-hidden="true" tabindex="-1"></a>fruits <span class="op">=</span> [<span class="st">"apple"</span>, <span class="st">"banana"</span>, <span class="st">"orange"</span>]</span>
<span id="cb29-3"><a href="#cb29-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb29-4"><a href="#cb29-4" aria-hidden="true" tabindex="-1"></a><span class="co"># Accessing elements</span></span>
<span id="cb29-5"><a href="#cb29-5" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(fruits[<span class="dv">0</span>]) <span class="co"># Output: "apple"</span></span>
<span id="cb29-6"><a href="#cb29-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb29-7"><a href="#cb29-7" aria-hidden="true" tabindex="-1"></a><span class="co"># Adding elements</span></span>
<span id="cb29-8"><a href="#cb29-8" aria-hidden="true" tabindex="-1"></a>fruits.append(<span class="st">"grape"</span>)</span>
<span id="cb29-9"><a href="#cb29-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb29-10"><a href="#cb29-10" aria-hidden="true" tabindex="-1"></a><span class="co"># Removing elements</span></span>
<span id="cb29-11"><a href="#cb29-11" aria-hidden="true" tabindex="-1"></a>fruits.remove(<span class="st">"banana"</span>)</span>
<span id="cb29-12"><a href="#cb29-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb29-13"><a href="#cb29-13" aria-hidden="true" tabindex="-1"></a><span class="co"># Length of the list</span></span>
<span id="cb29-14"><a href="#cb29-14" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="bu">len</span>(fruits)) <span class="co"># Output: 3</span></span></code></pre></div><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></div>
</div>
</section>
<section id="functions" class="level3">
<h3 class="anchored" data-anchor-id="functions">Functions</h3>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb30"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb30-1"><a href="#cb30-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Function to add two numbers and return the result</span></span>
<span id="cb30-2"><a href="#cb30-2" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> add_numbers(a, b):</span>
<span id="cb30-3"><a href="#cb30-3" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> a <span class="op">+</span> b</span>
<span id="cb30-4"><a href="#cb30-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb30-5"><a href="#cb30-5" aria-hidden="true" tabindex="-1"></a>result <span class="op">=</span> add_numbers(<span class="dv">5</span>, <span class="dv">3</span>)</span>
<span id="cb30-6"><a href="#cb30-6" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(result) <span class="co"># Output: 8</span></span></code></pre></div><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></div>
</div>
<p>Functions can be used to automate tedious tasks that you do often. Some examples would be creating directories if they don’t exist, or downloading and unzipping files. For example:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb31"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb31-1"><a href="#cb31-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> os</span>
<span id="cb31-2"><a href="#cb31-2" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> make_directory(directory_name):</span>
<span id="cb31-3"><a href="#cb31-3" aria-hidden="true" tabindex="-1"></a> <span class="co"># Check if directory already exists</span></span>
<span id="cb31-4"><a href="#cb31-4" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="kw">not</span> os.path.exists(directory_name):</span>
<span id="cb31-5"><a href="#cb31-5" aria-hidden="true" tabindex="-1"></a> os.mkdir(directory_name)</span></code></pre></div><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></div>
</div>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb32"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb32-1"><a href="#cb32-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> requests</span>
<span id="cb32-2"><a href="#cb32-2" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> zipfile</span>
<span id="cb32-3"><a href="#cb32-3" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> os</span>
<span id="cb32-4"><a href="#cb32-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb32-5"><a href="#cb32-5" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> download_and_unzip(url: <span class="bu">str</span>, extract_to: <span class="bu">str</span> <span class="op">=</span> <span class="st">"."</span>):</span>
<span id="cb32-6"><a href="#cb32-6" aria-hidden="true" tabindex="-1"></a> <span class="co">"""</span></span>
<span id="cb32-7"><a href="#cb32-7" aria-hidden="true" tabindex="-1"></a><span class="co"> Downloads a ZIP file from a URL and extracts it.</span></span>
<span id="cb32-8"><a href="#cb32-8" aria-hidden="true" tabindex="-1"></a><span class="co"> This function was written by ChatGPT and edited and checked for correctness by Arno Timmer</span></span>
<span id="cb32-9"><a href="#cb32-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb32-10"><a href="#cb32-10" aria-hidden="true" tabindex="-1"></a><span class="co"> Args:</span></span>
<span id="cb32-11"><a href="#cb32-11" aria-hidden="true" tabindex="-1"></a><span class="co"> url (str): The URL to the ZIP file.</span></span>
<span id="cb32-12"><a href="#cb32-12" aria-hidden="true" tabindex="-1"></a><span class="co"> extract_to (str): Directory where the files will be extracted.</span></span>
<span id="cb32-13"><a href="#cb32-13" aria-hidden="true" tabindex="-1"></a><span class="co"> """</span></span>
<span id="cb32-14"><a href="#cb32-14" aria-hidden="true" tabindex="-1"></a> <span class="co"># Get filename from URL</span></span>
<span id="cb32-15"><a href="#cb32-15" aria-hidden="true" tabindex="-1"></a> local_zip_path <span class="op">=</span> os.path.join(extract_to, url.split(<span class="st">"/"</span>)[<span class="op">-</span><span class="dv">1</span>])</span>
<span id="cb32-16"><a href="#cb32-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb32-17"><a href="#cb32-17" aria-hidden="true" tabindex="-1"></a> <span class="co"># Download the file</span></span>
<span id="cb32-18"><a href="#cb32-18" aria-hidden="true" tabindex="-1"></a> response <span class="op">=</span> requests.get(url)</span>
<span id="cb32-19"><a href="#cb32-19" aria-hidden="true" tabindex="-1"></a> response.raise_for_status()</span>
<span id="cb32-20"><a href="#cb32-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb32-21"><a href="#cb32-21" aria-hidden="true" tabindex="-1"></a> <span class="cf">with</span> <span class="bu">open</span>(local_zip_path, <span class="st">"wb"</span>) <span class="im">as</span> f:</span>
<span id="cb32-22"><a href="#cb32-22" aria-hidden="true" tabindex="-1"></a> f.write(response.content)</span>
<span id="cb32-23"><a href="#cb32-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb32-24"><a href="#cb32-24" aria-hidden="true" tabindex="-1"></a> <span class="co"># Extract the zip file</span></span>
<span id="cb32-25"><a href="#cb32-25" aria-hidden="true" tabindex="-1"></a> <span class="cf">with</span> zipfile.ZipFile(local_zip_path, <span class="st">"r"</span>) <span class="im">as</span> zip_ref:</span>
<span id="cb32-26"><a href="#cb32-26" aria-hidden="true" tabindex="-1"></a> zip_ref.extractall(extract_to)</span>
<span id="cb32-27"><a href="#cb32-27" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb32-28"><a href="#cb32-28" aria-hidden="true" tabindex="-1"></a> <span class="co"># remove the zip file</span></span>
<span id="cb32-29"><a href="#cb32-29" aria-hidden="true" tabindex="-1"></a> os.remove(local_zip_path)</span></code></pre></div><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></div>
</div>
<p>As you can see functions don’t need to return something, but can also return multiple things. If they do, be careful to also store the returned values in multiple variables! If not, they are stored as a tuple.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb33"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb33-1"><a href="#cb33-1" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> multiply_value(a):</span>
<span id="cb33-2"><a href="#cb33-2" aria-hidden="true" tabindex="-1"></a> <span class="co">''' </span></span>
<span id="cb33-3"><a href="#cb33-3" aria-hidden="true" tabindex="-1"></a><span class="co"> This function multiplies value a with 100 and with 1000. It returns both the results.</span></span>
<span id="cb33-4"><a href="#cb33-4" aria-hidden="true" tabindex="-1"></a><span class="co"> '''</span></span>
<span id="cb33-5"><a href="#cb33-5" aria-hidden="true" tabindex="-1"></a> hundredfold <span class="op">=</span> <span class="dv">100</span> <span class="op">*</span> a </span>
<span id="cb33-6"><a href="#cb33-6" aria-hidden="true" tabindex="-1"></a> thousandfold <span class="op">=</span> <span class="dv">1000</span> <span class="op">*</span> a</span>
<span id="cb33-7"><a href="#cb33-7" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> hundredfold, thousandfold</span>
<span id="cb33-8"><a href="#cb33-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb33-9"><a href="#cb33-9" aria-hidden="true" tabindex="-1"></a><span class="co"># When called like this both values are stored as a tuple</span></span>
<span id="cb33-10"><a href="#cb33-10" aria-hidden="true" tabindex="-1"></a>results <span class="op">=</span> multiply_value(<span class="dv">5</span>)</span>
<span id="cb33-11"><a href="#cb33-11" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="bu">type</span>(results))</span>
<span id="cb33-12"><a href="#cb33-12" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="ss">f'We calculated the hundredfold of a number: </span><span class="sc">{</span>results[<span class="dv">0</span>]<span class="sc">}</span><span class="ss"> and the thousandfold: </span><span class="sc">{</span>results[<span class="dv">1</span>]<span class="sc">}</span><span class="ss">'</span> )</span>
<span id="cb33-13"><a href="#cb33-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb33-14"><a href="#cb33-14" aria-hidden="true" tabindex="-1"></a><span class="co"># But we can also call it like this:</span></span>
<span id="cb33-15"><a href="#cb33-15" aria-hidden="true" tabindex="-1"></a>hundreds, thousands <span class="op">=</span> multiply_value(<span class="dv">10</span>)</span>
<span id="cb33-16"><a href="#cb33-16" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="ss">f'We calculated the hundredfold of a number: </span><span class="sc">{</span>hundreds<span class="sc">}</span><span class="ss"> and the thousandfold: </span><span class="sc">{</span>thousands<span class="sc">}</span><span class="ss">'</span> )</span></code></pre></div><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></div>
</div>
</section>
<section id="dictionaries" class="level3">
<h3 class="anchored" data-anchor-id="dictionaries">Dictionaries</h3>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb34"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb34-1"><a href="#cb34-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Creating a dictionary</span></span>
<span id="cb34-2"><a href="#cb34-2" aria-hidden="true" tabindex="-1"></a>person <span class="op">=</span> {</span>
<span id="cb34-3"><a href="#cb34-3" aria-hidden="true" tabindex="-1"></a> <span class="st">"name"</span>: <span class="st">"Alice"</span>,</span>
<span id="cb34-4"><a href="#cb34-4" aria-hidden="true" tabindex="-1"></a> <span class="st">"age"</span>: <span class="dv">30</span>,</span>
<span id="cb34-5"><a href="#cb34-5" aria-hidden="true" tabindex="-1"></a> <span class="st">"is_student"</span>: FALSE</span>
<span id="cb34-6"><a href="#cb34-6" aria-hidden="true" tabindex="-1"></a>}</span>
<span id="cb34-7"><a href="#cb34-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb34-8"><a href="#cb34-8" aria-hidden="true" tabindex="-1"></a><span class="co"># Accessing values</span></span>
<span id="cb34-9"><a href="#cb34-9" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(person[<span class="st">"name"</span>]) <span class="co"># Output: "Alice"</span></span>
<span id="cb34-10"><a href="#cb34-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb34-11"><a href="#cb34-11" aria-hidden="true" tabindex="-1"></a><span class="co"># Adding a new key-value pair</span></span>
<span id="cb34-12"><a href="#cb34-12" aria-hidden="true" tabindex="-1"></a>person[<span class="st">"occupation"</span>] <span class="op">=</span> <span class="st">"Engineer"</span></span>
<span id="cb34-13"><a href="#cb34-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb34-14"><a href="#cb34-14" aria-hidden="true" tabindex="-1"></a><span class="co"># Removing a key-value pair</span></span>
<span id="cb34-15"><a href="#cb34-15" aria-hidden="true" tabindex="-1"></a><span class="kw">del</span> person[<span class="st">"is_student"</span>]</span></code></pre></div><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></div>
</div>
</section>
<section id="importing-packages" class="level3">
<h3 class="anchored" data-anchor-id="importing-packages">Importing packages</h3>
<p>Python is used by a very large community, as is said before. One of the reasons for this is that this entire community builds a lot of (open source) packages. It is therefor very useful to be able to build upon these packages. In R you have worked a with <em>dataframes</em> and <em>spatial dataframes</em>. In Python these are not standard datatypes, but they are implemented in very well known packages called <code>Pandas</code> and its spatial counterpart <code>GeoPandas.</code> We will go in much more detail during the Python-Vector tutorial but we will introduce them quickly here.</p>
<p>In Python we import a package using the <code>import</code> statement (instead of th the <code>library</code> function in R) . For example importing the pandas package goes as follows:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb35"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb35-1"><a href="#cb35-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> pandas <span class="im">as</span> pd</span></code></pre></div><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></div>
</div>
<p>As you can see we can import a package <em>as</em> something. We use this if we want to point at specific functionality of this package. If we want to point at for example the <code>read_csv</code> function from pandas we we call <code>pd.read_csv</code>. This function is also implemented in other packages, but now we are sure we use the pandas version of this function. Importing pandas is a convention, used very widely in the python community.</p>
<p>We can create a <code>dataframe</code> as follows:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb36"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb36-1"><a href="#cb36-1" aria-hidden="true" tabindex="-1"></a>data <span class="op">=</span> {</span>
<span id="cb36-2"><a href="#cb36-2" aria-hidden="true" tabindex="-1"></a> <span class="st">'Name'</span>: [<span class="st">'Alice'</span>, <span class="st">'Bob'</span>, <span class="st">'Charlie'</span>],</span>
<span id="cb36-3"><a href="#cb36-3" aria-hidden="true" tabindex="-1"></a> <span class="st">'Age'</span>: [<span class="dv">25</span>, <span class="dv">30</span>, <span class="dv">22</span>],</span>
<span id="cb36-4"><a href="#cb36-4" aria-hidden="true" tabindex="-1"></a> <span class="st">'City'</span>: [<span class="st">'New York'</span>, <span class="st">'San Francisco'</span>, <span class="st">'Chicago'</span>]</span>
<span id="cb36-5"><a href="#cb36-5" aria-hidden="true" tabindex="-1"></a>}</span>
<span id="cb36-6"><a href="#cb36-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb36-7"><a href="#cb36-7" aria-hidden="true" tabindex="-1"></a>df <span class="op">=</span> pd.DataFrame(data)</span>
<span id="cb36-8"><a href="#cb36-8" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(df)</span></code></pre></div><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></div>
</div>
<p>We can access some information from this <code>dataframe</code> as follows:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb37"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb37-1"><a href="#cb37-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Display the first few rows of the DataFrame</span></span>
<span id="cb37-2"><a href="#cb37-2" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(df.head())</span>
<span id="cb37-3"><a href="#cb37-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb37-4"><a href="#cb37-4" aria-hidden="true" tabindex="-1"></a><span class="co"># Get statistical information about the DataFrame</span></span>
<span id="cb37-5"><a href="#cb37-5" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(df.describe())</span>
<span id="cb37-6"><a href="#cb37-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb37-7"><a href="#cb37-7" aria-hidden="true" tabindex="-1"></a><span class="co"># Access a specific column</span></span>
<span id="cb37-8"><a href="#cb37-8" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(df[<span class="st">'Age'</span>])</span></code></pre></div><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></div>
</div>
</section>
<section id="geodataframe" class="level3">
<h3 class="anchored" data-anchor-id="geodataframe">GeoDataFrame</h3>
<p>The spatial counterpart of a <code>dataframe</code> is a ‘GeoDataFrame’, which we normally import <em>as</em> <code>gpd</code>:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb38"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb38-1"><a href="#cb38-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> geopandas <span class="im">as</span> gpd</span>
<span id="cb38-2"><a href="#cb38-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb38-3"><a href="#cb38-3" aria-hidden="true" tabindex="-1"></a><span class="co"># Dummy data for the GeoDataFrame</span></span>
<span id="cb38-4"><a href="#cb38-4" aria-hidden="true" tabindex="-1"></a>data <span class="op">=</span> {</span>
<span id="cb38-5"><a href="#cb38-5" aria-hidden="true" tabindex="-1"></a> <span class="st">'Name'</span>: [<span class="st">'Location A'</span>, <span class="st">'Location B'</span>, <span class="st">'Location C'</span>],</span>
<span id="cb38-6"><a href="#cb38-6" aria-hidden="true" tabindex="-1"></a> <span class="st">'Latitude'</span>: [<span class="fl">40.7128</span>, <span class="fl">34.0522</span>, <span class="fl">41.8781</span>],</span>
<span id="cb38-7"><a href="#cb38-7" aria-hidden="true" tabindex="-1"></a> <span class="st">'Longitude'</span>: [<span class="op">-</span><span class="fl">74.0060</span>, <span class="op">-</span><span class="fl">118.2437</span>, <span class="op">-</span><span class="fl">87.6298</span>]</span>
<span id="cb38-8"><a href="#cb38-8" aria-hidden="true" tabindex="-1"></a>}</span>
<span id="cb38-9"><a href="#cb38-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb38-10"><a href="#cb38-10" aria-hidden="true" tabindex="-1"></a><span class="co"># Create the GeoDataFrame with a single line of code</span></span>
<span id="cb38-11"><a href="#cb38-11" aria-hidden="true" tabindex="-1"></a>gdf <span class="op">=</span> gpd.GeoDataFrame(data, geometry<span class="op">=</span>gpd.points_from_xy(data[<span class="st">'Longitude'</span>], data[<span class="st">'Latitude'</span>]))</span>
<span id="cb38-12"><a href="#cb38-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb38-13"><a href="#cb38-13" aria-hidden="true" tabindex="-1"></a><span class="co"># Display the GeoDataFrame</span></span>
<span id="cb38-14"><a href="#cb38-14" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(gdf)</span></code></pre></div><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></div>
</div>
</section>
</section>
</section>
<section id="python-help" class="level1">
<h1>Python help</h1>
<p>There are several ways to find help with programming in Python. Searching the internet typically solves your problem the quickest, because it finds answers on multiple platforms, such as StackOverflow and GitHub. During Geoscripting we have the forum to ask and give help. Asking your friends or colleagues in person is also a great way to learn and fix programming problems. Another good option is get documentation from the package website or inside Python:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb39"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb39-1"><a href="#cb39-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> sys</span>
<span id="cb39-2"><a href="#cb39-2" aria-hidden="true" tabindex="-1"></a><span class="bu">help</span>(sys)</span></code></pre></div><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></div>
</div>
<p>See how the objects and functions in the <code>sys</code> package got listed.</p>
<div class="cell" type="alert alert-success">
<div class="alert alert-success">
<blockquote class="blockquote">
<p>
<strong>Question 4</strong>: What kind of functionality does the <code>sys</code> package provide?
</p>
</blockquote>
</div>
</div>
</section>
<section id="more-info" class="level1">
<h1>More info</h1>
<ul>
<li><a href="https://docs.Python.org/3/contents.html">Official Python tutorial</a></li>
<li><a href="https://www.python.org/dev/peps/pep-0008/">Python Style guide</a></li>
<li><a href="https://ugoproto.github.io/ugo_py_doc/py_cs/">Python 3 Cheatsheet</a></li>
<li><a href="https://www.datacamp.com/community/data-science-cheatsheets?tag=python">Overview Python package Cheatsheets</a></li>
</ul>
</section>
<section id="sources-used" class="level1">
<h1>Sources used:</h1>
<ul>
<li><a href="https://carpentries-incubator.github.io/reproducible-ml-workflows/pixi-intro.html">Carpenters introduction to pixi</a></li>
<li><a href="https://pixi.prefix.dev/latest/">pixi documentation</a></li>
</ul>
</section>
</main>
<!-- /main column -->
<script id="quarto-html-after-body" type="application/javascript">
window.document.addEventListener("DOMContentLoaded", function (event) {
const icon = "";
const anchorJS = new window.AnchorJS();
anchorJS.options = {
placement: 'right',
icon: icon
};
anchorJS.add('.anchored');
const isCodeAnnotation = (el) => {
for (const clz of el.classList) {
if (clz.startsWith('code-annotation-')) {
return true;
}
}
return false;
}
const onCopySuccess = function(e) {
// button target
const button = e.trigger;
// don't keep focus
button.blur();
// flash "checked"
button.classList.add('code-copy-button-checked');
var currentTitle = button.getAttribute("title");
button.setAttribute("title", "Copied!");
let tooltip;
if (window.bootstrap) {
button.setAttribute("data-bs-toggle", "tooltip");
button.setAttribute("data-bs-placement", "left");
button.setAttribute("data-bs-title", "Copied!");
tooltip = new bootstrap.Tooltip(button,
{ trigger: "manual",
customClass: "code-copy-button-tooltip",
offset: [0, -8]});
tooltip.show();
}
setTimeout(function() {
if (tooltip) {
tooltip.hide();
button.removeAttribute("data-bs-title");
button.removeAttribute("data-bs-toggle");
button.removeAttribute("data-bs-placement");
}
button.setAttribute("title", currentTitle);
button.classList.remove('code-copy-button-checked');
}, 1000);
// clear code selection
e.clearSelection();
}
const getTextToCopy = function(trigger) {
const outerScaffold = trigger.parentElement.cloneNode(true);
const codeEl = outerScaffold.querySelector('code');
for (const childEl of codeEl.children) {
if (isCodeAnnotation(childEl)) {
childEl.remove();
}
}
return codeEl.innerText;
}
const clipboard = new window.ClipboardJS('.code-copy-button:not([data-in-quarto-modal])', {
text: getTextToCopy
});
clipboard.on('success', onCopySuccess);
if (window.document.getElementById('quarto-embedded-source-code-modal')) {
const clipboardModal = new window.ClipboardJS('.code-copy-button[data-in-quarto-modal]', {
text: getTextToCopy,
container: window.document.getElementById('quarto-embedded-source-code-modal')
});
clipboardModal.on('success', onCopySuccess);
}
var localhostRegex = new RegExp(/^(?:http|https):\/\/localhost\:?[0-9]*\//);
var mailtoRegex = new RegExp(/^mailto:/);
var filterRegex = new RegExp('/' + window.location.host + '/');
var isInternal = (href) => {
return filterRegex.test(href) || localhostRegex.test(href) || mailtoRegex.test(href);
}
// Inspect non-navigation links and adorn them if external
var links = window.document.querySelectorAll('a[href]:not(.nav-link):not(.navbar-brand):not(.toc-action):not(.sidebar-link):not(.sidebar-item-toggle):not(.pagination-link):not(.no-external):not([aria-hidden]):not(.dropdown-item):not(.quarto-navigation-tool):not(.about-link)');
for (var i=0; i<links.length; i++) {
const link = links[i];
if (!isInternal(link.href)) {
// undo the damage that might have been done by quarto-nav.js in the case of
// links that we want to consider external
if (link.dataset.originalHref !== undefined) {
link.href = link.dataset.originalHref;
}
}
}
function tippyHover(el, contentFn, onTriggerFn, onUntriggerFn) {
const config = {
allowHTML: true,
maxWidth: 500,
delay: 100,
arrow: false,
appendTo: function(el) {
return el.parentElement;
},
interactive: true,
interactiveBorder: 10,
theme: 'quarto',
placement: 'bottom-start',
};
if (contentFn) {
config.content = contentFn;
}
if (onTriggerFn) {
config.onTrigger = onTriggerFn;
}
if (onUntriggerFn) {
config.onUntrigger = onUntriggerFn;
}
window.tippy(el, config);
}
const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]');
for (var i=0; i<noterefs.length; i++) {
const ref = noterefs[i];
tippyHover(ref, function() {
// use id or data attribute instead here
let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href');
try { href = new URL(href).hash; } catch {}
const id = href.replace(/^#\/?/, "");
const note = window.document.getElementById(id);
if (note) {
return note.innerHTML;
} else {
return "";
}
});
}
const xrefs = window.document.querySelectorAll('a.quarto-xref');
const processXRef = (id, note) => {
// Strip column container classes
const stripColumnClz = (el) => {
el.classList.remove("page-full", "page-columns");
if (el.children) {
for (const child of el.children) {
stripColumnClz(child);
}
}
}
stripColumnClz(note)
if (id === null || id.startsWith('sec-')) {
// Special case sections, only their first couple elements
const container = document.createElement("div");
if (note.children && note.children.length > 2) {
container.appendChild(note.children[0].cloneNode(true));
for (let i = 1; i < note.children.length; i++) {
const child = note.children[i];
if (child.tagName === "P" && child.innerText === "") {
continue;
} else {
container.appendChild(child.cloneNode(true));
break;
}
}
if (window.Quarto?.typesetMath) {