Posts tagged ‘Python’

Umlaute rendern mit jinja2

Vor kurzem bin ich gefragt worden, wie man mit jinja2 Umlaute rendern kann. Grundsätzlich hatte ich auch angenommen, dass dies wegen Unicode und so kein Problem sein kann, konnte aber das aufgetretene Problem „öäüÖÜÄ,“ nachstellen.

Die Lösung war dann die folgende:

from jinja2 import Environment, BaseLoader
 
myString = 'öäü{{hello}}'
 
template = Environment(loader=BaseLoader).from_string(myString)
 
with open('render2.tex','wb') as output:
    x = template.render(hello='ÖÜÄ')
    output.write(x.encode('utf-8'))

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

Historisierung von Tabellen mit Python

Ich bin aktuell dabei, mich mehr in die Anwendungsprogrammierung mit Python einzuarbeiten. Irgendwann läuft es auf ein MVC-Framework hinaus, bis dahin ist erst einmal Experimentieren angesagt. Das folgende Beispiel legt eine SQLite In-Memory Datenbank an, fügt einige Datensätze ein und ändert einen der Datensätze ab. Die Anpassungen werden dabei historisiert über das Validfrom and Validto.

import toml # handle toml files
import sqlite3
from datetime import datetime
import time
 
 
settings = toml.load('settings.toml')
dbfilename = settings['dbfilename'] 
 
conn = sqlite3.connect(":memory:")
c = conn.cursor()
 
with conn:
    c.execute(
        """
    create table if not exists
        contacts (id integer primary key, 
                  personid integer, 
                  validfrom text, 
                  validto text,
                  firstname text,
                  lastname text,
                  phonenumber text);
    """
    )
 
    now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
 
    c.execute(f"INSERT INTO contacts (personid, validfrom, validto, firstname, lastname, phonenumber) values (1,'{now}','9999-12-31 23:59:59','Mickey','Mouse','0123-456')")
    c.execute(f"INSERT INTO contacts (personid, validfrom, validto, firstname, lastname, phonenumber) values (2,'{now}','9999-12-31 23:59:59','Donald','Duck','0123-123')")
 
    time.sleep(6)
    now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
 
    c.execute(f"UPDATE contacts set validto = '{now}' where id = 1")
 
    time.sleep(6)
    now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
 
    c.execute(f"INSERT INTO contacts (personid, validfrom,validto, firstname, lastname, phonenumber) values (1, '{now}','9999-12-31 23:59:59','Mickey','Mouse','0123-789')")
 
 
    result = c.execute(f"select * from contacts where validto > '2023-12-31';").fetchall()
 
    for row in result:
        print(row)

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

Aus Python heraus Pakete installieren

import pip
 
def install(package):
    if hasattr(pip, 'main'):
        pip.main(['install', package])
    else:
        pip._internal.main(['install', package])
 
 
# Beispiel für spyder ide
if __name__ == '__main__':
    install('spyder')

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 mehrfache Leerzeichen durch ein einziges ersetzen

Der folgende Trick hat mir einige Klimmzüge erspart. In einer Textdatei gab es an diversen Stellen mehrfache Leerzeichen, die ich durch ein einzelnes ersetzen wollte.

Ich hätte jetzt einfach so lange doppelte Leerzeichen durch ein einzelnes ersetzen können, bis keine doppelten Leerzeichen mehr vorhanden sind, über einen regular expression geht es aber viel eleganter.

import re
 
s = 'a     b     c'
 
print(re.sub('\s+',' ',s))

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

Klammern in Cognos-Reports zählen

Ich hatte vor kurzem das Problem (oder die „Challenge“), einen sehr komplexen Cognos-Report anpassen zu müssen. In mehreren dutzend Formeln mussten Formeln angepasst werden, den Formel-Check zur Prüfung meiner Anpassungen konnte ich jedoch nicht nutzen, da die Datenüberprüfung unendlich lang gedauert hätte (schlechtes Report-Design…).

Mit Python gab es aber eine einfache und elegante Lösung, die mit dem Export des Report-Designs in eine XML-Datei begann.
In der XML-Datei fanden sich dann Schnipsel wie

<expression>abs(total((if ([Database].[storedProc].[ColumnID]=6) then ([Database].[storedProc].[Amount]) else (0))))</expression>

Mit dem folgenden Programm-Code konnte ich dann innerhalb der expression-Tags einfach die öffnenden und schließenden Klammern zählen. Wenn die Zahl der öffnenden Klammern nicht der Zahl der schließenden Klammern entsprach, war die Formel noch falsch.

