Modularization#

Midjourney: Modular Blocks, ref. Piet Mondrian

Write programs that do one thing and do it well.

โ€” Doug McIlroy

Slides/PDF#

Split code into files, modules, and packages#

Large programs often contain dozens of classes with hundreds of functions and many thousands of lines of code. It quickly becomes difficult to keep an overview when all classes are defined in a single file. Especially when different programmers work at different places in the program, version conflicts can arise very quickly when people work on similar files.

To keep this organized and easy to navigate, code is split into multiple files with the extension .py. It is common to have one file

  • per class, when classes are defined

  • per topic, when helper functions are defined (e.g., mathematical functions, โ€ฆ)

  • per area of responsibility, when (for example) data loading is separated from its processing. This way you can later define other processing steps and reuse the loading.

If we save each class of the geometry elements from the Class Definition section of the last lecture, we would then have, for example, a project structure corresponding to:

Each file contains only the code of the class with the same name, even if that is only a few lines, as in the case of the classes Triangle, Tetragon, and Pentagon. Crucially, when a programmer searches for the code of a class, they should be able to see exactly in which file it can be found and not have to search far.

Larger projects are split into multiple modules by creating additional subdirectories. For example, we want to group all generic classes for points in the points directory and all geometric shapes in the shapes directory. This makes it easy to structure larger projects.

The sum of all modules then forms a package. In this case the geometry package, which we can reuse in different implementations.

main() - The entry point of a program#

When code is spread across multiple files, Python needs a hint about which code should be executed. For this, you define the special entry function main().

It exists in almost all programming languages and always designates the starting point of a program.

In Python, it either takes no arguments or receives them dynamically when it is invoked by the user or by another program (a.k.a. command-line arguments).

def main():
	print("This is the main function")

However, you want to avoid the function main() from being called when the Python file is, for example, imported as a library, where youโ€™re only interested in the functions. Therefore, at the end of a file that defines a main() function you use the following conditional.

if __name__ == "__main__":
	main()
This is the main function

She takes advantage of the fact that the value of the special variable __name__ in the main file is always '__main__', whereas in an imported file it indicates the name of the main file.

Importing Modules#

To avoid constantly loading unnecessary code, Python does not load this code automatically.

So, if we want to use the code in our files, modules, and packages, we must first tell Python to load it.

This importing is done with the import command.

A simple import is importing an entire package.

This is done by writing import followed by the package name.

import geometry.points.ImmutablePoint
import geometry.shapes.Line

def main():
	point_1 = geometry.points.ImmutablePoint.ImmutablePoint(x=54.083336, y=12.108811)
	point_2 = geometry.points.ImmutablePoint.ImmutablePoint(y=12.094167, x=54.075211)
	line_1 = geometry.shapes.Line.Line(start=point_1, end=point_2)
	print(f"Die Lรคnge der Linie zwischen Punkt 1 und 2 ist: {line_1.length()}")

if __name__ == "__main__":
	main()
Die Lรคnge der Linie zwischen Punkt 1 und 2 ist: 0.016747010509340444

One drawback of importing entire packages is that if we want to reference individual classes that reside in submodules, we must specify the fully qualified class name. For example, in the example above: geometry.points.ImmutablePoint.ImmutablePoint.

Therefore, one typically imports individual modules by specifying the path to a module, for example geometry.points.ImmutablePoint.ImmutablePoint. Here, you can also assign new names to the imported modules, such as point or line, in the example below.

import geometry.points.ImmutablePoint as point
import geometry.shapes.Line as line

def main():
	point_1 = point.ImmutablePoint(x=54.083336, y=12.108811)
	point_2 = point.ImmutablePoint(y=12.094167, x=54.075211)
	line_1 = line.Line(start=point_1, end=point_2)
	print(f"Die Lรคnge der Linie zwischen Punkt 1 und 2 ist: {line_1.length()}")

if __name__ == "__main__":
	main()
Die Lรคnge der Linie zwischen Punkt 1 und 2 ist: 0.016747010509340444

Alternatively, parts of a module can also be imported using the wildcard * and the from statement. All elements are imported with the wildcard *. Specific elements, such as individual classes, can also be specified directly, as in the following example Line.

from geometry.points.ImmutablePoint import *
from geometry.shapes.Line import Line

