Balkendiagramm

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
flopi
User
Beiträge: 1
Registriert: Samstag 27. November 2021, 11:12

Guten Tag,
ich lerne an meiner UNI gerade Programmieren und da ich Bauingenieurwissenschaft studiere, bin ich ein kompletter Neuling in diesem Bereich. Ich habe die Aufgabe, mit einem fairen Würfel 1000-mal zu Würfeln und dabei eine zufällige Zahl 1-6 zu bekommen und die Häufigkeit auszugeben und sie in einem Balkendiagramm darzustellen. Ich habe nun alles geschafft, außer die Daten im Balkendiagramm darzustellen. Kann mir bitte jemand einen Tipp geben, wie das funktioniert?

Mein Code lautet:


from random import choice
import matplotlib.pyplot as plt

x = ("123456")

def spiel():
return choice(x)

def spielserie(n):
return [ spiel() for i in range(n) ]

def häufigkeit(werte, spiele):
for x in werte:
h = spiele.count(x)
print("Häufigkeit", x, "=", h)

ergebnisse = spielserie(1000)
häufigkeit(x, ergebnisse)



Vielen Dank im Voraus:)
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

@flopi,

zunächst sollte die Funktion 'häufigkeit' die Häufigkeiten in einer geeigneten Datenstruktur speichern und als Rückgabewert bereitstellen, um sie später an die Plot-Funktion zu übergeben.
Dafür eignen sich unter anderem eine Liste von Tupeln oder ein Dictionary:

Code: Alles auswählen

def häufigkeit(werte, spiele):
    occurences = []
    for x in werte:
        h = spiele.count(x)
        print("Häufigkeit", x, "=", h)
        occurences.append((x, h))
    return occurences
Wie man Balkendiagramme erstellt kann man auf der Beispielseite von Matplotlib lernen:
https://matplotlib.org/stable/gallery/index.html

Hier eine sehr simple Variante:

Code: Alles auswählen

from random import choice
import matplotlib.pyplot as plt

x = "123456"


def spiel():
    return choice(x)


def spielserie(n):
    return [spiel() for i in range(n)]


def häufigkeit(werte, spiele):
    occurences = []
    for x in werte:
        h = spiele.count(x)
        print("Häufigkeit", x, "=", h)
        occurences.append((x, h))
    return occurences


def create_chart(occurences):
    for x, y in occurences:
        plt.bar(x, y)
    plt.show()


def main():
    ergebnisse = spielserie(1000)
    occurences = häufigkeit(x, ergebnisse)
    create_chart(occurences)


main()

Ich weiß nicht wieso, aber aus irgendeinem Grund schwanken die Werte immer so ungefähr um den Wert 166,66.
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@flopi: Aufbauend auf der Antwort von rogerb: Funktionen (und Methoden) werden in der Regel nach der Tätigkeit benannt die sie durchführen. Damit weiss der Leser was er erwarten kann und man kann Funktionen und Methoden einfach(er) von eher passiven Werten unterscheiden. `spiel`, `spielserie`, und `häufigkeit` sind keine Tätigkeiten und der Leser würde da eher Objekte erwarten die ein Spiel, eine Serie oder eine Häufigkeit als Wert repräsentieren. Bei letzterem zum Beispiel eine ganze Zahl — eben die Häufigkeit von irgend etwas.

Einbuchstabige Namen sind in der Regel keine guten Namen und Namen sollten um so besser sein/werden, je weitreichender ihre Sichtbarkeit ist. Konstanten beispielsweise sollte man auf keinen Fall `x` nennen — es sei denn es handelt sich um einen konstanten Wert für eine X-Koordinate, was aber eher ungewöhnlich wäre. Und Konstantennamen werden per Konvention KOMPLETT_GROSS geschrieben. Ein Blick in den Style Guide for Python Code ist sinnvoll investierte Zeit.