import re
buffer = open('./Report.xml','r').read()
 
results = re.findall(r"(<expression>)(.*)(</expression>)",buffer,re.MULTILINE)
 
for result in results:
    expression = result[1]
    opened = expression.count('(')
    closed = expression.count(')')
 
    if opened != closed:
        print(expression)

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

Stammdaten prüfen mit Python und Levenshtein

Nehmen wir mal an, wir haben eine Excel-Datei Daten.xlsx mit Namen, in der es Fehleingaben durch beispielsweise einen Buchstabendreher geben kann:

Mit Python und dem Levenshtein-Paket können wir die Ähnlichkeit der Namen recht einfach prüfen.

import pandas as pd
import Levenshtein
 
df = pd.read_excel('Daten.xlsx')
df = df.sort_values(by=['Name'])
df = df.reset_index(drop=True)
 
dfs= df.shift() # Shift df by one row
dfs = dfs.rename(columns={'Name': 'Nameshifted'})
 
df_combined = pd.concat([df,dfs],axis=1) # combine original and shifted df
df_combined = df_combined.fillna('') # remove NaNs
 
for index, row in df_combined.iterrows():
    df_combined.loc[index,'Ratio'] = (Levenshtein.ratio(row['Name'], row['Nameshifted']))
    df_combined.loc[index,'Distance'] = (Levenshtein.distance(row['Name'], row['Nameshifted']))    
 
print(df_combined)

Als Ergebnis erhält man dann einen Dataframe, der die sortierten Namen miteinander vergleicht und die Levenshtein-Ratio sowie die Levenshtein-Distanz ausgibt.

Name Nameshifted Ratio Distance
0 Ambacher 0.000000 8.0
1 Bertram Ambacher 0.266667 8.0
2 Cderick Bertram 0.285714 6.0
3 Cedrick Cderick 0.857143 2.0
4 Dorn Cedrick 0.181818 6.0
5 Elba Dorn 0.000000 4.0
6 Friedrich Elba 0.000000 9.0
7 Gastav Friedrich 0.000000 9.0
8 Gustav Gastav 0.833333 1.0
9 Horn Gustav 0.000000 6.0
10 Immenweg Horn 0.166667 7.0
11 Klaas Immenweg 0.000000 8.0
12 Klaus Klaas 0.800000 1.0

Bei hoher Ratio oder kleiner Distanz sollte man sich die Werte anschauen.

Hinweis: Ich bin hier davon ausgegangen, dass nur im Namen der nächsten Zeile ein Dreher auftreten kann. Vergleicht man alle n Namen mit allen anderen n-1 Namen, so wird es schnell aufwändig und zeitintensiv.

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

Dateien in Unterverzeichnissen clever umbenennen mit Python

Hier noch ein weiteres Beispiel, wie man sich mit Python sinnlose manuelle Arbeiten erleichtern kann. Gegeben sei die folgende Verzeichnisstruktur:

Verzeichnis1
 Ordner1
  Unterordner1
   Willich.txt
 Ordner2
  Unterordner2
   Willich.txt
 Ordner3
  Unterordner3
   Willich.txt

Die in den Ordnern liegenden Dateien sind alle gleich benannt (trotz unterschiedlicher Inhalte), sollen aber für die weitere Verarbeitung in einen Ordner verschoben werden. Man kann sie jetzt manuell nach dem Schema „Ordnerx-Unterordnerx-Dateiname“ umbenennen, man kann es aber auch lassen und ein kurzes Python-Skript dazu schreiben. Spätestens bei 20 oder 30 Dateien lohnt sich der Aufwand der initialen Entwicklung, das Beispiel lässt sich auch leicht auf andere Aufgaben übertragen. Die folgende Python-Datei speichert man in „Verzeichnis1“, dieses Verzeichnis bildet dann den root-Pfad. Der Rest ist dann einfach nur cleveres Auswerten des Pfades und das Wechseln der Backslashes in Unterstriche, um den neuen Pfad zu bauen.

import os
 
for (root,dirs,files) in os.walk('.'):
 
    for file in files:
        fullpath = os.path.join(root,file)
 
        if fullpath.endswith('.txt'):
            newpath = root+'\\'+root[2:].replace('\\','_')+'_'+file
            print(newpath)
            os.rename(fullpath, newpath)

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

Lineare Funktionen plotten mit matplotlib

Hier ein kurzes Beispiel, wie man mit matplotlib Funktionen plotten kann.

import matplotlib.pyplot as plt
import numpy as np
 
ax = plt.gca()
plt.gca().set_aspect('equal')
 
