Archive for the ‘Python / SciPy / pandas’ Category.

Monatskalender für LaTeX mit Python erzeugen

Hier ein Beispiel, wie man mit Python kleine Monatskalender erzeugen kann. Geht auch mit LaTeX allein, ich möchte aber verschiedene Output-Formate (Markdown, HTML, etc.) erzeugen und dabei die komplette Kontrolle über den Code behalten.

# -*- coding: utf-8 -*-
 
import calendar
import datetime
 
def number_of_weeks(year, month):
    """
        Returns a tupel with the ISO no of the first and week and the no of weeks
    """
    tup_month_days = calendar.monthrange(year, month)
    first = datetime.date(year, month, 1)
    last = datetime.date(year, month, tup_month_days[1])
    first_week = first.isocalendar()[1]
    last_week = last.isocalendar()[1]
    return (first_week, last_week, last_week-first_week+1)
 
def gen_cal_latex(year, month):
    """
        https://stackoverflow.com/questions/9459337/assign-value-to-an-individual-cell-in-a-two-dimensional-python-array
    """
    c = calendar.TextCalendar()
    week_month_first, week_month_last, no_of_weeks = number_of_weeks(year, month)
 
    # generate calendar list, using tupel as a key    
    m = {(i, j):' ' for i in range(no_of_weeks) for j in range(7)}
 
    for tupel_date in c.itermonthdays4(year, month):
        t_year, t_month, t_day, t_weekday = tupel_date
        # use only dates inside the required month
        if t_month == month:
            temp_date = datetime.date(t_year, t_month, t_day)
            # check in which week we are with the current date
            # to get index for the list
            week_no = temp_date.isocalendar()[1]
            m[week_no % week_month_first, t_weekday] = t_day
 
    print(r'\begin{tabular}{rrrrrrr}')
    print(r'Mo & Di & Mi & Do & Fr & Sa & So \\')
    for i in m:
        if i[1] < 6:
            print('{0} &'.format(m[i]), end='')
        else:
            print('{0}'.format(m[i]),end='')
        if i[1] == 6:
            print(r'\\')
    print(r'\end{tabular}')
 
gen_cal_latex(2020, 4)

Erzeugt werden kleine Monatskalender der Form

\begin{tabular}{rrrrrrr}
Mo & Di & Mi & Do & Fr & Sa & So \\
  &  &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 &  &  & \\
\end{tabular}

Per Copy & Paste kann man den Code in ein LaTeX-Dokument kopieren, natürlich lässt sich das alles auch direkt in eine LaTeX-Datei schreiben.

Uwe

Uwe Ziegenhagen likes LaTeX and Python, sometimes even combined. Do you like my content and would like to thank me for it? Consider making a small donation to my local fablab, the Dingfabrik Köln. Details on how to donate can be found here Spenden für die Dingfabrik.

More Posts - Website

TeX-Dokumentstrukturen visualisieren mit Graphviz und Python

Hier ein Code-Schnipsel, um die Inputs und Includes von LaTeX-Dokumenten zu visualisieren. Ist noch ein wenig rudimentär und hardcoded, in den nächsten Tagen werde ich den Code mal in ein Github-Repo packen und dann ein wenig aufräumen. Aktuell wird eine Datei Master.tex erwartet, eine Graph.dot Datei wird als Output geschrieben. Das Skript geht rekursiv durch die TeX-Dateien durch und sucht nach \input, \include, \includegraphics und \lstinputlisting Befehlen.

# -*- coding: utf-8 -*-
import re
 
nodes = []
 
# which commands indicate following
commandsToFollow = ('input', 'include')
 
def find_ext_references(somefile):
    with open(somefile) as file:
        filecontent = file.readlines()
        for i in filecontent:
            search_results = re.findall(r"(\\)(includegraphics|include|lstinputlisting|input)(\[?.*\]?{)(.+?)(})", i)
            for j in search_results:
                print(j)
                nodes.append((somefile, j[3], j[1]))
                if j[1].endswith(commandsToFollow):
                    find_ext_references(j[3]+'.tex') # assume that no extension is used for input/include
 