Würfelergebnisse sind ja eigentlich Zahlen und keine Zeichen. Die Konstante mit den möglichen Ergebnissen würde ich also eher als Liste anlegen. Für die Darstellung braucht man die dann als Zeichenkette, wenn man nicht will, das `matplotlib` die Werte als Zahl behandelt. Zum Beispiel wenn man die Reihenfolge in der Darstellung selbst bestimmen möchte. Das wandelt man dann aber dort um, wo man das für die Darstellung braucht. Innerhalb eines Programms sollten Werte einen Typ haben, der zum Wert passt, und nicht einen der für die Ein- oder Ausgabe praktisch ist oder benötigt wird.

Man sollte sich bei der Namensgebung zwischen Englisch oder Deutsch entscheiden. Am besten Englisch. Das gibt weniger Probleme bei der Namensgebung von Kontainerobjekten, wo man in der Regel die Mehrzahl von dem Namen bildet, der für ein einzelnes Element sinnvoll wäre. Im Englischen ist das in der Regel ein Mehrzahl-”s” anhängen. Im Deutschen gibt es deutlich mehr Fälle von Mehrzahl ist identisch mit Einzahl, wo man sich dann irgend etwas ausdenken muss wie man mit diesen Fällen umgehen will.

Statt 6 mal `plot()` aufzurufen, würde ich das nur einmal machen, denn ich sehe bei diesem Diagramm keinen Sinn in verschiedenen Farben für die einzelnen Werte. Das ist auch unüblich für Histogramme dieser Art. Womit auch noch ein Stichwort gefallen wäre mit dem Du es Dir einfacher machen kannst: Histogramm. Ist ein verbreiteter Diagrammtyp. Da gibt's auch was von Ratio…, äh, `matplotlib` für.

Ich habe mir erlaubt die Darstellung der Würfelseiten etwas weniger langweilig zu gestalten. Eventuell muss man da die Schriftgrösse noch ein bisschen vergrössern. Und man kann natürlich generell noch ein wenig an der Darstellung von dem Diagramm schrauben. Unnötiges weg lassen, nötiges hinzufügen, weniger Platz verschwenden, eine Linie einzeichnen wo denn die Gleichverteilung wäre, und so weiter.

Code: Alles auswählen

#!/usr/bin/env python3
from random import choices

import matplotlib.pyplot as plt

DIE_VALUES = range(1, 7)


def play_games(count):
    return choices(DIE_VALUES, k=count)


def count_values(possible_values, values):
    values_and_counts = []
    for value in possible_values:
        count = values.count(value)
        print("Häufigkeit", value, "=", count)
        values_and_counts.append((value, count))
    return values_and_counts


