Wie erstellt man einen Barh-Plot mit vielen np.arrays?

mit matplotlib, NumPy, pandas, SciPy, SymPy und weiteren mathematischen Programmbibliotheken.
Antworten
unknown_sick
User
Beiträge: 3
Registriert: Dienstag 28. Januar 2020, 08:52

Ich baue eine Visualisierung mit Python auf, die tkinter, matplotlib und numpy enthält. Ich möchte mehrere Numpy-Arrays in einem Barh-Plot visualisieren. Damit ich alles in diesem einen Plot analysieren kann. In meinem vorherigen Code habe ich das nur mit Subplots geschafft. Aber ich musste immer zwei andere Subplots auskommentieren. Könnt ihr mir helfen, diese sechs Numpy-Arrays (Netflix_Beg / Ende, Youtube_Beg / Ende, Vimeo_Beg / Ende) in einem Barh-Plot zu visualisieren?

Das gewünschte Ergebnis sollte wie folgt aussehen. Dieses habe ich mit Powerpoint und meinem vorherigen Code erstellt.
Bild

Code: Alles auswählen

import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk 
import tkinter as tk
import numpy as np

fig, ax = plt.subplots(3, 1, facecolor = "white")

#data
Netflix_Beg = np.array([1,4,500,1500,2800,2960,2700, 5,2000,2000,3100,4000,4150,4150])
Netflix_End = np.array([5,1000,1000,2100,3000,3150,3150, 20,50,600,3500,3800,3960,3700])

Youtube_Beg = np.array([2,5,600,2600,3900,3970,3800, 6,3000,3000,4200,5000,5260,5260])
Youtube_End = np.array([6,2000,2000,3200,4000,4260,4260, 30,60,700,4600,4900,4070,4800])

Vimeo_Beg = np.array([0,3,400,400,1700,1850,1600,4,1000,1000,2000,3000,3040,3040])
Vimeo_End = np.array([4,500,500,1000,2000,2040,2040, 10,40,500,2400,2700,2850,2600])

Netflix = ["Netflix {}".format(i) for i in range(len(Netflix_Beg))]
Ytb = ["Youtube {}".format(i) for i in range(len(Youtube_Beg))]
Vim = ["Vimeo {}".format(i) for i in range(len(Vimeo_Beg))]

#window
root = tk.Tk()
root.title("Overview") 

#plot
Plot_Netflix = plt.barh(range(len(Netflix_Beg)),  Netflix_End-Netflix_Beg+20, 
                    left=Netflix_Beg,
                    color='#BDD7EE')

#Plot_Youtube = plt.barh(range(len(Youtube_Beg)),  Youtube_End-Youtube_Beg+20, 
#                    left=Youtube_Beg,
#                    color='#C5E0B4')
#                    
#Plot_Vimeo = plt.barh(range(len(Vimeo_Beg)),  Vimeo_End-Vimeo_Beg+20, 
#                    left=Vimeo_Beg,
#                    color="red",
#                    alpha=0.5)

plt.yticks(range(len(Netflix_Beg)), Netflix)
#plt.yticks(range(len(Youtube_Beg)), Ytb)
#plt.yticks(range(len(Vimeo_Beg)), Vim)

plt.tight_layout() 

#plot in tkinter window
canvas = FigureCanvasTkAgg(fig, master = root)
canvas.draw()
canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=True)
canvas._tkcanvas.pack(side = tk.TOP, fill = tk.BOTH, expand = True)

#plot toolbar
toolbar = NavigationToolbar2Tk(canvas, root)
toolbar.update()

root.mainloop()
Benutzeravatar
__blackjack__
User
Beiträge: 14047
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@unknown_sick: Du darfst halt nicht das globale `barh()` verwenden, woher soll das auch wissen das Du auf verschiedenen `Axis`-Objekten plotten willst statt auf dem zuletzt erstellten, sondern auf den `Axis`-Objekten die `subplots()` liefert. Das sollte auch nicht alles global auf Modulebene definiert sein, und da sind Codewiederholungen die ich in eine Funktion herausziehen würde. Die Namensschreibweisen entsprechen nicht dem Style Guide for Python Code, und auch inhaltlich sind die teilweise nicht so dolle. `Vim` ist ein Texteditor — wenn man Vimeo meint, sollte man das auch schreiben.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Benutzeravatar
__blackjack__
User
Beiträge: 14047
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Bei dem Bild das Du da hochgeladen hast stimmt die Beschriftung der X-Achse nicht, oder die Balken passen nicht zur Beschriftung bzw. nur die Balken einer Videoplattform stimmt, und für die anderen beiden ist es falsch.

Code: Alles auswählen

#!/usr/bin/env python3
import tkinter as tk
from collections import namedtuple

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.backends.backend_tkagg import (
    FigureCanvasTkAgg,
    NavigationToolbar2Tk,
)


PlatformData = namedtuple("PlatformData", "name color beginnings ends")