find_ext_references('Master.tex')
 
print(nodes)
 
if len(nodes)>0:
    with open('graph.dot','w') as output:
            output.write('digraph IncludesInputs {\n')
            output.write('node [shape=box];\n\n')
            for k in nodes:
                if k[2].endswith(commandsToFollow):
                    output.write('"'+k[0] + '"->"' + k[1] + '.tex" [color="green"];\n')
                elif k[2].endswith('graphics'):
                    output.write('"'+k[0] + '"->"' + k[1] + '" [color="blue"];\n')         
                elif k[2].endswith('listing'):
                    output.write('"'+k[0] + '"->"' + k[1] + '" [color="red"];\n')                             
 
            output.write('}')

Übersetzt man die Graph.dot dann mit der dot.exe aus Graphviz, so erhält man für ein kleines Beispiel den folgenden Graphen. (Beispielaufruf: dot -Tpng Graph.dot)

Uwe

Uwe Ziegenhagen likes LaTeX and Python, sometimes even combined. Do you like my content and would like to thank me for it? Consider making a small donation to my local fablab, the Dingfabrik Köln. Details on how to donate can be found here Spenden für die Dingfabrik.

More Posts - Website

Nordwind-DB mit Python abfragen (Python, pandas, MySQL)

Hier ein einfaches Beispiel, wie man die Daten aus der Nordwind-Datenbank in einen pandas Dataframe bekommt. Der originale Code stammt von https://pythontic.com/pandas/serialization/mysql und wurde auf meine Datenbank angepasst.

# -*- coding: utf-8 -*-
 
from sqlalchemy import create_engine
import pymysql
import pandas as pd
 
sqlEngine       = create_engine('mysql+pymysql://nwread:northwind@192.168.0.60/northwind', pool_recycle=3600)
dbConnection    = sqlEngine.connect()
frame           = pd.read_sql("select * from products", dbConnection);
 
pd.set_option('display.expand_frame_repr', False)
print(frame)
 
frame.to_excel('r:/abc.xlsx')
 
dbConnection.close()

Uwe

Uwe Ziegenhagen likes LaTeX and Python, sometimes even combined. Do you like my content and would like to thank me for it? Consider making a small donation to my local fablab, the Dingfabrik Köln. Details on how to donate can be found here Spenden für die Dingfabrik.

More Posts - Website

Getting jitsi into retirement homes

Together with friends from Dingfabrik Koeln (Thanks for the idea, Marian!) I am currently developing an solution for retirement homes to allow simple access to jitsi video sessions.

We know that many old people currently cannot receive visitors due to Corona. So our idea is to give them access to a simple Linux-based notebook and allow them to easily create a jitsi video session. Based on a predefined list of servers (that is to be updated from remote) and a text file with names, that can be edited by a nurse with a text editor, we simply create a url that can be shared among relatives.

The application was made using Python and tkinter, all code was pretty much copied from SO and other sources, I just had to put it together. (Thank you giants, that I could „stand on your shoulders“)

Using a Linux laptop with installed Python (and additional python3-tk package), Chrome/Chromium and git we have the tool run on startup. On the first start a text file with names is created, that can be edited easily.

If you find it useful, see the code in my github: https://github.com/UweZiegenhagen/pyJitsiopen.

Future updates shall include:

  • Automated updates
  • Logging for error tracking
  • Using local server lists that are not overwritten during updates

Uwe

Uwe Ziegenhagen likes LaTeX and Python, sometimes even combined. Do you like my content and would like to thank me for it? Consider making a small donation to my local fablab, the Dingfabrik Köln. Details on how to donate can be found here Spenden für die Dingfabrik.

More Posts - Website

Parsing Lexware Qif files with Python (and pandas)

Python has a few packages to parse Quicken files, among them:

However both packages generated errors when I used them with the file from Lexware Financial Manager 2019. Also as a programming exercise I decided to write my own parser, available under https://github.com/UweZiegenhagen/PyQIF-Parser.