ax.set_xticks(range(-6,6,1))
ax.set_yticks(range(-6,6,1))
ax.set_xlim([-5, 5])
ax.set_ylim([-5, 5])
 
ax.spines['top'].set_color('none')
ax.spines['bottom'].set_position('zero')
ax.spines['left'].set_position('zero')
ax.spines['right'].set_color('none')
 
x = np.linspace(-5,5,100)
y = 2*x+1
y2 = -0.5*x-2
 
plt.plot(x, y,  'r', label='2*x+1')
plt.plot(x, y2, 'g', label='-0.5*x-2')
 
plt.title('Linear Plots')
 
plt.legend(loc='upper left')
 
plt.grid()
plt.show()

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

XML-Dateien mit Python, pandas und Jinja2 befüllen

Angenommen, wir haben eine Excel-Datei Daten.xlsx mit Werten, die in ein entsprechendes XML-Dokument überführt werden müssen.

Mit Python und der Jinja2 Template-Engine ist das flink gemacht. Zuerst definieren wir das Template template.xml:

<?xml version='1.0' encoding='UTF-8'?>
	<table name="Tablename">
	{% for _,row in data.iterrows() %}
	<ROW>
    <COLUMN1>{{row['column1']}}</COLUMN1>
    <COLUMN2>{{row['column2']}}</COLUMN2>
    <COLUMN3>{{row['column3']}}</COLUMN3>
	</ROW>
	{% endfor %}
</table>

Dann definieren wir den Python-Code:

import pandas as pd # data wrangling
import jinja2 # template engine
import os # for file-related stuff
 
# create jinja env that can load template from filesystem
jinja_env = jinja2.Environment(loader = jinja2.FileSystemLoader(os.path.abspath('.')))
 
df = pd.read_excel('Daten.xlsx')
template = jinja_env.get_template('template.xml')
 
with open('FertigesXML.xml','w') as output:
    output.write(template.render(data=df))

Lassen wir den Python-Code laufen, so erhalten wir das folgende XML:

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

CSV-Dateien effizient vergleichen mit pandas

Hier ein bisschen Python-Code, um zwei CSV Dateien miteinander zu vergleichen. Die Ergebnisse des spalten- und zeilenweisen Vergleichs werden dann zusammengefasst dargestellt, um schnell einen Überblick zu bekommen, wo eine tiefergehende Analyse notwendig ist.

import sys
import collections
import pandas as pd
from tabulate import tabulate
 
 
file1 = pd.read_csv('file1.csv', sep=';', encoding='UTF-8')
file2 = pd.read_csv('file2.csv', sep=';', encoding='UTF-8')
 
columnnames1 = list(file1)
columnnames2 = list(file2)
 
if collections.Counter(columnnames1) == collections.Counter(columnnames2):
    print ("Number of columns and Names match, Comparison possible...\n\n")
else:
    print ("Number of columns and Names are not matching!!! Please check the input!")
    sys.exit('Error!')
 
# add suffixes to distinguish between actual and expected in the merger
file1 = file1.add_suffix('_e') # expected
file2 = file2.add_suffix('_t') # t
 
 
# merge them using the given key, use outer join
comparison = pd.merge(file1,file2, how='outer',
                      left_on=['Key_e'],
                      right_on=['Key_t'])
 
# create the columnwise comparison
for col in columnnames1:
    comparison[(col + '_c')] = comparison[(col + '_t')] == comparison[(col + '_e')]
 
# reorder the columns
comparison=comparison.reindex(sorted(comparison.columns),axis=1)
 
print(tabulate(comparison, tablefmt="pipe", headers="keys"))
 
 
# save the result as Excel file
comparison.to_excel('result.xlsx')
 
# names of the comparison column
check_colnames= [s + '_c' for s in columnnames1]
 
# initialize an empty dataframe for the log
logdf=pd.DataFrame(index=[True,False])
 
for column in check_colnames:
    t=comparison[column].value_counts() # returns a series
    tt=pd.DataFrame(t) # makes a DF out of the series
    logdf = logdf.join(tt,how='outer') # join the two dfs
 
# transpose for better readability
logdf = logdf.transpose()
 
# Ensure fixed sequence of the columns
logdf=logdf.reindex(sorted(logdf.columns),axis=1)
 
# write to disk
logdf.to_excel('logfile.xlsx')
 
# for better viewing on the screen
logdf.fillna('-',inplace=True)
pd.options.display.float_format = '{:,.0f}'.format
 
print(tabulate(logdf, tablefmt="pipe", headers="keys"))

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