def main():
	point_1 = ImmutablePoint(x=54.083336, y=12.108811)
	point_2 = ImmutablePoint(y=12.094167, x=54.075211)
	line_1 = Line(start=point_1, end=point_2)
	print(f"Die Lรคnge der Linie zwischen Punkt 1 und 2 ist: {line_1.length()}")

if __name__ == "__main__":
	main()
Die Lรคnge der Linie zwischen Punkt 1 und 2 ist: 0.016747010509340444

Import standard packages from Python#

Python includes many standard libraries for common tasks. For construction and environmental informatics, the following are the most useful:

packet

description

collections

More complex data types for counting, sorting

http

Functions of the HTTP protocol, such as web servers

json

Functions to store objects as text

logging

Functions to write logs

math

Mathematical functions

os

Functions to locate, load, and save files

pickle

Functions to store objects in binary form

pprint

print functions for pretty-printing objects

random

Functions for generating random numbers

re

Functions for regular expressions to search text

sys

Functions to obtain system information

time

Functions for time and date information

timeit

Functions to measure the performance of functions

traceback

Functions to display the stack trace

urllib

Functions to load and process URLs on the Internet

From the list, we have already become familiar with and used the libraries math, time, timeit, traceback, and logging. The other packages, however, offer additional useful functions.

For example, if we want to list all files in a directory, we use the os package.

import os

folder = "geometry/shapes/"
for count, filename in enumerate(os.listdir(folder)):
	if os.path.isfile(os.path.join(folder, filename)):
		path = os.path.join(folder, filename)
		print(path)
geometry/shapes/Tetragon.py
geometry/shapes/Pentagon.py
geometry/shapes/Line.py
geometry/shapes/Polygon.py
geometry/shapes/Triangle.py

Many websites offer application programming interfaces, so-called APIs, because these APIs are also used by their own websites to load data that is displayed on the page. The APIs usually use the JSON format to exchange data. This is a text-based file format that in Python closely resembles the dict data type, but it also supports all other primitive and composite data types in Python.

We would like, for example, to analyze the weather data of a weather station in Germany. We obtain these data from the German Weather Service. These data can also be downloaded from the API. For this, you need the ID (identification number) of a weather station, which can be found here. We take as an example a station in the Hansaviertel in Rostock with the ID 12495.

Then you can load the weather data with Python with the help of the urllib package from the API. The JSON format can be processed with the json package. To output this in a nicer way, we use the pprint function from the pprint package (pretty-print).

import urllib.request
import json
import pprint