As of today the code parses Quicken files and generates an Excel file with the accounts, classifications, categories and transactions it finds in the file. It supports (German) online accounts, investment accounts are not (yet) supported. I do not use my portfolio with Quicken so I probably will not implement this, feel free ask for it (with example files) or send pull requests.

Some code example is provided:

from PyQifParser import PyQifParser
 
P = PyQifParser(r'C:\Users\Uwe\Nextcloud\QIF-Parser\Quicken_h.QIF')
P.parse()
P.to_excel('r:/export.xlsx')

I plan to extend the code with repect to a) visualisation, b) sanity checks and c) statistical analyses

Uwe

Uwe Ziegenhagen likes LaTeX and Python, sometimes even combined. Do you like my content and would like to thank me for it? Consider making a small donation to my local fablab, the Dingfabrik Köln. Details on how to donate can be found here Spenden für die Dingfabrik.

More Posts - Website

Adressen zerlegen mit Python

Ich bin kürzlich auf die Herausforderung gestoßen, verschiedene Adresstypen aufzusplitten. Gegeben war immer die Straße und die Hausnummer, allerdings in verschiedenen länderspezifischen Variationen.

Hier eine Datei Datensatz.txt mit den Straßen:

Thanelstr. 46
Sieglinde-Briemer-Straße 716
Rennerstr. 542a
34, Rue de la Chanson
456 Market Square
Auf der Burg
Auf der Burg 234
90211 Melrost Place, Apt. 1

