Hallo Leute,
ich möchte mit Python eine Grafik erstellen, die Daten in Kästchen angeordnet darstellen kann, so ähnlich wie es derzeit in Excel per Hand geschieht. Nachfolgend ein zufällig ähnliches Beispiel. In dieser Art sollte Text und Farbe auf zweidimensionale Koordinaten eingetragen werden. Welche Python Module würden sich dort anbieten? Die Rohdaten liegen als csv auf einem Webserver, falls das irgendeine Relevanz hat.. (ich vermute nicht)
https://i.imgur.com/4bAb0zG.png
Darstellung zweidimensionaler Daten
MorgenGrauen: 1 Welt, 8 Rassen, 13 Gilden, >250 Abenteuer, >5000 Waffen & Rüstungen,
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
- noisefloor
- User
- Beiträge: 3856
- Registriert: Mittwoch 17. Oktober 2007, 21:40
- Wohnort: WW
- Kontaktdaten:
Hallo,
für eine SVG-Grafik brauchst du nicht nicht mal ein Modul. Schnelles Beispiel mit 100x100px großen Quadraten:
CSV-Datei:
Python-Code:
Könnte man sicherlich noch übersichtlicher formatieren...
Gruß, noisefloor
für eine SVG-Grafik brauchst du nicht nicht mal ein Modul. Schnelles Beispiel mit 100x100px großen Quadraten:
CSV-Datei:
Code: Alles auswählen
"foo|green";"bar|red";"spam|blue"
"egg|blue";"hello|white";"world|purple"
"pyhton|green";"java|grey";"erlang|yellow"
Code: Alles auswählen
import csv
svg = []
with open('square_input.csv') as f:
csv_reader = csv.reader(f, delimiter=';', quotechar='"')
for linecount, row in enumerate(csv_reader):
if linecount==0:
square_size = len(row)
svg.append('<svg xmlns="http://www.w3.org/2000/svg" width="{0}" height="{0}">'.format(square_size*100))
for item_count, item in enumerate(row):
text, color = item.split('|')
entry = '''<g>
<rect fill="{}" x="{}" y="{}" width="100" height="100"></rect>
<text x="{}" y="{}" fill="black" text-anchor="middle" alignment-baseline="central">{}</text>
</g>'''.format(color, item_count*100, linecount*100, item_count*100+50, linecount*100+50, text)
svg.append(entry)
svg.append('</svg>')
with open('svg_square.svg', 'w') as out_file:
out_file.write(''.join(svg))
Gruß, noisefloor
@noisefloor: wobei hier gilt: SVG ist XML und sollte auch so geschrieben werden, mit Hilfe von ElementTree. Bei entsprechenden Zeichen im Text fliegt Dir das sonst um die Ohren.
Code: Alles auswählen
import csv
import xml.etree.ElementTree as et
SVGNS = "{http://www.w3.org/2000/svg}"
def generate_rect(item, row, column):
text, color = item.split('|')
result = et.Element(SVGNS+'g')
et.SubElement(result, SVGNS+'rect',
y=str(row*100), x=str(column*100),
width="100" height="100", fill=color)
et.SubElement(result, SVGNS+'text',
y=str(row*100 + 50), x=str(column*100 + 50),
fill="black").text = text
)
return result
def generate_svg(rows):
result = et.Element(SVGNS + svg)
for row, items in enumerate(rows):
square_size = len(row)
for column, item in enumerate(items):
result.append(generate_rect(item, row, column))
result.attrib['width'] = str(square_size*100)
result.attrib['height'] = str(square_size*100)
return result
def main():
with open('square_input.csv') as f:
csv_reader = csv.reader(f, delimiter=';', quotechar='"')
svg = generate_svg(csv_reader)
with open('svg_square.svg', 'w') as out_file:
doc = ElementTree(svg)
doc.write(out_file)
if __name__ == '__main__':
main()
- noisefloor
- User
- Beiträge: 3856
- Registriert: Mittwoch 17. Oktober 2007, 21:40
- Wohnort: WW
- Kontaktdaten:
Hallo,
Gruß, noisefloor
Stimmt, das ist mir dann später auch noch eingefallen, dass das mit Etree robuster ist.obei hier gilt: SVG ist XML und sollte auch so geschrieben werden, mit Hilfe von ElementTree
Gruß, noisefloor
Danke für die eure raschen Antworten und beispielhaften Codes!
Pillow/PIL habe ich mir etwas angesehen, kenne ich bisher noch nicht. Dort fand ich aber hauptsächlich Funktionen, um Bilder zu öffnen, bearbeiten, usw. Weniger um sie aus strukturierten Daten selbst zu erstellen. Habe auch keine Beispiele gefunden, die so etwas damit tun. Hingegen die Codes aus dem Tutorial waren gar nicht in sich lauffähig, mehr Schnipsel. Da hatte ich noch keine Zeit mich genauer einzuwühlen, bis die zweite Antwort kam.
SVG finde ich eine sehr spannende Idee! Ich wusste gar nicht, dass das einfache Textdateien sind. Super! Für die Umwandlung von SVG nach PNG könnte ich dann ja doch noch mal auf PIL zurückgreifen, oder gibt's da lohnendere Wege?
Der Beispielcode von SIrius konnte bei mir nicht ausgeführt werden. Ich muss da noch genauer die Dokumentation lesen und verstehen, bis ich die gewünschte Logik selbst reparieren kann. Manches habe ich repariert bekommen, aber eben nicht alles:
Zeile 11: Komma fehlt, ok.
Zeile 14: Klammer unerwartet. Schon kniffliger, da ich ElementTree auch noch nicht kenne. Vermutlich aber analog Zeile 11 gemeint, eben mit text statt fill. Wobei dann lustigerweise nur text=text stehen bleibt, aber das hat wohl mit Scoping zu tun)
Zeile 19: svg ist unbekannt. Vermutlich ist hier "svg" gemeint?
Zeile 21: len(row) ist nicht definiert, row ist nur eine Zahl. Ist len(rows) gemeint? Macht aber mehr Sinn außerhalb der Schleife..? Oder geht es sinnvollerweise eher um len(items)? Eine andere Interpretation habe ich nicht gefunden, muss die Formeln genauer prüfen, wo das dann angewandt wird.
Zeile 33: Hier fehlt et. vor ElementTree
Letztendlich wird eine Datei erzeugt, aber noch nicht der Text ins Feld geschrieben.
Ansonsten wie gesagt schon ein sehr spannender Ansatz. Ich werde mal die 100 als magische Zahl in eine globale Konstante herausziehen, und mich weiter in SVG und ElementTree einlesen, welche Möglichkeiten sich noch bieten. Beispielsweise überlappt sich bestimmt Text aus mehreren Kästchen, wenn die kleiner dimensioniert sind, das sollte ggf. unterdrückt werden. Ob dann letztendlich überhaupt PNG benötigt wird, muss ich noch mal abklären.
Pillow/PIL habe ich mir etwas angesehen, kenne ich bisher noch nicht. Dort fand ich aber hauptsächlich Funktionen, um Bilder zu öffnen, bearbeiten, usw. Weniger um sie aus strukturierten Daten selbst zu erstellen. Habe auch keine Beispiele gefunden, die so etwas damit tun. Hingegen die Codes aus dem Tutorial waren gar nicht in sich lauffähig, mehr Schnipsel. Da hatte ich noch keine Zeit mich genauer einzuwühlen, bis die zweite Antwort kam.
SVG finde ich eine sehr spannende Idee! Ich wusste gar nicht, dass das einfache Textdateien sind. Super! Für die Umwandlung von SVG nach PNG könnte ich dann ja doch noch mal auf PIL zurückgreifen, oder gibt's da lohnendere Wege?
Der Beispielcode von SIrius konnte bei mir nicht ausgeführt werden. Ich muss da noch genauer die Dokumentation lesen und verstehen, bis ich die gewünschte Logik selbst reparieren kann. Manches habe ich repariert bekommen, aber eben nicht alles:
Zeile 11: Komma fehlt, ok.
Zeile 14: Klammer unerwartet. Schon kniffliger, da ich ElementTree auch noch nicht kenne. Vermutlich aber analog Zeile 11 gemeint, eben mit text statt fill. Wobei dann lustigerweise nur text=text stehen bleibt, aber das hat wohl mit Scoping zu tun)
Zeile 19: svg ist unbekannt. Vermutlich ist hier "svg" gemeint?
Zeile 21: len(row) ist nicht definiert, row ist nur eine Zahl. Ist len(rows) gemeint? Macht aber mehr Sinn außerhalb der Schleife..? Oder geht es sinnvollerweise eher um len(items)? Eine andere Interpretation habe ich nicht gefunden, muss die Formeln genauer prüfen, wo das dann angewandt wird.
Zeile 33: Hier fehlt et. vor ElementTree
Letztendlich wird eine Datei erzeugt, aber noch nicht der Text ins Feld geschrieben.
Ansonsten wie gesagt schon ein sehr spannender Ansatz. Ich werde mal die 100 als magische Zahl in eine globale Konstante herausziehen, und mich weiter in SVG und ElementTree einlesen, welche Möglichkeiten sich noch bieten. Beispielsweise überlappt sich bestimmt Text aus mehreren Kästchen, wenn die kleiner dimensioniert sind, das sollte ggf. unterdrückt werden. Ob dann letztendlich überhaupt PNG benötigt wird, muss ich noch mal abklären.
MorgenGrauen: 1 Welt, 8 Rassen, 13 Gilden, >250 Abenteuer, >5000 Waffen & Rüstungen,
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
Alles Quatsch, einfach Klammer aus Zeile 15 weg, dann passt's schon so, und der Text wird auch ins Feld geschrieben.Kebap hat geschrieben: Zeile 14: Klammer unerwartet. Schon kniffliger, da ich ElementTree auch noch nicht kenne. Vermutlich aber analog Zeile 11 gemeint, eben mit text statt fill. Wobei dann lustigerweise nur text=text stehen bleibt, aber das hat wohl mit Scoping zu tun)
Insgesamt lande ich dann hier:
Code: Alles auswählen
import csv
import xml.etree.ElementTree as et
SVGNS = "{http://www.w3.org/2000/svg}"
SIZE = 100
def generate_rect(item, row, column):
text, color = item.split('|')
result = et.Element(SVGNS+'g')
et.SubElement(result, SVGNS+'rect',
y=str(row*SIZE), x=str(column*SIZE),
width=str(SIZE), height=str(SIZE), fill=color)
et.SubElement(result, SVGNS+'text',
y=str(row*SIZE + SIZE/2), x=str(column*SIZE + SIZE/2),
fill='black').text = text
return result
def generate_svg(rows):
result = et.Element(SVGNS + 'svg')
for row, items in enumerate(rows):
square_size = len(items)
for column, item in enumerate(items):
result.append(generate_rect(item, row, column))
result.attrib['width'] = str(square_size*SIZE)
result.attrib['height'] = str(square_size*SIZE)
return result
def main():
filename_in = 'square_input.csv'
filename_out = 'svg_square.svg'
with open(filename_in) as f:
csv_reader = csv.reader(f, delimiter=';', quotechar='"')
svg = generate_svg(csv_reader)
with open(filename_out, 'w') as out_file:
doc = et.ElementTree(svg)
doc.write(out_file)
if __name__ == '__main__':
main()
noisefloor hatte die folgenden Parameter angegeben, um den Text zu zentrieren: text-anchor='middle' und alignment-baseline="central"
Wenn ich diese bei SubElement übergeben will, wird das Minuszeichen als Rechenoperation missverstanden. Was tun?
MorgenGrauen: 1 Welt, 8 Rassen, 13 Gilden, >250 Abenteuer, >5000 Waffen & Rüstungen,
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
- noisefloor
- User
- Beiträge: 3856
- Registriert: Mittwoch 17. Oktober 2007, 21:40
- Wohnort: WW
- Kontaktdaten:
Hallo,
das `text-anchor="middle" alignment-baseline="central"` habe ich übrigens aus einem Thread bei SO gefunden, als ich nach Zentrierung von Text in SVG-Grafiken gesucht habe. Sind aber beides gültige Attribute lt. MDN Doku.
Gruß, noisefloor
das `text-anchor="middle" alignment-baseline="central"` habe ich übrigens aus einem Thread bei SO gefunden, als ich nach Zentrierung von Text in SVG-Grafiken gesucht habe. Sind aber beides gültige Attribute lt. MDN Doku.
Gruß, noisefloor
- noisefloor
- User
- Beiträge: 3856
- Registriert: Mittwoch 17. Oktober 2007, 21:40
- Wohnort: WW
- Kontaktdaten:
Hallo,
das geht mit PIL (bzw. Pillow) auch ganz einfach, ein Minibeispiel mit nur einem Quadrat:
Gruß, noisefloor
das geht mit PIL (bzw. Pillow) auch ganz einfach, ein Minibeispiel mit nur einem Quadrat:
Code: Alles auswählen
from PIL import Image, ImageFont, ImageDraw
font = ImageFont.truetype('FreeMono.ttf', 14, encoding='unic')
img = Image.new('RGBA', (200, 200), 'white')
draw = ImageDraw.Draw(img)
draw.rectangle(((0, 0), (100, 100)), fill='yellow')
text = 'python'
text_size = font.getsize(text)
draw.text(((100-text_size[0])/2, (100-text_size[1])/2), text,
font=font, fill='black')
img.save('square.png', 'PNG')
Das ist schon fast Poesie...noisefloor hat geschrieben:Code: Alles auswählen
draw = ImageDraw.Draw(img)
Danke, genau so was hat gefehlt. Werde ich auch mal ausprobieren!
MorgenGrauen: 1 Welt, 8 Rassen, 13 Gilden, >250 Abenteuer, >5000 Waffen & Rüstungen,
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.