def show_chart(values_and_counts):
    #
    # Die Würfelwerte sollen von oben nach unten aufsteigend dargestellt werden.
    #
    values_and_counts = list(reversed(values_and_counts))
    plt.barh(
        #
        # TODO Beschriftung der Würfelwerte eventuell etwas grösser machen.
        #
        [chr(ord("⚀") + (value - 1) for value, _ in values_and_counts],
        [count for _, count in values_and_counts],
    )
    plt.show()


def main():
    results = play_games(1000)
    values_and_counts = count_values(DIE_VALUES, results)
    show_chart(values_and_counts)


if __name__ == "__main__":
    main()
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Benutzeravatar
Dennis89
User
Beiträge: 1123
Registriert: Freitag 11. Dezember 2020, 15:13

Hallo,

@__blackjack__ in Zeile 31 fehlt noch die schließende Klammer von 'chr'.

Dann wird vom Interpreter der Generator bemängelt, hier (also Zeile 31) wird laut Fehlermeldung ein Integer erwartet:

Code: Alles auswählen

Traceback (most recent call last):
  File "C:\Users\Dennis\PycharmProjects\Versuche\test.py", line 44, in <module>
    main()
  File "C:\Users\Dennis\PycharmProjects\Versuche\test.py", line 40, in main
    show_chart(values_and_counts)
  File "C:\Users\Dennis\PycharmProjects\Versuche\test.py", line 31, in show_chart
    [chr(ord("⚀") + (value - 1) for value, _ in values_and_counts)],
TypeError: an integer is required (got type generator)
Nur als Info falls du gerade Lust und Zeit hast, das anzupassen. Ich sollte gerade eigentlich gar nicht hier sein :roll:

Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Dennis89: Also bei mir funktioniert das wenn ich die schliessende Klammer ergänze:

Code: Alles auswählen

#!/usr/bin/env python3
from random import choices

import matplotlib.pyplot as plt

DIE_VALUES = range(1, 7)


def play_games(count):
    return choices(DIE_VALUES, k=count)


def count_values(possible_values, values):
    values_and_counts = []
    for value in possible_values:
        count = values.count(value)
        print("Häufigkeit", value, "=", count)
        values_and_counts.append((value, count))
    return values_and_counts


def show_chart(values_and_counts):
    #
    # Die Würfelwerte sollen von oben nach unten aufsteigend dargestellt werden.
    #
    values_and_counts = list(reversed(values_and_counts))
    plt.barh(
        #
        # TODO Beschriftung der Würfelwerte eventuell etwas grösser machen.
        #
        [chr(ord("⚀") + (value - 1)) for value, _ in values_and_counts],
        [count for _, count in values_and_counts],
    )
    plt.show()


def main():
    results = play_games(1000)
    values_and_counts = count_values(DIE_VALUES, results)
    show_chart(values_and_counts)


if __name__ == "__main__":
    main()
Wenn man ein bisschen an dem Diagramm herum schraubt, könnte das beispielsweise so aussehen:
Bild
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Benutzeravatar
Dennis89
User
Beiträge: 1123
Registriert: Freitag 11. Dezember 2020, 15:13

Bei mir jetzt auch, war mein Fehler in Hektik.

Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
LeSchakal
User
Beiträge: 23
Registriert: Dienstag 5. Februar 2019, 23:40

__blackjack__ hat geschrieben: Samstag 27. November 2021, 13:27 Würfelergebnisse sind ja eigentlich Zahlen und keine Zeichen.
Würfelergebnisse sind im Grunde genommen nur Zeichen , die unterschiedlichst interpretiert werden können.
Und da in der Aufgabe nur Häufigkeiten gesucht werden, ist ein Umwandlung in Zahlen nicht erforderlich.
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@LeSchakal: Naja, Augenzahlen aufsummieren ist aber eine *sehr* verbreitete Interpretation in verschiedensten Kontexten. Im Gegensatz beispielsweise zu Postleitzahlen, die eher sehr selten sinnvoll als Zahlen verarbeitet werden. Und wenn man sie nur als Symbole sehen will/muss, ist die Frage warum es das "1" bis "6" sind und nicht "a" bis "f" oder, wie in meinem Diagramm, "⚀⚁⚂⚃⚄⚅". 🎲
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
LeSchakal
User
Beiträge: 23
Registriert: Dienstag 5. Februar 2019, 23:40

__blackjack__ hat geschrieben: Samstag 27. November 2021, 23:59 @LeSchakal: Naja, Augenzahlen aufsummieren ist aber eine *sehr* verbreitete Interpretation in verschiedensten Kontexten. Im Gegensatz beispielsweise zu Postleitzahlen, die eher sehr selten sinnvoll als Zahlen verarbeitet werden. Und wenn man sie nur als Symbole sehen will/muss, ist die Frage warum es das "1" bis "6" sind und nicht "a" bis "f" oder, wie in meinem Diagramm, "⚀⚁⚂⚃⚄⚅". 🎲
Ich wollte mit meinem Kommentar nur darauf hinweisen, dass Würfelergebnisse nicht automatisch Zahlen sind.
Was wäre beispielsweise der Erwartungswert bei Pokerwürfeln (9,10,B,D,K,A)?
Antworten