def main():
    platforms = [
        PlatformData(
            "Netflix",
            "#BDD7EE",
            np.array(
                [
                    1,
                    4,
                    500,
                    1500,
                    2800,
                    2960,
                    2700,
                    5,
                    2000,
                    2000,
                    3100,
                    4000,
                    4150,
                    4150,
                ]
            ),
            np.array(
                [
                    5,
                    1000,
                    1000,
                    2100,
                    3000,
                    3150,
                    3150,
                    20,
                    50,
                    600,
                    3500,
                    3800,
                    3960,
                    3700,
                ]
            ),
        ),
        PlatformData(
            "Youtube",
            "#C5E0B4",
            np.array(
                [
                    2,
                    5,
                    600,
                    2600,
                    3900,
                    3970,
                    3800,
                    6,
                    3000,
                    3000,
                    4200,
                    5000,
                    5260,
                    5260,
                ]
            ),
            np.array(
                [
                    6,
                    2000,
                    2000,
                    3200,
                    4000,
                    4260,
                    4260,
                    30,
                    60,
                    700,
                    4600,
                    4900,
                    4070,
                    4800,
                ]
            ),
        ),
        PlatformData(
            "Vimeo",
            "red",
            np.array(
                [
                    0,
                    3,
                    400,
                    400,
                    1700,
                    1850,
                    1600,
                    4,
                    1000,
                    1000,
                    2000,
                    3000,
                    3040,
                    3040,
                ]
            ),
            np.array(
                [
                    4,
                    500,
                    500,
                    1000,
                    2000,
                    2040,
                    2040,
                    10,
                    40,
                    500,
                    2400,
                    2700,
                    2850,
                    2600,
                ]
            ),
        ),
    ]

    figure, axes = plt.subplots(
        len(platforms), 1, sharex=True, facecolor="white"
    )
    for ax, platform in zip(axes, platforms):
        data_point_count = len(platform.beginnings)
        assert data_point_count == len(platform.ends)
        y_values = range(data_point_count)
        ax.barh(
            y_values,
            platform.ends - platform.beginnings + 20,
            left=platform.beginnings,
            color=platform.color,
        )
        ax.set_yticks(y_values, [f"{platform.name} {i}" for i in y_values])
    figure.tight_layout()

    root = tk.Tk()
    root.title("Overview")

    canvas = FigureCanvasTkAgg(figure, master=root)
    canvas.draw()
    canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=True)
    canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=True)

    toolbar = NavigationToolbar2Tk(canvas, root)
    toolbar.update()

    root.mainloop()


if __name__ == "__main__":
    main()
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
einfachTobi
User
Beiträge: 512
Registriert: Mittwoch 13. November 2019, 08:38

Die Hinweise von __blackjack__ gelten fast uneingeschränkt und sind zu beachten. Mit der Ausnahme, dass das globale `barh()` verwendet werden kann.
Der Doku von matpltlib.pyplot.barh kann folgendes entnommen werden:
Each of y, width, height, and left may either be a scalar applying to all bars, or it may be a sequence of length N providing a separate value for each bar.
Also machen wir das doch auch einfach so :) Hier ein Beispiel für die Umsortierung deiner Daten und den Plot:

Code: Alles auswählen

from matplotlib import pyplot as plt
import numpy as np

Netflix_Beg_data = np.array([1,4,500,1500,2800,2960,2700, 5,2000,2000,3100,4000,4150,4150])
Netflix_End_data = np.array([5,1000,1000,2100,3000,3150,3150, 20,50,600,3500,3800,3960,3700])

Youtube_Beg_data = np.array([2,5,600,2600,3900,3970,3800, 6,3000,3000,4200,5000,5260,5260])
Youtube_End_data = np.array([6,2000,2000,3200,4000,4260,4260, 30,60,700,4600,4900,4070,4800])

Vimeo_Beg_data = np.array([0,3,400,400,1700,1850,1600,4,1000,1000,2000,3000,3040,3040])
Vimeo_End_data = np.array([4,500,500,1000,2000,2040,2040, 10,40,500,2400,2700,2850,2600])

bars_netflix_left = [netflix_begin for netflix_begin in Netflix_Beg_data]
bars_netflix_width = [netflix_end - netflix_begin for netflix_begin, netflix_end in zip(Netflix_Beg_data, Netflix_End_data)]
bars_netflix_y = [f'Netflix {y}' for y in range(0, len(bars_netflix_width))]

bars_youtube_left = [youtube_begin for youtube_begin in Youtube_Beg_data]
bars_youtube_width = [youtube_end - youtube_begin for youtube_begin, youtube_end in zip(Youtube_Beg_data, Youtube_End_data)]
bars_youtube_y = [f'Youtube {y}' for y in range(0, len(bars_youtube_width))]

bars_vimeo_left = [vimeo_begin for vimeo_begin in Vimeo_Beg_data]
bars_vimeo_width = [vimeo_end - vimeo_begin for vimeo_begin, vimeo_end in zip(Vimeo_Beg_data, Vimeo_End_data)]
bars_vimeo_y = [f'Vimeo {y}' for y in range(0, len(bars_vimeo_width))]

plt.barh(y=bars_netflix_y, width=bars_netflix_width, left=bars_netflix_left)
plt.barh(y=bars_youtube_y, width=bars_youtube_width, left=bars_youtube_left)
plt.barh(y=bars_vimeo_y, width=bars_vimeo_width, left=bars_vimeo_left)
plt.show()
Dieser Code ist allerdings echt nicht gut und sollte so nicht verwendet werden, aus den von __blackjack__ genannten Gründen. Er soll lediglich aufzeigen wie dein Vorhaben grundsätzlich funktionieren kann. Man sieht deutlich die Wiederholungen, die durch Funktionen bzw. eine passende Datenstruktur ersetzt werden sollten - das musst du dann selbst erledigen.

PS: Der Plot aus deinem Bild stimmt nicht mit den übergebenen Daten überein. Das ist hier direkt auffallend, bei anderen Fragestellungen solltest du darauf achten, dass du die tatsächlich verwendeten Daten hier postest.

Edit: Da warst du wohl schneller und auch noch ausführlicher :)
Antworten