stationID='12495' # Rostock-Hansaviertel
with urllib.request.urlopen(f'https://dwd.api.proxy.bund.dev/v30/stationOverviewExtended?stationIds={stationID}') as f:
    data=f.read() # This returns binary data
    weather=json.loads(data) # We convert the binary data into a dict
    pprint.pprint(weather, indent=2, compact=True)
{ '12495': { 'days': [ { 'dayDate': '2026-01-22',
                         'icon': 3,
                         'icon1': None,
                         'icon2': None,
                         'moonPhase': 0,
                         'moonrise': 1769068441000,
                         'moonriseOnThisDay': 1769068441000,
                         'moonset': 1769110057000,
                         'moonsetOnThisDay': 1769110057000,
                         'precipitation': 0,
                         'stationId': None,
                         'sunrise': 1769062879000,
                         'sunriseOnThisDay': 1769062879000,
                         'sunset': 1769094200000,
                         'sunsetOnThisDay': 1769094200000,
                         'sunshine': 32767,
                         'temperatureMax': -96,
                         'temperatureMin': -126,
                         'windDirection': 1150,
                         'windGust': 315,
                         'windSpeed': 111},
                       { 'dayDate': '2026-01-23',
                         'icon': 14,
                         'icon1': None,
                         'icon2': None,
                         'moonPhase': 1,
                         'moonrise': 1769155544000,
                         'moonriseOnThisDay': 1769155544000,
                         'moonset': 1769201206000,
                         'moonsetOnThisDay': 1769201206000,
                         'precipitation': 16,
                         'stationId': None,
                         'sunrise': 1769149209000,
                         'sunriseOnThisDay': 1769149209000,
                         'sunset': 1769180702000,
                         'sunsetOnThisDay': 1769180702000,
                         'sunshine': 0,
                         'temperatureMax': -29,
                         'temperatureMin': -87,
                         'windDirection': 950,
                         'windGust': 352,
                         'windSpeed': 111},
                       { 'dayDate': '2026-01-24',
                         'icon': 14,
                         'icon1': None,
                         'icon2': None,
                         'moonPhase': 1,
                         'moonrise': 1769242671000,
                         'moonriseOnThisDay': 1769242671000,
                         'moonset': 1769292482000,
                         'moonsetOnThisDay': 1769292482000,
                         'precipitation': 34,
                         'stationId': None,
                         'sunrise': 1769235537000,
                         'sunriseOnThisDay': 1769235537000,
                         'sunset': 1769267205000,
                         'sunsetOnThisDay': 1769267205000,
                         'sunshine': 0,
                         'temperatureMax': -35,
                         'temperatureMin': -48,
                         'windDirection': 1110,
                         'windGust': 370,
                         'windSpeed': 167},
                       { 'dayDate': '2026-01-25',
                         'icon': 14,
                         'icon1': None,
                         'icon2': None,
                         'moonPhase': 1,
                         'moonrise': 1769329896000,
                         'moonriseOnThisDay': 1769329896000,
                         'moonset': 1769383971000,
                         'moonsetOnThisDay': 1769383971000,
                         'precipitation': 14,
                         'stationId': None,
                         'sunrise': 1769321862000,
                         'sunriseOnThisDay': 1769321862000,
                         'sunset': 1769353709000,
                         'sunsetOnThisDay': 1769353709000,
                         'sunshine': 0,
                         'temperatureMax': -8,
                         'temperatureMin': -36,
                         'windDirection': 990,
                         'windGust': 278,
                         'windSpeed': 93},
                       { 'dayDate': '2026-01-26',
                         'icon': 4,
                         'icon1': None,
                         'icon2': None,
                         'moonPhase': 2,
                         'moonrise': 1769417320000,
                         'moonriseOnThisDay': 1769417320000,
                         'moonset': 1769475643000,
                         'moonsetOnThisDay': None,
                         'precipitation': 0,
                         'stationId': None,
                         'sunrise': 1769408185000,
                         'sunriseOnThisDay': 1769408185000,
                         'sunset': 1769440214000,
                         'sunsetOnThisDay': 1769440214000,
                         'sunshine': 0,
                         'temperatureMax': 9,
                         'temperatureMin': -10,
                         'windDirection': 1190,
                         'windGust': 333,
                         'windSpeed': 130},
                       { 'dayDate': '2026-01-27',
                         'icon': 4,
                         'icon1': None,
                         'icon2': None,
                         'moonPhase': 2,
                         'moonrise': 1769505116000,
                         'moonriseOnThisDay': 1769505116000,
                         'moonset': 1769475643000,
                         'moonsetOnThisDay': 1769475643000,
                         'precipitation': 0,
                         'stationId': None,
                         'sunrise': 1769494505000,
                         'sunriseOnThisDay': 1769494505000,
                         'sunset': 1769526720000,
                         'sunsetOnThisDay': 1769526720000,
                         'sunshine': 0,
                         'temperatureMax': 14,
                         'temperatureMin': -11,
                         'windDirection': 1980,
                         'windGust': 204,
                         'windSpeed': 74},
                       { 'dayDate': '2026-01-28',
                         'icon': 4,
                         'icon1': None,
                         'icon2': None,
                         'moonPhase': 2,
                         'moonrise': 1769593555000,
                         'moonriseOnThisDay': 1769593555000,
                         'moonset': 1769567349000,
                         'moonsetOnThisDay': 1769567349000,
                         'precipitation': 1,
                         'stationId': None,
                         'sunrise': 1769580823000,
                         'sunriseOnThisDay': 1769580823000,
                         'sunset': 1769613226000,
                         'sunsetOnThisDay': 1769613226000,
                         'sunshine': 0,
                         'temperatureMax': 5,
                         'temperatureMin': -22,
                         'windDirection': 1530,
                         'windGust': 259,
                         'windSpeed': 111},
                       { 'dayDate': '2026-01-29',
                         'icon': 4,
                         'icon1': None,
                         'icon2': None,
                         'moonPhase': 2,
                         'moonrise': 1769682966000,
                         'moonriseOnThisDay': 1769682966000,
                         'moonset': 1769658611000,
                         'moonsetOnThisDay': 1769658611000,
                         'precipitation': 3,
                         'stationId': None,
                         'sunrise': 1769667139000,
                         'sunriseOnThisDay': 1769667139000,
                         'sunset': 1769699732000,
                         'sunsetOnThisDay': 1769699732000,
                         'sunshine': 0,
                         'temperatureMax': 6,
                         'temperatureMin': -11,
                         'windDirection': 1180,
                         'windGust': 296,
                         'windSpeed': 111},
                       { 'dayDate': '2026-01-30',
                         'icon': 4,
                         'icon1': None,
                         'icon2': None,
                         'moonPhase': 3,
                         'moonrise': 1769773532000,
                         'moonriseOnThisDay': 1769773532000,
                         'moonset': 1769748920000,
                         'moonsetOnThisDay': 1769748920000,
                         'precipitation': 0,
                         'stationId': None,
                         'sunrise': 1769753452000,
                         'sunriseOnThisDay': 1769753452000,
                         'sunset': 1769786239000,
                         'sunsetOnThisDay': 1769786239000,
                         'sunshine': 0,
                         'temperatureMax': -3,
                         'temperatureMin': -24,
                         'windDirection': 1270,
                         'windGust': 278,
                         'windSpeed': 111},
                       { 'dayDate': '2026-01-31',
                         'icon': 14,
                         'icon1': None,
                         'icon2': None,
                         'moonPhase': 3,
                         'moonrise': 1769864987000,
                         'moonriseOnThisDay': 1769864987000,
                         'moonset': 1769838104000,
                         'moonsetOnThisDay': 1769838104000,
                         'precipitation': 6,
                         'stationId': None,
                         'sunrise': 1769839764000,
                         'sunriseOnThisDay': 1769839764000,
                         'sunset': 1769872747000,
                         'sunsetOnThisDay': 1769872747000,
                         'sunshine': 0,
                         'temperatureMax': -25,
                         'temperatureMin': -34,
                         'windDirection': 980,
                         'windGust': 278,
                         'windSpeed': 111}],
             'forecast1': { 'cloudCoverTotal': [],
                            'dewPoint2m': [ -134, -135, -133, -136, -132, -126,
                                            -120, -116, -111, -108, -106, -104,
                                            -100, -98, -94, -91, -86, -82, -75,
                                            -70, -65, -59, -51, -47, -43, -39,
                                            -39, -42, -44, -46, -48, -48, -48,
                                            -51, -54, -56, -56, -59, -60, -61,
                                            -61, -60, -59, -57, -56, -53, -52,
                                            -50, -51, -48, -47, -51, -50, -50,
                                            -48, -48, -49, -49, -48, -49],
                            'humidity': [ 744, 732, 768, 767, 792, 825, 866,
                                          881, 916, 917, 924, 903, 903, 903,
                                          896, 890, 904, 911, 933, 933, 927,
                                          920, 927, 914, 914, 942, 928, 921,
                                          901, 900, 914, 914, 928, 934, 913,
                                          913, 906, 899, 906, 899, 892, 906,
                                          920, 927, 920, 920, 907, 907, 887,
                                          914, 914, 914, 920, 914, 928, 914,
                                          907, 914, 921, 914],
                            'icon': [ 1, 32767, 32767, 32767, 32767, 32767, 1,
                                      32767, 32767, 32767, 32767, 32767, 4, 2,
                                      2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
                                      4, 4, 4, 4, 4, 14, 14, 14, 14, 14, 14, 14,
                                      14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
                                      14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
                                      14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
                                      14, 14, 14],
                            'icon1h': [ 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4,
                                        4, 4, 4, 4, 4, 4, 4, 14, 14, 14, 14, 14,
                                        14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
                                        14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
                                        14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
                                        14, 14, 14, 14, 14],
                            'isDay': [ False, False, False, False, False, False,
                                       False, False, False, False, False, False,
                                       True, True, True, True, True, False,
                                       False, False, False, False, False, False,
                                       False, False, False, False, False, False,
                                       False, False, True, True, True, True,
                                       True, True, True, True, True, False,
                                       False, False, False, False, False, False,
                                       False, False, False, False, False, False,
                                       False, False, True, True, True, True,
                                       True, True, True, True, True, False,
                                       False, False, False, False, False, False,
                                       False],
                            'precipitationProbablity': None,
                            'precipitationProbablityIndex': None,
                            'precipitationTotal': [ 32767, 32767, 32767, 32767,
                                                    32767, 32767, 32767, 32767,
                                                    32767, 32767, 32767, 32767,
                                                    32767, 0, 0, 0, 0, 0, 0, 0,
                                                    0, 0, 0, 0, 0, 0, 0, 0, 0,
                                                    0, 0, 0, 0, 1, 1, 1, 1, 1,
                                                    1, 1, 1, 1, 1, 1, 1, 1, 1,
                                                    1, 1, 1, 1, 1, 1, 1, 1, 1,
                                                    2, 2, 2, 2, 2, 2, 1, 1, 1,
                                                    1, 1, 1, 2, 1, 2, 2, 2],
                            'start': 1769036400000,
                            'stationId': '12495',
                            'sunshine': [ 32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767],
                            'surfacePressure': [ 10088, 10089, 10092, 10098,
                                                 10099, 10099, 10100, 10101,
                                                 10101, 10102, 10100, 10099,
                                                 10098, 10098, 10096, 10096,
                                                 10095, 10094, 10096, 10097,
                                                 10096, 10097, 10094, 10093,
                                                 10093, 10092, 10091, 10094,
                                                 10096, 10098, 10101, 10103,
                                                 10105, 10106, 10106, 10106,
                                                 10106, 10105, 10104, 10103,
                                                 10100, 10103, 10103, 10105,
                                                 10108, 10106, 10105, 10103,
                                                 10103, 10105, 10103, 10107,
                                                 10107, 10108, 10110, 10109,
                                                 10109, 10107, 10106, 10105],
                            'temperature': [ 32767, -126, 32767, 32767, 32767,
                                             32767, 32767, -117, 32767, 32767,
                                             32767, 32767, 32767, -108, -97,
                                             -96, -100, -103, -103, -102, -102,
                                             -100, -100, -97, -96, -91, -87,
                                             -85, -80, -76, -73, -70, -66, -61,
                                             -55, -48, -41, -35, -31, -31, -29,
                                             -31, -30, -32, -36, -36, -38, -42,
                                             -42, -44, -43, -45, -47, -47, -46,
                                             -47, -48, -47, -45, -42, -39, -37,
                                             -35, -36, -35, -39, -39, -38, -38,
                                             -36, -36, -37, -37, -37, -34, -33,
                                             -33, -34, -36, -36, -31, -29, -26,
                                             -20, -16, -12, -8, -10, -9, -10,
                                             -12, -13, -12, -13, -14, -14, -14,
                                             -11, -10, -9, -7, -5, -2, -3, -1,
                                             1, 1, 4, 6, 9, 9, 7, 7, 3, 1, 1, 4,
                                             3, 1, 0, -1, -2, -4, -4, -5, -1,
                                             -1, -2, 0, -1, 2, 7, 10, 14, 14,
                                             12, 9, 7, 4, 2, -2, -5, -8, -11,
                                             -9, -11, -9, -9, -11, -19, -21,
                                             -21, -22, -19, -15, -11, -4, 0, 3,
                                             5, 2, 1, -1, -7, -9, -10, -11, -11,
                                             -11, -11, -5, -5, -6, -6, -5, -4,
                                             -3, -1, 2, -2, 1, 6, 6, 6, 3, -1,
                                             -1, -4, -3, -5, -6, -8, -9, -11,
                                             -11, -9, -10, -10, -13, -15, -15,
                                             -15, -12, -7, -5, -7, -6, -3, -5,
                                             -9, -10, -11, -17, -19, -19, -20,
                                             -22, -24, -27, -27, -27, -28, -30,
                                             -31, -30, -30, -30, -29, -25, -29,
                                             -27, -27, -28, -33, -33, -32, -33,
                                             -33, -32, -32, -33, -34],
                            'temperatureStd': [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                                                0, 0, 0, 12, 13, 12, 12, 13, 14,
                                                15, 15, 15, 14, 15, 15, 14, 15,
                                                15, 13, 14, 14, 13, 13, 13, 12,
                                                12, 12, 13, 13, 12, 12, 13, 14,
                                                13, 14, 14, 14, 14, 14, 14, 14,
                                                14, 15, 15, 14, 14, 14, 14, 14,
                                                14, 14, 13, 13, 13, 14, 14, 14,
                                                14, 14, 14, 15, 14, 15, 14, 13,
                                                14, 14, 14, 15, 16, 16, 16, 15,
                                                16, 17, 17, 18, 17, 17, 17, 17,
                                                16, 16, 17, 17, 17, 17, 17, 17,
                                                14, 14, 15, 15, 15, 16, 17, 17,
                                                15, 15, 16, 15, 15, 14, 15, 14,
                                                15, 15, 16, 16, 15, 16, 16, 16,
                                                17, 17, 17, 17, 19, 19, 17, 18,
                                                18, 18, 18, 17, 18, 18, 17, 18,
                                                18, 19, 20, 20, 20, 21, 21, 21,
                                                21, 20, 20, 20, 21, 19, 19, 18,
                                                19, 19, 22, 23, 22, 21, 19, 19,
                                                20, 20, 21, 20, 21, 21, 20, 21,
                                                22, 21, 20, 21, 22, 21, 20, 20,
                                                21, 21, 21, 22, 21, 21, 22, 22,
                                                23, 24, 24, 25, 24, 24, 23, 24,
                                                24, 24, 24, 24, 24, 24, 24, 22,
                                                21, 20, 21, 21, 21, 20, 20, 21,
                                                20, 20, 20, 20, 22, 22, 23, 23,
                                                24, 23, 23, 23, 22, 22, 21, 21,
                                                21, 21, 21, 23, 22, 23, 22, 23,
                                                23, 23, 23, 23, 23, 23],
                            'timeStep': 3600000,
                            'windDirection': None,
                            'windGust': None,
                            'windSpeed': None},
             'forecast2': { 'cloudCoverTotal': [],
                            'dewPoint2m': [ -47, -43, -37, -27, -22, -26, -23,
                                            -25, -18, -13, -6, -1, 4, -1, -6,
                                            -10, -8, -7, -6, -2, -4, -12, -13,
                                            -16, -26, -33, -26, -18, -15, -14,
                                            -15, -19, -17, -17, -10, -8, -20,
                                            -22, -20, -26, -25, -20, -18, -21,
                                            -5, -12, -29, -31, -32, -38, -34,
                                            -32, -34, -32, -32, -34],
                            'humidity': [ 900, 949, 921, 895, 909, 909, 936,
                                          902, 923, 930, 950, 930, 979, 986,
                                          950, 943, 978, 964, 944, 891, 910,
                                          903, 964, 964, 895, 915, 922, 877,
                                          883, 950, 971, 943, 923, 909, 916,
                                          903, 845, 876, 902, 895, 895, 964,
                                          957, 902, 1000, 993, 929, 949, 963,
                                          949, 971, 978, 956, 1000, 1000,
                                          1000],
                            'icon': [ 14, 14, 14, 14, 14, 4, 4, 4, 4, 4, 4, 4,
                                      4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
                                      14, 4, 4, 4, 4, 4, 7, 7, 4, 4, 7, 4, 4, 4,
                                      4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 14, 4,
                                      14, 14, 4],
                            'icon1h': [ 14, 14, 14, 14, 14, 4, 4, 4, 4, 4, 4, 4,
                                        4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
                                        4, 14, 4, 4, 4, 4, 4, 7, 7, 4, 4, 7, 4,
                                        4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
                                        14, 4, 14, 14, 4],
                            'isDay': [ False, False, True, True, True, False,
                                       False, False, False, False, True, True,
                                       True, False, False, False, False, False,
                                       True, True, True, False, False, False,
                                       False, False, True, True, True, False,
                                       False, False, False, False, True, True,
                                       True, False, False, False, False, False,
                                       True, True, True, False, False, False,
                                       False, False, True, True, True, False,
                                       False, False],
                            'precipitationProbablity': None,
                            'precipitationProbablityIndex': None,
                            'precipitationTotal': [ 4, 3, 3, 3, 1, 0, 0, 0, 0,
                                                    0, 0, 0, 0, 0, 0, 0, 0, 0,
                                                    0, 0, 0, 0, 0, 0, 0, 0, 1,
                                                    0, 0, 0, 0, 0, 1, 1, 0, 0,
                                                    1, 0, 0, 0, 0, 0, 0, 0, 0,
                                                    0, 0, 0, 0, 0, 0, 1, 0, 3,
                                                    2, 0],
                            'start': 1769295600000,
                            'stationId': '12495',
                            'sunshine': [ 32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767, 32767, 32767, 32767, 32767,
                                          32767],
                            'surfacePressure': [ 10112, 10106, 10108, 10105,
                                                 10101, 10099, 10090, 10080,
                                                 10063, 10045, 10037, 10031,
                                                 10027, 10029, 10026, 10029,
                                                 10027, 10022, 10026, 10029,
                                                 10029, 10035, 10038, 10037,
                                                 10026, 10022, 10015, 10011,
                                                 10008, 10007, 10006, 10001,
                                                 10000, 10000, 9992, 9989,
                                                 10005, 10014, 10011, 10032,
                                                 10022, 10026, 10032, 10028,
                                                 10028, 10019, 10019, 10024,
                                                 10020, 10026, 10039, 10036,
                                                 10032, 10018, 10022, 10017],
                            'temperature': [],
                            'temperatureStd': [],
                            'timeStep': 10800000,
                            'windDirection': None,
                            'windGust': None,
                            'windSpeed': None},
             'forecastStart': None,
             'threeHourSummaries': None,
             'warnings': []}}

