json Objekt mit Schleife erzeugen

Django, Flask, Bottle, WSGI, CGI…
Antworten
Pitwheazle
User
Beiträge: 869
Registriert: Sonntag 19. September 2021, 09:40

Ich brauche (für meine svg Datei) ein json Objekt, dass etwa so ausehen soll:
{'x1':100, 'x2':200, 'x3':300 ... und möchte dies mit einer Schleife erzeugen:

Code: Alles auswählen

 n=1
            koo = {}
            while n < 6:
                koo_n = {"x" + str(n) +":" + str(n*100)}
                koo.update(koo_n)
                n = n+1
... funktioniert natürlich nicht (hatte ich auch nicht wirklich erwartet) - aber irgendwie anders geht es wahrscheinlich schon?
Benutzeravatar
ThomasL
User
Beiträge: 1366
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Code: Alles auswählen

koo = {f"x{n}": f"{n*100}" for n in range(1,6)}
print(koo)
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Warum brauchst Du denn für Deine svg-Datei ein solch umständliches json-Objekt? Warum nicht einfach eine Liste?

Die while-Schleife ist eigentlich eine for-Schleife. Wörterbücher füllt man nicht, indem man einelementige Wörterbücher per update hinzufügt. Man setzt keine Strings per + zusammen.

Code: Alles auswählen

koo_n = {"x" + str(n) +":" + str(n*100)}
eigentlich

Code: Alles auswählen

koo_n = {f"x{n}: {n * 100}"}
ist eine Menge (Set) mit einem Element und kein Wörterbuch.
Man benutzt keine kryptischen Abkürzungen.

Code: Alles auswählen

koordinaten = {}
for n in range(1, 6):
    koordinaten[f"x{n}"] = n * 100
oder kurz:

Code: Alles auswählen

koordinaten = {
    f"x{n}": n * 100
    for n in range(1, 6)
}
ist beides aber auch falsch, weil es die falsche Datenstruktur ist.
Was Du eigentlich willst, ist eine Liste:

Code: Alles auswählen

koordinaten = [ n * 100 for n in range(1, 6)]
und mußt natürlich dein svg-Template entsprechend darauf anpassen. Was aber auch dort den Code vereinfachen dürfte.

@ThomasL: was lernt der OP aus Deiner Antwort?
Pitwheazle
User
Beiträge: 869
Registriert: Sonntag 19. September 2021, 09:40

Sirius3 hat geschrieben: Sonntag 31. Juli 2022, 14:02 Warum brauchst Du denn für Deine svg-Datei ein solch umständliches json-Objekt? Warum nicht einfach eine Liste?
Zunächst als Info: Ich erstelle gerade ein Koordinatensystem. Das muss etwas flexibel sein. Z.B. für die 5.Klässer nur mit positiven Zahlen, für die höheren Klassen auch mit negativen Zahlen.

Es ist noch nicht fertig, soll aber etwa so aussehen:
Bild
Mir ist es nicht gelungen, in der svg Datei eine Schleife zu erstellen und übergebe daher die Daten aus dem view. Das sieht jetzt schon mal so aus:

Code: Alles auswählen

  koo = {}
            for n in range(0,6):
                koo_n = {f"x{n+1}": f"{n*100+16}", f"txt{n+1}": f"{n-1}"}
                koo.update(koo_n)
            print(koo)
            grafik = {'name': 'svg/koosys.svg', 'hoehe' : 350,  'breite' : 550, 'x_achse': 300, 'y_achse': 120}
            grafik.update(koo)
... geht das auch mit einer Liste?
Sirius3 hat geschrieben: Sonntag 31. Juli 2022, 14:02 @ThomasL: was lernt der OP aus Deiner Antwort?
... mir hat der der Code von @ThomasL geholfen
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Dir hat der Code von @ThomasL nicht geholfen, weil er Dich nur in Deinem Irrweg bestärkt hat.
Um Dir sagen zu können, wie Du das mit Listen löst, brauche ich schon auch Dein svg-Template.
Ich habe nicht die Zeit, anhand Deines Bilder selbst so ein Template zu entwickeln.
Pitwheazle
User
Beiträge: 869
Registriert: Sonntag 19. September 2021, 09:40

Nun ja, funktioniert erstmal. Aber es wäre schön, wenn du mir zeigen kannst, wie das einfacher geht:

Code: Alles auswählen

<svg xmlns="http://www.w3.org/2000/svg"
    version=1.1"

    <svg viewbox="0 0 {{ grafik.breite}} {{ grafik.hoehe}}">

    <rect x="0" y="0" width={{ grafik.breite}} height={{ grafik.hoehe}} fill="white"></rect>	
    <defs>
        <pattern id="grid" patternUnits="userSpaceOnUse" width="10" height="10" x="0" y="0">
            <path d="M0,0 v10 h10" stroke="#57c4ff" fill="none" />
        </pattern>
        
        <pattern id="xduenn" x="20" y="0" width="10" height="20" patternUnits="userSpaceOnUse">
            <rect width="1" height="20">
        </pattern>
        <pattern id="xmittel" x="30" y="0" width=50 height="20" patternUnits="userSpaceOnUse">
            <rect width="1" height="25">
        </pattern>        
        <pattern id="xdick" x="30" y="0" width="100" height="20" patternUnits="userSpaceOnUse">
            <rect width="1" height="30">
        </pattern>

        <pattern id="yduenn" x="20" y="20" width="20" height="10" patternUnits="userSpaceOnUse">
            <rect width="20" height="1">
        </pattern>
        <pattern id="ymittel" x="20" y="80" width=20 height="50" patternUnits="userSpaceOnUse">
            <rect width="20" height="1">
        </pattern>        
        <pattern id="ydick" x="20" y="80" width="30" height="100" patternUnits="userSpaceOnUse">
            <rect width="30" height="1">
        </pattern>
        
        <symbol id="text" style="font-size:10px;font-family:Sans Serif, Verdana; stroke:black;stroke-width:5;fill:black">
            <text x="20" y="10"/> 
        </symbol>
    </defs>	

    <!-- Karo-Muster -->
    <rect x="0" y="0" width={{ grafik.breite}} height={{ grafik.hoehe}} fill="url(#grid)"></rect>

    <!--x-Achse-->
    <line x1=0 y1={{ grafik.x_achse}} x2={{ grafik.breite}} y2={{ grafik.x_achse}} style="stroke:black;stroke-width:1;" />
    <!--Pfeil-->
    <line x1={{ grafik.breite|add:-20}} y1={{ grafik.x_achse|add:-10}} x2={{ grafik.breite}} y2={{ grafik.x_achse}} style="stroke:black;stroke-width:2;" />	
    <line x1={{ grafik.breite|add:-20}} y1={{ grafik.x_achse|add:10}} x2={{ grafik.breite}} y2={{ grafik.x_achse}} style="stroke:black;stroke-width:2;" />	

    <!--dünne Linien-->
    <rect x=0 y={{ grafik.x_achse|add:-5}} width={{ grafik.breite}} height="10" fill="url(#xduenn)" />
    <!--dicke Linien-->
    <rect x=20 y={{ grafik.x_achse|add:-10}} width={{ grafik.breite}} height="20" fill="url(#xdick)" />
    <!--5er Linien-->
    <rect x=10 y={{ grafik.x_achse|add:-5}} width={{ grafik.breite}} height="15" fill="url(#xmittel)" />

    <text x={{ grafik.x1}} y={{ grafik.x_achse|add:25}} style="url(#text)">{{grafik.txt1}}</text>
    <text x={{ grafik.x2}} y={{ grafik.x_achse|add:25}} style="url(#text)">{{grafik.txt2}}</text>
    <text x={{ grafik.x3}} y={{ grafik.x_achse|add:25}} style="url(#text)">{{grafik.txt3}}</text>
    <text x={{ grafik.x4}} y={{ grafik.x_achse|add:25}} style="url(#text)">{{grafik.txt4}}</text>
    <text x={{ grafik.x5}} y={{ grafik.x_achse|add:25}} style="url(#text)">{{grafik.txt5}}</text>
    <text x={{ grafik.x6}} y={{ grafik.x_achse|add:25}} style="url(#text)">{{grafik.txt6}}</text> 

    <!--y-Achse-->
    <line x1={{ grafik.y_achse}} x2={{ grafik.y_achse}} y1=0 y2={{ grafik.hoehe}} style="stroke:black;stroke-width:1;" />
    <!--Pfeil-->
    <line x1={{ grafik.y_achse|add:-10}} y1 = 20 x2={{ grafik.y_achse}}  y2=0 style="stroke:black;stroke-width:2;" />	
    <line x1={{ grafik.y_achse|add:10}} Y1 = 20 x2={{ grafik.y_achse}}  y2=0 style="stroke:black;stroke-width:2;" />	

    <!--dünne Linien-->
    <rect x={{ grafik.y_achse|add:-5}}  y=20 width="10" height={{ grafik.hoehe}} fill="url(#yduenn)" />
    <!--dicke Linien-->
    <rect x={{ grafik.y_achse|add:-10}}  y=20 width="20" height={{ grafik.hoehe}} fill="url(#ydick)" />
    <!--5er Linien-->
    <rect x={{ grafik.y_achse|add:-8}}  y=20 width="16" height={{ grafik.hoehe}} fill="url(#ymittel)" />

    <!--Beschriftung-->	
    <text y={{ grafik.y1|add:30}} x={{ grafik.y_achse|add:-25}} style="url(#text)">{{grafik.tyt1}}</text>
    <text y={{ grafik.y2|add:30}} x={{ grafik.y_achse|add:-25}} style="url(#text)">{{grafik.tyt2}}</text>
    <text y={{ grafik.y3|add:30}} x={{ grafik.y_achse|add:-25}} style="url(#text)">{{grafik.tyt3}}</text>
    <text y={{ grafik.y4|add:30}} x={{ grafik.y_achse|add:-25}} style="url(#text)">{{grafik.tyt4}}</text>
    <text y={{ grafik.y5|add:30}} x={{ grafik.y_achse|add:-25}} style="url(#text)">{{grafik.tyt5}}</text>
    <text y={{ grafik.y6|add:30}} x={{ grafik.y_achse|add:-25}} style="url(#text)">{{grafik.tyt6}}</text> 
</svg>
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@Pitwheazle: da fehlen etliche Anführungszeichen und sonstige Zeichen, damit das gültiges svg wird.
`txt` als Abkürzunge für Text geht ja noch, aber was ist `tyt`?

Code: Alles auswählen

<svg xmlns="http://www.w3.org/2000/svg"
    version="1.1"
    viewbox="0 0 {{grafik.breite}} {{ grafik.hoehe}}">
    <defs>
        <pattern id="grid" patternUnits="userSpaceOnUse" width="10" height="10" x="0" y="0">
            <path d="M0,0 v10 h10" stroke="#57c4ff" fill="none" />
        </pattern>
        
        <pattern id="xduenn" x="20" y="0" width="10" height="20" patternUnits="userSpaceOnUse">
            <rect width="1" height="20" />
        </pattern>
        <pattern id="xmittel" x="30" y="0" width="50" height="20" patternUnits="userSpaceOnUse">
            <rect width="1" height="25" />
        </pattern>        
        <pattern id="xdick" x="30" y="0" width="100" height="20" patternUnits="userSpaceOnUse">
            <rect width="1" height="30" />
        </pattern>

        <pattern id="yduenn" x="20" y="20" width="20" height="10" patternUnits="userSpaceOnUse">
            <rect width="20" height="1" />
        </pattern>
        <pattern id="ymittel" x="20" y="80" width="20" height="50" patternUnits="userSpaceOnUse">
            <rect width="20" height="1" />
        </pattern>        
        <pattern id="ydick" x="20" y="80" width="30" height="100" patternUnits="userSpaceOnUse">
            <rect width="30" height="1" />
        </pattern>
        
        <symbol id="text" style="font-size:10px;font-family:Sans Serif, Verdana; stroke:black;stroke-width:5;fill:black">
            <text x="20" y="10"/> 
        </symbol>
    </defs>	

    <!-- Karo-Muster -->
    <rect x="0" y="0" width="{{grafik.breite}}" height="{{grafik.hoehe}}" fill="url(#grid)"/>

    <!--x-Achse-->
    <line x1="0" y1="{{grafik.x_achse}}" x2="{{grafik.breite}}" y2="{{grafik.x_achse}}" style="stroke:black;stroke-width:1;" />
    <!--Pfeil-->
    <line x1="{{grafik.breite|add:-20}}" y1="{{grafik.x_achse|add:-10}}" x2="{{ grafik.breite}}" y2="{{grafik.x_achse}}" style="stroke:black;stroke-width:2;" />	
    <line x1="{{grafik.breite|add:-20}}" y1="{{grafik.x_achse|add:10}}" x2="{{ grafik.breite}}" y2="{{grafik.x_achse}}" style="stroke:black;stroke-width:2;" />	

    <!-- dünne Linien-->
    <rect x="0" y="{{grafik.x_achse|add:-5}}" width="{{grafik.breite}}" height="10" fill="url(#xduenn)" />
    <!--5er Linien-->
    <rect x="10" y="{{grafik.x_achse|add:-7.5}}" width="{{grafik.breite}}" height="15" fill="url(#xmittel)" />
    <!--dicke Linien-->
    <rect x="20" y="{{grafik.x_achse|add:-10}}" width="{{grafik.breite}}" height="20" fill="url(#xdick)" />

    {%for x, txt in grafik.xvalues %}
    <text x="{{x}}" y="{{grafik.x_achse|add:25}}" style="url(#text)">{{txt}}</text>
    {%endfor%}

    <!--y-Achse-->
    <line x1="{{grafik.y_achse}}" x2="{{grafik.y_achse}}" y1="0" y2="{{grafik.hoehe}}" style="stroke:black;stroke-width:1;" />
    <!--Pfeil-->
    <line x1="{{grafik.y_achse|add:-10}}" y1="20" x2="{{grafik.y_achse}}"  y2="0" style="stroke:black;stroke-width:2;" />	
    <line x1="{{grafik.y_achse|add:10}}" y1="20" x2="{{grafik.y_achse}}"  y2="0" style="stroke:black;stroke-width:2;" />	

    <!--dünne Linien-->
    <rect x="{{ grafik.y_achse|add:-5}}"  y="20" width="10" height="{{grafik.hoehe}}" fill="url(#yduenn)" />
    <!--5er Linien-->
    <rect x="{{ grafik.y_achse|add:-7.5}}"  y="20" width="15" height="{{grafik.hoehe}}" fill="url(#ymittel)" />
    <!--dicke Linien-->
    <rect x="{{ grafik.y_achse|add:-10}}"  y="20" width="20" height="{{grafik.hoehe}}" fill="url(#ydick)" />

    {%for y, txt in grafik.yvalues %}
    <text x="{{grafik.y_achse|add:-25}}" y="{{y}}" style="url(#text)">{{txt}}</text>
    {%endfor%}
</svg>
Und der passende Python-Code:

Code: Alles auswählen

    x_achse = 300
    y_achse = 120
    grafik = {
        'name': 'svg/koosys.svg',
        'hoehe' : 350,
        'breite' : 550,
        'x_achse': x_achse,
        'y_achse': y_achse,
        'xvalues': [
            (y_achse + n*100, n) for n in range(-1, 5)
        ],
        'yvalues': [
            (x_achse - n*100, n) for n in range(-1, 5)
        ],
    }
Benutzeravatar
noisefloor
User
Beiträge: 3843
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

@Pitwheazle: was du halt immer im Hinterkopf behalten solltest: Template Engines wie die von Django oder Jinja2 sind _universell_ einsetzbar. Auch, wenn man damit bei Webanwendungen i.d.R. HTML generiert ist die Engine nicht darauf beschränkt. Grundsätzlich geht alles, was text-basiert ist und wo der Einsatz eine Template Engine Sinn macht. Du kannst damit also auch Textdateien, Markdown Dateien, SVG-Dateien etc generieren.

Gruß, noisefloor
Pitwheazle
User
Beiträge: 869
Registriert: Sonntag 19. September 2021, 09:40

Sirius3 hat geschrieben: Sonntag 31. Juli 2022, 19:24 @Pitwheazle: da fehlen etliche Anführungszeichen und sonstige Zeichen, damit das gültiges svg wird.
Ich habe festgestellt, dass es (zumindest bei mir) egal ist, ob ich die Anführungszeichen mache oder nicht. OK, ich werde sie ergänzen.
Sirius3 hat geschrieben: Sonntag 31. Juli 2022, 19:24 `txt` als Abkürzunge für Text geht ja noch, aber was ist `tyt`?
Nu ja, txt ist der Text an der x-Achse und tyt der an der y-Achse. Stört das wirklich sehr? Ich fand es originell.
noisefloor hat geschrieben: Sonntag 31. Juli 2022, 19:31 @Pitwheazle: was du halt immer im Hinterkopf behalten solltest: Template Engines wie die von Django oder Jinja2 sind _universell_ einsetzbar. Auch, wenn man damit bei Webanwendungen i.d.R. HTML generiert ist die Engine nicht darauf beschränkt. Grundsätzlich geht alles, was text-basiert ist und wo der Einsatz eine Template Engine Sinn macht. Du kannst damit also auch Textdateien, Markdown Dateien, SVG-Dateien etc generieren.
Ehrlich gesagt, fühle ich mich immer noch als totalen Anfänger und weiß nicht so recht, was ich mit diesem Tipp machen kann.

Ich hatte ja darauf hingewiesen, dass mein Koordinatensystem noch nicht fertig ist. Zwischenzeitlich gibt es zwei Versionen:
Bild
für die Älteren
Anmerkung: Hier würde ich gerne noch, ohne viel Aufwand, die Nullen am Ursprung loswerden.
und für die Jüngeren sieht es so aus:
Bild

Der Code sieht jetzt so aus:

Code: Alles auswählen

            titel = "Koordinatensystem"
            text = "Wie lauten die Koordinaten des Punktes?"
            koo = {'name': 'svg/koosys.svg'}
            if stufe<18:
                typ2 = 1
            else:
                typ2 =2
            if typ2 ==1:                                                            #nur 1.Quadrant
                for n in range(1,3):
                    koo_x = {f"x{n+1}": f"{n*100+22}", f"txt{n+1}": f"{n*10}"}
                    koo.update(koo_x)
                for n in range(1,3):
                    koo_y = {f"y{n+1}": f"{n*100-45}", f"tyt{n+1}": f"{(3-n)*10}"}
                    koo.update(koo_y)   
                x_koo = random.randint(0,27)
                y_koo = random.randint(0,26) 
                lsg = ["({0};{1})".format(x_koo, y_koo)]               
                grafik = {'hoehe' : 320,  'breite' : 350, 'x_achse': 280, 'y_achse': 30, 'x_start': 40, 'y_start': 30, 'x_koo': x_koo*10 + 30, 'y_koo': 280-(y_koo*10)}
            else:
                for n in range(0,6):
                    koo_n = {f"x{n+1}": f"{n*100+26}", f"txt{n+1}": f"{n-1}", f"y{n+1}": f"{n*100+54}", f"tyt{n+1}": f"{2-n}"}
                    koo.update(koo_n)
                x_koo = random.randint(-12,28)
                y_koo = random.randint(-15,26) 
                lsg = ["({0};{1})".format(x_koo/10, y_koo/10).replace(".", ",")]
                grafik = {'hoehe' : 450,  'breite' : 450, 'x_achse': 280, 'y_achse': 130, 'x_start': 0, 'y_start': 0, 'x_koo': x_koo*10 + 130, 'y_koo': 280-(y_koo*10)}
            grafik.update(koo)
Ich bin ganz stolz, dass das so funktioniert. Macht es wirklich Sinn, das jetzt nach @Sirius3s Vorschlag abzuändern? Ich sehe den Vorteil noch nicht.
Benutzeravatar
noisefloor
User
Beiträge: 3843
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,
Ich bin ganz stolz, dass das so funktioniert.
Das ist gut so und dein gutes Recht.

Es ist nun mal so, dass noch kein Meiter vom Himmel gefallen ist. Heißt: niemand programmiert auf Anhieb perfekt. Heißt auch: du wirst auch ziemlich sicher an den Punkt kommen, wo die Teile deines Codes weg schmeißt und neu schreibst, weil der Code dann besser, kompakter, lesbarer, ... wird. Das ist völlig normal, und das geht allen hier so.

Heißt aber auch: je eher du Tipps umsetzt (wie z.B. den von Sirius3), des weniger Code schreibst du später ggf. neu.

Im oben gezeigten Code von dir ist der 1. if-else Block überflüssig, das kannst du in einen Blok zusammenziehen.

Gruß, noisefloor
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Nochmal, weil es wirklich für das spätere Verstehen des Codes wichtig ist und um Fehler zu vermeiden: Benutze keine Abkürzungen. `koo` oder `lsg` sind unleserlich, die paar Buchstaben, die Du damit sparst, sind nicht die Probleme wert, die Du später bekommst.

Vergleiche nochmal Deinen Code mit dem Code, der übrig bleibt, wenn Du eine Liste verwendest.
Hier nur zusammenkopiert, um die Mengen besser vergleichen zu können:

Code: Alles auswählen

                for n in range(1,3):
                    koo_x = {f"x{n+1}": f"{n*100+22}", f"txt{n+1}": f"{n*10}"}
                    koo.update(koo_x)

    <text x={{ grafik.x1}} y={{ grafik.x_achse|add:25}} style="url(#text)">{{grafik.txt1}}</text>
    <text x={{ grafik.x2}} y={{ grafik.x_achse|add:25}} style="url(#text)">{{grafik.txt2}}</text>
    <text x={{ grafik.x3}} y={{ grafik.x_achse|add:25}} style="url(#text)">{{grafik.txt3}}</text>
    <text x={{ grafik.x4}} y={{ grafik.x_achse|add:25}} style="url(#text)">{{grafik.txt4}}</text>
    <text x={{ grafik.x5}} y={{ grafik.x_achse|add:25}} style="url(#text)">{{grafik.txt5}}</text>
    <text x={{ grafik.x6}} y={{ grafik.x_achse|add:25}} style="url(#text)">{{grafik.txt6}}</text> 
Und hier mit Liste:

Code: Alles auswählen

        'xvalues': [
            (y_achse + n*100, n) for n in range(-1, 5)
        ],

    {%for x, text in grafik.xvalues %}
    <text x="{{x}}" y="{{grafik.x_achse|add:25}}" style="url(#text)">{{text}}</text>
    {%endfor%}
Weniger Code bedeutet, dass Du weniger Fehler machen kannst und Änderungen einfacher umzusetzen sind. Wenn Du Beispielsweise die nötigen Anführungszeichen hinzufügen möchtest, dann ist das unten nur eine Zeile, oben aber 6 Zeilen zu ändern. Und wenn Du statt 6 mal nur 5 Labels haben möchtest, geht das oben gar nicht unten ist die Änderung minimal.
Pitwheazle
User
Beiträge: 869
Registriert: Sonntag 19. September 2021, 09:40

Mann, mann, mann, das ist ja genial.
Da habe ich Pfuscher nur mal einen Blick auf deinen Code geworfen und nicht auf Anhieb diese genialen Änderungen gesehen. Das ist ja toll - vielen Dank.
Ich zitiere mich mal selbst:
Pitwheazle hat geschrieben: Sonntag 31. Juli 2022, 15:41 Mir ist es nicht gelungen, in der svg Datei eine Schleife zu erstellen
Dann geht das ja doch (wenn man weiß, wie es geht).
Und dann hast du auch noch die ganzen Verschiebungen und Berechnungen vereinfacht!

Auch hier muss ich nochmals sagen: Danke für deine Geduld
Antworten