Hinweis: Benötigt man größere Mengen an Fake-Adressen, dann leistet die Faker-Bibliothek (https://github.com/joke2k/faker) gute Dienste. Mit dem folgenden Python-Code gelingt der Split in Straße und Hausnummer recht gut:

with open('Datensatz.txt', 'rt', encoding='utf-8') as eingabedatei:
    for zeile in eingabedatei:
 
        if zeile[-1] == '\n':
            zeile = zeile[:-1] # Entferne Zeilenumbruch, falls vorhanden
        gesplittet = zeile.split(' ') # Splitte anhand des Leerzeichens
        print(gesplittet) # gibt die Liste aus
 
        if gesplittet[-1].isdigit() and gesplittet[0].isdigit():
            namensteil = ''
            for i in gesplittet[1:]:
                namensteil = namensteil + " " + i 
            print('Name ist "', namensteil.strip() ,  '", Hausnummer ist ',  gesplittet[0], sep = '')
 
        elif gesplittet[-1][0].isdigit() and gesplittet[-1][-1].isalpha():
            namensteil = ''
            for i in gesplittet[:-1]:
                namensteil = namensteil + " " + i 
            print('Name ist "', namensteil.strip() ,  '", Hausnummer ist ',  gesplittet[-1], sep = '')
 
        elif gesplittet[-1].isdigit():
            namensteil = ''
            for i in gesplittet[:-1]:
                namensteil = namensteil + " " + i 
            print('Name ist "', namensteil.strip() ,  '", Hausnummer ist ',  gesplittet[-1], sep = '')
 
        elif gesplittet[0].isdigit():
            namensteil = ''
            for i in gesplittet[1:]:
                namensteil = namensteil + " " + i 
            print('Name ist "', namensteil.strip() ,  '", Hausnummer ist ',  gesplittet[0], sep = '')            
 
        elif gesplittet[0][0].isdigit() and gesplittet[0][-1] == ',':
            namensteil = ''
            for i in gesplittet[1:]:
                namensteil = namensteil + " " + i 
            print('Name ist "', namensteil.strip() ,  '", Hausnummer ist ',  gesplittet[0][:-1], sep = '')

Ergebnis:

['Thanelstr.', '46']
Name ist "Thanelstr.", Hausnummer ist 46
['Sieglinde-Briemer-Straße', '716']
Name ist "Sieglinde-Briemer-Straße", Hausnummer ist 716
['Rennerstr.', '542a']
Name ist "Rennerstr.", Hausnummer ist 542a
['34,', 'Rue', 'de', 'la', 'Chanson']
Name ist "Rue de la Chanson", Hausnummer ist 34
['456', 'Market', 'Square']
Name ist "Market Square", Hausnummer ist 456
['Auf', 'der', 'Burg']
['Auf', 'der', 'Burg', '234']
Name ist "Auf der Burg", Hausnummer ist 234
['90211', 'Melrost', 'Place,', 'Apt.', '1']
Name ist "Melrost Place, Apt. 1", Hausnummer ist 90211

Die Lösung ist nicht optimal, besser fährt man sicher mit libpostal und seinen Python-Bindings (https://github.com/openvenues/pypostal)

Uwe

Uwe Ziegenhagen likes LaTeX and Python, sometimes even combined. Do you like my content and would like to thank me for it? Consider making a small donation to my local fablab, the Dingfabrik Köln. Details on how to donate can be found here Spenden für die Dingfabrik.

More Posts - Website

Mit Python PDFs herunterladen

Mit dem folgenden Python-Skript lassen sich auf einfache Weise alle PDFs von einer Webseite herunterladen.

from bs4 import BeautifulSoup
import urllib.request
import requests
 
url = 'http://irgendeineurl.de'
 
r  = requests.get(url)
data = r.text
soup = BeautifulSoup(data)
 
for link in soup.find_all('a'):
    if link.get('href').endswith('.pdf'):
        urllib.request.urlretrieve(url + link.get('href'), link.get('href'))
        print(url + link.get('href'))

Uwe

Uwe Ziegenhagen likes LaTeX and Python, sometimes even combined. Do you like my content and would like to thank me for it? Consider making a small donation to my local fablab, the Dingfabrik Köln. Details on how to donate can be found here Spenden für die Dingfabrik.

More Posts - Website

Ordner anlegen mit Python und Excel

Für das Github-Repository der Vorträge von Dante e.V. Vereinstagungen habe ich heute eine Menge Unterordner nebst entsprechenden README-Dateien anlegen dürfen. Da die manuelle Anlage zu lange gedauert hätte (und Verschwendung wertvoller Lebenszeit bedeutet hätte), habe ich ein kleines Python-Skript genutzt, das sich die Daten aus einer Excel-Datei geholt hat.

Die Excel-Datei Daten.xlsx hatte dabei den folgenden Aufbau:

Mit dem folgenden Skript habe ich pro Jahr jeweils zwei Unterordner angelegt und die README-Datei jeweils mit dem passenden Titel versorgt. Man hätte es noch schöner schreiben können, für einen Quick und Dirty Hack war es aber mehr als ausreichend.

import pandas as pd
import os
 
df = pd.read_excel('Daten.xlsx')
 
for index, row in df.iterrows():
    jahr = str(row['Year'])
 
    f1 = jahr + '-Frühling'
    f2 = jahr + '-Herbst'
    spring = row['Spring']
    autumn = row['Autumn']
 
    try:
        if not os.path.exists(f1):
            os.makedirs(f1)
    except OSError:
        print ('Fehler bei Verzeichnis ' +  directory)
 
    with open(f1+'/README.md', 'wt') as file:
        file.write('# Vorträge der Dante e.V. Frühjahrstagung '+jahr + '\n\n')
        file.write('Datum: \n')
        file.write('Veranstaltungsort: ' + spring +'\n')
 
    try:
        if not os.path.exists(f2):
            os.makedirs(f2)
    except OSError:
        print ('Fehler bei Verzeichnis ' +  directory)
 
 
    with open(f2+'/README.md','wt') as file:
        file.write('# Vorträge der Dante e.V. Herbsttagung '+jahr + '\n\n')
        file.write('Datum: \n')
        file.write('Veranstaltungsort: ' + autumn +'\n')

Uwe

Uwe Ziegenhagen likes LaTeX and Python, sometimes even combined. Do you like my content and would like to thank me for it? Consider making a small donation to my local fablab, the Dingfabrik Köln. Details on how to donate can be found here Spenden für die Dingfabrik.

More Posts - Website

Python-Übungsaufgabe: MD5-Hashes

Hier eine Übungsaufgabe, die ich mir heute basierend auf https://www.programmieraufgaben.ch/aufgabe/baeckerei-b-rot/xyikp5d5 ausgedacht habe:

Eine Firma hat sich im Streit von ihrem alten Administrator getrennt und hat jetzt ein Problem. Das Passwort für das Lohnzahlungssystem hatte nur der Admin, man kann es nicht zurücksetzen und sollte es einmal falsch eingegeben werden, werden alle Daten der letzten zehn Jahre gelöscht.

Studentin Susanne, die gerade ein Praktikum bei der Firma macht, findet im Dateisystem des Rechners eine Datei, die einen MD5-Hash vom Passwort enthält. Zusätzlich ist bekannt, dass es sich beim Passwort um (verschiedene Fälle mit steigender Komplexität)

* eine vierstellige Zahl (Hash lautet \texttt{48c8c3963853fff20bd9e8bee9bd4c07})
* eine fünfstellige Zahl (Hash selbst ausdenken) oder
* eine sechsstellige Zahl oder
* einen String aus vier (oder fünf oder sechs) Ziffern und Kleinbuchstaben (super als Hausaufgabe!)

handelt. Schreiben Sie ein Programm, das das Passwort im Klartext auf Basis des MD5-Hash ausgibt.

Für die Bestimmung des MD5-Hash nutzen Sie eine passende Bibliothek, eine Implementierung des Algorithmus ist natürlich nicht notwendig.

Uwe

Uwe Ziegenhagen likes LaTeX and Python, sometimes even combined. Do you like my content and would like to thank me for it? Consider making a small donation to my local fablab, the Dingfabrik Köln. Details on how to donate can be found here Spenden für die Dingfabrik.

More Posts - Website

Zwei Aufgabenblätter auf einer Seite mit LaTeX

Für meine Studierenden erstelle ich diverse Übungsblätter, damit das Thema „Python“ etwas anschaulicher wird. Dazu nutze ich ein angepasstes LaTeX-Template, mit dem ich die Seite dupliziere und in verkleinerter Form auf das DIN A4-Blatt bringe.

%!TEX TS-program = Arara
% arara: pdflatex: {shell: yes}
% arara: pdflatex: {shell: yes}
% arara: clean: { extensions: [ log, aux, nav, out, snm, vrb, toc ] }
 
\documentclass[a4paper,ngerman,12pt]{exam} 
 
\usepackage{babel}
\usepackage[a4paper,top=2.5cm,bottom=3cm,left=2.5cm,right=2cm]{geometry}
\usepackage[T1]{fontenc}
\usepackage{booktabs}
\usepackage{graphicx}
\usepackage{csquotes}
\usepackage{paralist}
\usepackage[math]{iwona}
\usepackage{textcomp}
\usepackage{listings}
\usepackage{xcolor}
 
\pointpoints{Punkt}{Punkte}
\bonuspointpoints{Bonuspunkt}{Bonuspunkte}
\renewcommand{\solutiontitle}{\noindent\textbf{Lösung:}\enspace}
 
\chqword{Frage}   
\chpgword{Seite} 
\chpword{Punkte}   
\chbpword{Bonus Punkte} 
\chsword{Erreicht}   
\chtword{Gesamt}
 
\pagestyle{headandfoot}
\runningheadrule
 
%%%%%%%
\definecolor{hellgelb}{rgb}{1,1,0.8}
\definecolor{lightgelb}{rgb}{1,1,0.8}
\definecolor{colKeys}{rgb}{0,0,1}
\definecolor{colIdentifier}{rgb}{0,0,0}
\definecolor{colComments}{rgb}{1,0,0}
\definecolor{colString}{rgb}{0,0.5,0}
 
\usepackage{listings}
\lstset{%
    float=hbp,%
    basicstyle=\ttfamily\footnotesize, %
    identifierstyle=\color{colIdentifier}, %
    keywordstyle=\color{colKeys}, %
    stringstyle=\color{colString}, %
    commentstyle=\color{colComments}, %
    columns=flexible, %
    tabsize=2, %
    frame=single, %
    upquote=true,%
    extendedchars=true, %
    showspaces=false, %
    showstringspaces=false, %
    numbers=left, %
    numberstyle=\tiny, %
    breaklines=true, %
    backgroundcolor=\color{hellgelb}, %
    breakautoindent=true, %
    captionpos=b%
}
 
%%%%%%%%%%%%
\lstset{literate=%
    {Ö}{{\"O}}1
    {Ä}{{\"A}}1
    {Ü}{{\"U}}1
    {ß}{{\ss}}1
    {ü}{{\"u}}1
    {ä}{{\"a}}1
    {ö}{{\"o}}1
    {~}{{\textasciitilde}}1
}
 
 
 
\usepackage{pgfpages}                                 % <— load the package
\usepackage{atbegshi}
 
\newcommand{\twoonone}{% 
  \pgfpagesuselayout{2 on 1}[a4paper,landscape,border shrink=5mm] % <— set options
  % duplicate the content at shipout time
  \AtBeginShipout{%
    \pgfpagesshipoutlogicalpage{1}\copy\AtBeginShipoutBox%
    \pgfpagesshipoutlogicalpage{2}\box\AtBeginShipoutBox%
    \pgfshipoutphysicalpage%
  }}
 
 
 
\firstpageheader{WS~2018/2019}{Skriptsprachenprogrammierung}{Dr.~Uwe Ziegenhagen}
\runningheader{WS~2018/2019}{Skriptsprachenprogrammierung}{Dr.~Uwe Ziegenhagen}
\firstpagefooter{\today}{}{\thepage\,/\,\numpages}
\runningfooter{\today}{Mitte unten}{\thepage\,/\,\numpages}
 
\setlength{\parindent}{0pt}
\setlength{\parskip}{6pt}
 
 
\twoonone % two pages on one
 
\begin{document}
 
\vspace*{0.5cm}
\begin{center}
\huge\bfseries Arbeitsblatt 02: Datentypen
\end{center}
\vspace*{0.5cm}
 
\section*{Aufgaben}
 
\begin{questions}
\question Welche Datentypen kennen Sie in Python?
 
\begin{itemize}
	\item 
	\item 
	\item 
	\item 
	\item 
\end{itemize}
 
\question Erstellen Sie verschiedene Variablen mit unterschiedlichen Datentypen! Führen Sie verschiedene Grundrechenarten mit den Datentypen durch.
 
\question Satz des Pythagoras: Berechnen Sie mittels Python die Hypotenuse eines Dreiecks, dessen Katheten 3 und 4 Zentimeter lang sind. Prüfen Sie die Datentypen der Variablen mittels \texttt{type()} Funktion! Warum gibt es Unterschiede in den Typen?
 
\question Richten Sie einen String beliebiger Länge bei der Ausgabe auf der Kommandozeile rechtsbündig aus! Hinweise: Gehen Sie von einer Zeilenbreite von 60 Zeichen aus. Benutzen Sie die \texttt{len()} Funktion, um die Länge der Zeichenkette zu bestimmen.
 
\question Nutzen Sie die \texttt{int()}, \texttt{float()} und \texttt{str()} Funktion, um verschiedene Datentypen umzuwandeln!
 
\question Hier kommt ein Listing
 
\begin{lstlisting}[language={Python}]
def create_bruch():
    zahlen = list(range(1,13))
    zaehler = random.choice(zahlen)
    zahlen.remove(zaehler)
    nenner = random.choice(zahlen)
    return 1234
\end{lstlisting}
 
\end{questions}
 
\end{document}

Uwe

Uwe Ziegenhagen likes LaTeX and Python, sometimes even combined. Do you like my content and would like to thank me for it? Consider making a small donation to my local fablab, the Dingfabrik Köln. Details on how to donate can be found here Spenden für die Dingfabrik.

More Posts - Website