Installing and Importing External Packages#

Pythonโ€™s strength, however, lies in its enormous selection of available packages. For most purposes, there are Python packages available. One such directory is PyPI, which lists over 400,000 packages.

The installation of new packages for Python is easy. For this, you open a terminal (command line) and enter the command pip install <packetname>.

For example, we want to display the weather data we just loaded. To do this we use:

  • first the pandas package for creating a table from the weather data.

  • then we use the plotly package to draw a chart.

  • finally we create a web server with dash that will display the chart to us

We install all three with pip. We can do this in a single call. We use the --quiet switch to reduce the output.

# pip install pandas plotly dash  --quiet

Now we load both packages, with pandas typically assigned the alias pd and Plotly Express, which is easy to use, assigned the alias px.

import pandas as pd
import plotly.express as px
import dash
---------------------------------------------------------------------------
ModuleNotFoundError                       Traceback (most recent call last)
Cell In[9], line 1
----> 1 import pandas as pd
      2 import plotly.express as px
      3 import dash

ModuleNotFoundError: No module named 'pandas'

First, we convert the daily weather forecast days data from the weather station with the stationID into a table, since this can be processed by Plotly Express. Tables are called DataFrames in Pandas (in general, thatโ€™s what such tables are called in data science). So we create from the weather forecast a new object instance of type DataFrame via

