From 8e83a18cd0835ee049be601c412e765f5c377f39 Mon Sep 17 00:00:00 2001 From: Meik Hellmund Date: Tue, 4 Jun 2024 17:57:12 +0200 Subject: [PATCH] IO fertig, trick mit module name in first julia cell --- .vscode/settings.json | 13 +- chapters/10_Strings.qmd | 6 +- chapters/13_IO.qmd | 286 ++++++++++++++++++++++---------------- chapters/5_TricksHelp.qmd | 6 + chapters/7_ArraysP2.qmd | 4 + chapters/9_functs.qmd | 11 +- chapters/pcomplex.qmd | 8 ++ chapters/types.qmd | 4 + 8 files changed, 210 insertions(+), 128 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 68e5d9b..581eec1 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,14 +1,15 @@ { "julia.environmentPath": "/home/hellmund/Julia/23", "files.exclude": { - "**/.git": true, - "**/.svn": true, - "**/.hg": true, - "**/CVS": true, "**/.DS_Store": true, - "**/Thumbs.db": true, + "**/.git": true, + "**/.hg": true, + "**/.svn": true, "**/*.ipynb": true, - "**/*.md": true + "**/*.md": true, + "**/*.quarto_ipynb": true, + "**/CVS": true, + "**/Thumbs.db": true }, "explorerExclude.backup": {}, "ltex.enabled": false, diff --git a/chapters/10_Strings.qmd b/chapters/10_Strings.qmd index aeaefa7..4dcddd9 100644 --- a/chapters/10_Strings.qmd +++ b/chapters/10_Strings.qmd @@ -7,6 +7,8 @@ engine: julia #| echo: false #| output: false using InteractiveUtils +import QuartoNotebookWorker +Base.stdout = QuartoNotebookWorker.with_context(stdout) ``` # Zeichen, Strings und Unicode @@ -140,10 +142,6 @@ Alternativ können Sie die PDF-Version dieser Seite verwenden. Dort sind alle Fo Eine kleine Hilfsfunktion: ```{julia} -""" -printuc(c, n): -print n characters from unicode table, starting with character c -""" function printuc(c, n) for i in 0:n-1 print(c + i) diff --git a/chapters/13_IO.qmd b/chapters/13_IO.qmd index 3db5bbb..5c85d5b 100644 --- a/chapters/13_IO.qmd +++ b/chapters/13_IO.qmd @@ -2,124 +2,172 @@ engine: julia --- +# Ein- und Ausgabe + + ```{julia} #| error: false #| echo: false #| output: false + +# https://github.com/JuliaLang/julia/blob/master/base/show.jl#L516-L520 +# https://github.com/JuliaLang/julia/blob/master/base/show.jl#L3073-L3077 + + using InteractiveUtils +import QuartoNotebookWorker +Base.stdout = QuartoNotebookWorker.with_context(stdout) +myactive_module() = Main.Notebook +Base.active_module() = myactive_module() ``` + + # Ein- und Ausgabe - -zahlreiche Varianten und Funktionen, das Folgende ist eine kleine Auswahl - ## Konsole -- OS-abhängig; üblicherweise 3 Kanäle _(streams)_: `stdin, stdout, stderr` (Standardinput, -output, -errorkanal) +Das Betriebssystem stellt für ein Programm üblicherweise 3 Kanäle _(streams)_ zur Verfügung: +- Standardeingabekanal `stdin` +- Standardausgabekanal `stdout` und +- Standardfehlerausgabekanal `stderr`. + +Wenn das Programm in einem Terminal (oder Konsole bzw. Shell) gestartet wird, kann das Programm über `stdin` die Tastatureingaben +einlesen und Ausgaben über `stdout` sowie `stdout` erscheinen im Terminal. - Schreiben nach `stdout`: `print()`,`println()`,`printstyled()` - Schreiben nach `stderr`: `print(strerr,...)`, `println(stderr,...)`, `printstyled(stderr,...)` - Lesen von `stdin`: `readline()` -### Umwandeln von Strings in andere Typen: - - - `chomp()` entfernt newline - - `split()` zerlegt in "Wörter" - - `parse()` wandelt in andere Typen um -### Buffer +### Eingaben -- `write`-Zugriffe werden gebuffert. - - - `flush(stdout)` leert Buffer +Die Sprache _Python_ stellt eine Funktion `input()` zur Verfügung: +```{.python} +ans = input("Bitte eine positive Zahl eingeben!") +``` +Die Funktion gibt den Prompt aus, wartet auf eine Eingabe und liefert die +Eingabe als `string` zurück. +In Julia kann man diese Funktion so implementieren: + ```{julia} - function input(prompt = "Eingabe:") println(prompt) flush(stdout) return chomp(readline()) end - ``` +**Anmerkungen** + +- Schreibanweisungen werden von modernen Betriebssystemen gebuffert. Mit `flush(stdout)` wird die Leerung des Buffers und sofortige Schreiboperation erzwungen. +- `readline()` liefert einen String zurück, der mit einer Newline `\n` endet. Die Funktion `chomp()` entfernt einen eventuellen Zeilenumbruch vom Ende eines Strings. + ```{julia} #| eval: false a = input("Bitte 2 Zahlen eingeben!") ``` - - ```{julia} #| echo: false a = "34 56" ``` + +### Verarbeitung der Eingabe + +> `split(str)` zerlegt einen String in "Wörter" und liefert einen _(array of strings)_: + ```{julia} av = split(a) ``` -```{julia} -parse.(Int, av) -``` +> `parse(T, str)` versucht, `str` in den Typ `T` umzuwandeln: ```{julia} -# Ausgaben auf den Fehlerkanal stderr erscheinen im Jupyter in rot: -@warn "Das @warn-Macro schreibt nach stderr." -println("Hallo!") -println(stderr, "Das sollte nicht passieren!") +v = parse.(Int, av) ``` +`parse()` erzeugt einen Fehler, wenn der String sich nicht als Wertangabe von Typ `T` parsen lässt. Man kann den Fehler mit +`try/catch` abfangen oder die Funktion `tryparse(T, str)` verwenden, die in so einem Fall `nothing` zurückgibt - worauf man dann +z.B. mit `isnothing()` testen kann. + + + ### Einzelne Tastenanschläge einlesen - `readline()` u.ä. warten auf den Abschluss der Eingabe durch Drücken der `Enter`-Taste. -- Zum Einlesen einzelner _keystrokes_: +- Techniken zum Einlesen einzelner _keystrokes_ findet man hier: - [https://stackoverflow.com/questions/56888266/how-to-read-keyboard-inputs-at-every-keystroke-in-julia](https://stackoverflow.com/questions/56888266/how-to-read-keyboard-inputs-at-every-keystroke-in-julia) - [https://stackoverflow.com/questions/60954235/how-can-i-test-whether-stdin-has-input-available-in-julia](https://stackoverflow.com/questions/60954235/how-can-i-test-whether-stdin-has-input-available-in-julia) -## Formatierte Ausgabe mit dem `Printf`-Paket -Die Macros `@sprintf` und `@printf` sind den gleichnamigen C-Funktionen nachempfunden -- Formatstring: Normaler String mit Platzhaltern -- Platzhalter haben die Form +## Formatierte Ausgabe mit dem `Printf`-Makro + +Oft möchte man Zahlen oder Strings mit einer strikten Formatvorgabe - Gesamtlänge, Nachkommastellen, rechts/linksbündig usw - ausgeben. + +Dazu definiert das Paket `Printf` die Makros `@sprintf` und `@printf`, welche sehr ähnlich wie die gleichnamigen C-Funktionen arbeiten. + +```{julia} +using Printf + +x = 123.7876355638734 + +@printf("Ausgabe rechtsbündig mit max. 10 Zeichen Platz und 3 Nachkommastellen: x= %10.3f", x) +``` + + +Das erste Argument ist ein String, der Platzhalter (hier: `%10.3`) für auszugebende Variablen enthält; gefolgt von diesen Variablen als weitere Argumente. + +Platzhalter haben die Form ``` %[flags][width][.precision]type ``` - (wobei die Angaben in eckigen Klammern alle optional sind) -- Typen: -``` -%s string -%i integer -%o integer octal (base=8) -%x, %X integer hexadecimal (base=16) with digits 0-9abcdef or 0-9ABCDEF, resp. -%f floatong point number -%e floating point number, scientific representation -%g floating point, uses %f or %e depending on value -``` +wobei die Angaben in eckigen Klammern alle optional sind. -- Flags: -``` -Pluszeichen: rechtsbündig (Standard) -Minuszeichen: linksbündig -Null: mit führenden Nullen -``` +**Typangaben im Platzhalter** + +| | | +|:--|:------------| +|`%s`| `string`| +|`%i`| `integer`| +|`%o`| `integer octal (base=8)`| +|`%x, %X`| `integer hexadecimal (base=16) with digits 0-9abcdef or 0-9ABCDEF, resp.`| +|`%f`| `floating point number`| +|`%e`| `floating point number, scientific representation`| +|`%g`| `floating point, uses %f or %e depending on value`| + +: {.striped .hover} + + +**Flags** + +| | | +|:----|:-----| +|Pluszeichen| rechtsbündig (Standard)| +|Minuszeichen| linksbündig| +|Null| mit führenden Nullen| + +: {.striped .hover} + + +**Width** -- Width: ``` Anzahl der minimal verwendeten Zeichen (wenn nötig, werden auch mehr genommen) ``` -Zeit für Beispiele: +### Beispiele: ```{julia} @@ -130,6 +178,7 @@ using Printf # Paket laden nicht vergessen! ```{julia} @printf("|%s|", "Hallo") # string mit Platzhalter für String ``` +Die senkrechten Striche sind nicht Teil des Platzhalters. Sie sollen die Begrenzung des Ausgabefeldes anzeigen. ```{julia} @@ -144,7 +193,7 @@ using Printf # Paket laden nicht vergessen! ```{julia} @printf("|%3s|", "Hallo") # Längenangabe kann überschritten werden - # besser eine 'kaputt formatierte' Tabelle als falsche Werte!! + # besser eine 'kaputt formatierte' Tabelle als falsche Werte! ``` @@ -156,21 +205,21 @@ l = 3342678 @printf("j= %012i, k= %-12i, l = %12i", j, k, l) # 0-Flag für führende Nullen ``` -`@printf` und `@sprintf` können wie alle Macros wie Funktionen aufgerufen werden: +`@printf` und `@sprintf` können wie alle Makros wie Funktionen aufgerufen werden: ```{julia} @printf("%i %i", 22, j) ``` --- oder wie Macros, also ohne Funktionsklammern und ohne Komma: +-- oder wie Makros, also ohne Funktionsklammern und ohne Komma: ```{julia} @printf "%i %i" 22 j ``` -`@printf` kann als erstes Argument noch einen stream übergeben bekommen. +`@printf` kann als erstes Argument noch einen Stream übergeben bekommen. Ansonsten besteht die Argumentliste aus @@ -183,7 +232,7 @@ Ansonsten besteht die Argumentliste aus j, "(geschätzt)" ,k) ``` -`@sprintf` druckt nichts, sondern liefert den ausgefüllten formatierten String zurück: +Das Makro `@sprintf` druckt nichts, sondern liefert den ausgefüllten formatierten String zurück: ```{julia} @@ -195,12 +244,12 @@ str = @sprintf("x = %10.6f", π ); str ``` -##### Formatierung der Gleitkommazahlen: +### Formatierung der Gleitkommazahlen: Bedeutung des _Precision_-Wertes: -- `%f` und `%e`-Format: max. Anzahl der Nachkommastellen -- `%g`-Format: max. Anzahl von ausgegebenen Ziffern (Vor- + Nachkommastellen) +- `%f` und `%e`-Format: maximale Anzahl der Nachkommastellen +- `%g`-Format: maximale Anzahl von ausgegebenen Ziffern (Vor- + Nachkommastellen) ```{julia} @@ -223,157 +272,153 @@ x = 123456.7890123456 Dateien werden - - geöffnet ==> Dabei ensteht ein neues _stream_-Objekt (zusätzlich zu `stdin, stdout, stderr`) + - geöffnet $\Longrightarrow$ dabei ensteht ein neues _stream_-Objekt (zusätzlich zu `stdin, stdout, stderr`) - dann kann dieser _stream_ gelesen und geschrieben werden - - geschlossen ==> _stream_-Objekt wird von Datei getrennt + - geschlossen $\Longrightarrow$ _stream_-Objekt wird von Datei getrennt - ``` + ```{.julia} stream = open(path, mode) ``` - path: Dateiname/pfad - mode: + ``` "r" read, öffnet am Dateianfang "w" write, öffnet am Dateianfang (Datei wird neu angelegt oder überschrieben) "a" append, öffnet zum Weiterschreiben am Dateiende ``` +Schreiben wir mal eine Datei: ```{julia} -f = open("datei.txt", "w") -``` - - -```julia -@printf(f, "%20i\n", k) +file = open("datei.txt", "w") ``` ```{julia} -println(f, " zweite Zeile") +@printf(file, "%10i\n", k) ``` ```{julia} -close(f) +println(file, " zweite Zeile") ``` +```{julia} +close(file) +``` + +Schauen wir uns die Datei an: + ```{julia} ;cat datei.txt ``` +...und jetzt öffnen wir sie wieder zum Einlesen: ```{julia} -f = open("datei.txt", "r") +stream = open("datei.txt", "r") ``` +`readlines(stream)` liefert alle Zeilen einer Textdatei als Vector von Strings. + +`eachline(stream)` liefert einen Iterator über die Zeilen der Datei. + ```{julia} n = 0 -for i in readlines(f) # Lese zeilenweise +for line in eachline(stream) # Lese zeilenweise n += 1 - println(n, i) # Drucke mit Zeilennummer + println(n, line) # Drucke mit Zeilennummer end +close(stream) ``` ## Pakete für Dateiformate -Pakete für die Ein- und Ausgabe in den verschiedensten Dateiformaten +Für die Ein- und Ausgabe in den verschiedensten Dateiformaten existieren Julia-Pakete, z.B. - [PrettyTables.jl](https://ronisbr.github.io/PrettyTables.jl/stable/) Ausgabe von formatierten Tabellen - [DelimitedFiles.jl](https://docs.julialang.org/en/v1/stdlib/DelimitedFiles/) Ein- und Ausgabe von Matrizen u.ä. -- [CSV.jl](https://csv.juliadata.org/stable/) Ein- und Ausgabe von Dateien mit "comma-delimited values" u.ä. +- [CSV.jl](https://csv.juliadata.org/stable/) Ein- und Ausgabe von Dateien mit "comma-separated values" u.ä. - [XLSX.jl](https://felipenoris.github.io/XLSX.jl/stable/tutorial/) Ein- und Ausgabe von Excel-Dateien und viele andere mehr... -### Delimited Files - +### DelimitedFiles.jl +Dieses Paket ermöglicht das bequeme Abspeichern/Einlesen von Matrizen. Dazu stellt es die Funktionen `writedlm()` und `readdlm()` zur +Verfügung. ```{julia} using DelimitedFiles ``` +Wir erzeugen eine 200×3-Matrix von Zufallszahlen ```{julia} A = rand(200,3) ``` - +und speichern diese ```{julia} f = open("data2.txt", "w") -``` - - -```{julia} writedlm(f, A) -``` - - -```{julia} close(f) ``` +Die geschriebene Datei fängt so an: + ```{julia} ;head data2.txt ``` +Das Wiedereinlesen ist noch einfacher: ```{julia} B = readdlm("data2.txt") - ``` -```{julia} -# man kann open() auch als 1.Argument eine function(iostream) übergeben, die auf den stream -# angewendet wird, wonach der stream automatisch geschlosssen wird. -# -# Mit der do-Notation sieht obiger code so aus: +Noch ein Punkt: Beim Umgang mit Dateien wird in Julia oft die `do`-Notation verwendet, s. @sec-do. +Dazu nutzt man, dass `open()` auch Methoden hat, bei denen das 1. Argument eine `function(iostream)` ist. +Diese wird dann auf den _stream_ angewendet und dieser abschliessend automatisch geschlossen. Die `do`-Notation erlaubt es, +diese Funktion anonym nach dem `do` zu definieren: +```{julia} open("data2.txt", "w") do io writedlm(io, A) end - ``` ### CSV und DataFrames -- [DataFrames.jl](https://dataframes.juliadata.org/stable/) ist ein Paket zum bequemen Umgang mit tabellarischen Daten - +- Das CSV-Format wird oft benutzt, um Tabellen in einer nicht nur mit MS Excel lesbaren Form zur Verfügung zu stellen. +- Ein Beispiel ist die Wetter- und Klimadatenbank _Meteostat_. +- Das Paket [DataFrames.jl](https://dataframes.juliadata.org/stable/) stellt Funktionen zum bequemen Umgang mit tabellarischen Daten +zur Verfügung. ```{julia} using CSV, DataFrames, Downloads -``` - - -```{julia} # Wetterdaten von Westerland, s. https://dev.meteostat.net/bulk/hourly.html - url = "https://bulk.meteostat.net/v2/hourly/10018.csv.gz" -``` - - -```{julia} http_response = Downloads.download(url) +file = CSV.File(http_response, header=false); ``` -```{julia} -file = CSV.File(http_response, header=false) -``` +Die Daten sehen so aus: ```{julia} # https://dev.meteostat.net/bulk/hourly.html#endpoints - +# # Spalte 1 Datum # 2 Uhrzeit (Stunde) # 3 Temp @@ -382,25 +427,30 @@ file = CSV.File(http_response, header=false) # 8 Windrichtung # 9 Windstärke - df = DataFrame(file) ``` + ```{julia} +#| error: false +#| echo: false +#| output: false +#| eval: false describe(df) ``` + +Zum bequemen Plotten und zum Umgang mit den Datums- und Zeitformaten in der Wettertabelle +laden wir noch 2 Helferlein: + ```{julia} -using StatsPlots +using StatsPlots, Dates ``` -```{julia} -using Dates -``` - +Wir erzeugen eine neue Spalte, die Datum (asu Spalte 1) und Uhrzeit (aus Spalte 2) kombiniert: ```{julia} # neue Spalte mit Sp.1 und 2 (date & time) kombiniert @@ -409,20 +459,24 @@ df[!, :datetime] = DateTime.(df.Column1) .+ Hour.(df.Column2); ``` -```{julia} -describe(df) -``` ```{julia} +#| error: false +#| echo: false +#| output: false +#| eval: false + @df df plot(:datetime, :Column3) ``` +Und nun zum Plot: ```{julia} @df df plot(:datetime, [:Column9, :Column6, :Column3], - xlims = (DateTime(2022,1,1), DateTime(2022,7,1)), - layout=(3,1), title=["Wind" "Regen" "Temp"], legend=:none) + xlims = (DateTime(2023,9,1), DateTime(2024,5,30)), + layout=(3,1), title=["Wind" "Regen" "Temp"], + legend=:none, size=(800,800)) ``` diff --git a/chapters/5_TricksHelp.qmd b/chapters/5_TricksHelp.qmd index 30d81ae..5fa4aa4 100644 --- a/chapters/5_TricksHelp.qmd +++ b/chapters/5_TricksHelp.qmd @@ -9,6 +9,12 @@ engine: julia #| echo: false #| output: false using InteractiveUtils +import QuartoNotebookWorker +Base.stdout = QuartoNotebookWorker.with_context(stdout) +myactive_module() = Main.Notebook +Base.active_module() = myactive_module() +# https://github.com/JuliaLang/julia/blob/master/base/show.jl#L516-L520 +# https://github.com/JuliaLang/julia/blob/master/base/show.jl#L3073-L3077 ``` ## Dokumentation diff --git a/chapters/7_ArraysP2.qmd b/chapters/7_ArraysP2.qmd index 1632bf2..7d61b82 100644 --- a/chapters/7_ArraysP2.qmd +++ b/chapters/7_ArraysP2.qmd @@ -7,6 +7,10 @@ engine: julia #| echo: false #| output: false using InteractiveUtils +import QuartoNotebookWorker +Base.stdout = QuartoNotebookWorker.with_context(stdout) +myactive_module() = Main.Notebook +Base.active_module() = myactive_module() ``` # Vektoren, Matrizen, Arrays diff --git a/chapters/9_functs.qmd b/chapters/9_functs.qmd index 054e69b..c762fa8 100644 --- a/chapters/9_functs.qmd +++ b/chapters/9_functs.qmd @@ -2,14 +2,21 @@ engine: julia --- +# Funktionen und Operatoren + ```{julia} #| error: false #| echo: false #| output: false using InteractiveUtils +import QuartoNotebookWorker +Base.stdout = QuartoNotebookWorker.with_context(stdout) +myactive_module() = Main.Notebook +Base.active_module() = myactive_module() +# https://github.com/JuliaLang/julia/blob/master/base/show.jl#L516-L520 +# https://github.com/JuliaLang/julia/blob/master/base/show.jl#L3073-L3077 ``` -# Funktionen und Operatoren Funktionen verarbeiten ihre Argumente zu einem Ergebnis, das sie beim Aufruf zurückliefern. @@ -305,7 +312,7 @@ f(.2) ["a", "list", "of", "strings"] .|> [length, uppercase, reverse, titlecase] ``` -## Die `do`-Notation +## Die `do`-Notation {#sec-do} Eine syntaktische Besonderheit zur Definition anonymer Funktionen als Argumente anderer Funktionen ist die `do`-Notation. diff --git a/chapters/pcomplex.qmd b/chapters/pcomplex.qmd index 243bf19..3c43c3f 100644 --- a/chapters/pcomplex.qmd +++ b/chapters/pcomplex.qmd @@ -2,11 +2,19 @@ engine: julia --- +# Ein Fallbeispiel: Der parametrisierte Datentyp PComplex + ```{julia} #| error: false #| echo: false #| output: false using InteractiveUtils +import QuartoNotebookWorker +Base.stdout = QuartoNotebookWorker.with_context(stdout) +myactive_module() = Main.Notebook +Base.active_module() = myactive_module() +# https://github.com/JuliaLang/julia/blob/master/base/show.jl#L516-L520 +# https://github.com/JuliaLang/julia/blob/master/base/show.jl#L3073-L3077 ``` # Ein Fallbeispiel: Der parametrisierte Datentyp PComplex diff --git a/chapters/types.qmd b/chapters/types.qmd index 29238e5..3db8099 100644 --- a/chapters/types.qmd +++ b/chapters/types.qmd @@ -8,6 +8,10 @@ engine: julia #| echo: false #| output: false using InteractiveUtils +import QuartoNotebookWorker +Base.stdout = QuartoNotebookWorker.with_context(stdout) +myactive_module() = Main.Notebook +Base.active_module() = myactive_module() ```