df = pd.DataFrame(weather[stationID]['days'])
df
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[10], line 1
----> 1 df = pd.DataFrame(weather[stationID]['days'])
      2 df

NameError: name 'pd' is not defined

Now we plot the data df as a line chart using Plotly, with the date axis on the x-axis (dayDate) and the minimum temperature temperatureMin and the maximum temperature temperatureMax on the y-axis.

fig=px.line(df, x="dayDate", y=["temperatureMin", "temperatureMax"])
fig.show(renderer="svg")
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[11], line 1
----> 1 fig=px.line(df, x="dayDate", y=["temperatureMin", "temperatureMax"])
      2 fig.show(renderer="svg")

NameError: name 'px' is not defined

Finally, we want to display this diagram on a webpage on a web server. Here we use the package dash, which enables creating a webpage with Python commands and displaying interactive Plotly charts in it.

import dash

app = dash.Dash()
---------------------------------------------------------------------------
ModuleNotFoundError                       Traceback (most recent call last)
Cell In[12], line 1
----> 1 import dash
      3 app = dash.Dash()

ModuleNotFoundError: No module named 'dash'

Then we generate a webpage with a heading (H1) that contains the plot as a Graph.

app.layout = dash.html.Div(children = [
    dash.html.H1(children='Wetter in Rostock'),
    dash.dcc.Graph(id="fare_vs_age", figure=fig)
])
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[15], line 1
----> 1 app.layout = dash.html.Div(children = [
      2     dash.html.H1(children='Wetter in Rostock'),
      3     dash.dcc.Graph(id="fare_vs_age", figure=fig)
      4 ])

NameError: name 'dash' is not defined

And start the web server.

app.run_server()
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[16], line 1
----> 1 app.run_server()

NameError: name 'app' is not defined

This starts a web server that we can access in a browser at http://127.0.0.1:8083/. It shows a webpage with an interactive chart that displays the weather data.