Einführung
In diesem Lab werden wir lernen, wie man mithilfe von Matplotlib in Python einen gepackten Blasen-Diagramm erstellt. Ein gepacktes Blasen-Diagramm ist ein Diagrammtyp, der Daten in Blasen unterschiedlicher Größen darstellt, wobei die Größe der Blase die Größe der Daten repräsentiert. Dieses Diagramm eignet sich gut zur Darstellung von skalaren Daten, wobei die Daten ein einzelner numerischer Wert sind, der einem Element zugeordnet ist.
VM-Tipps
Nachdem der VM-Start abgeschlossen ist, klicken Sie in der oberen linken Ecke, um zur Registerkarte Notebook zu wechseln und Jupyter Notebook für die Übung zu öffnen.
Manchmal müssen Sie einige Sekunden warten, bis Jupyter Notebook vollständig geladen ist. Die Validierung von Vorgängen kann aufgrund von Einschränkungen in Jupyter Notebook nicht automatisiert werden.
Wenn Sie bei der Lernphase Probleme haben, können Sie Labby gerne fragen. Geben Sie nach der Sitzung Feedback, und wir werden das Problem für Sie prompt beheben.
Importieren der erforderlichen Bibliotheken
Um ein gepacktes Blasen-Diagramm zu erstellen, müssen wir die Bibliotheken matplotlib.pyplot und numpy importieren. Die numpy-Bibliothek wird verwendet, um mathematische Operationen auf Arrays durchzuführen, was für die Berechnung der Blasengrößen nützlich ist.
import matplotlib.pyplot as plt
import numpy as np
Definieren der Daten
Die Daten, die wir für dieses Beispiel verwenden werden, sind die Marktanteile verschiedener Desktop-Browser. Wir werden die Daten als Dictionary definieren, das die Browser-Namen, den Marktanteil und die Farbe für jede Blase enthält.
browser_market_share = {
'browsers': ['firefox', 'chrome', 'safari', 'edge', 'ie', 'opera'],
'market_share': [8.61, 69.55, 8.36, 4.12, 2.76, 2.43],
'color': ['#5A69AF', '#579E65', '#F9C784', '#FC944A', '#F24C00', '#00B825']
}
Definieren der BubbleChart-Klasse
Die BubbleChart-Klasse wird verwendet, um das gepackte Blasen-Diagramm zu erstellen. Die Klasse nimmt ein Array von Blasenflächen und einen Blasenabstandswert entgegen. Die __init__-Methode setzt die Anfangspositionen der Blasen und berechnet die maximale Schrittweite, die die Entfernung ist, die jede Blase in einer einzelnen Iteration bewegen kann.
class BubbleChart:
def __init__(self, area, bubble_spacing=0):
"""
Setup for bubble collapse.
Parameters
----------
area : array-like
Fläche der Blasen.
bubble_spacing : float, Standardwert: 0
Minimaler Abstand zwischen den Blasen nach dem Zusammenfallen.
Notes
-----
Wenn "area" sortiert ist, können die Ergebnisse merkwürdig aussehen.
"""
area = np.asarray(area)
r = np.sqrt(area / np.pi)
self.bubble_spacing = bubble_spacing
self.bubbles = np.ones((len(area), 4))
self.bubbles[:, 2] = r
self.bubbles[:, 3] = area
self.maxstep = 2 * self.bubbles[:, 2].max() + self.bubble_spacing
self.step_dist = self.maxstep / 2
## berechne die Anfangs-Gitterlayout für die Blasen
length = np.ceil(np.sqrt(len(self.bubbles)))
grid = np.arange(length) * self.maxstep
gx, gy = np.meshgrid(grid, grid)
self.bubbles[:, 0] = gx.flatten()[:len(self.bubbles)]
self.bubbles[:, 1] = gy.flatten()[:len(self.bubbles)]
self.com = self.center_of_mass()
Definieren von Blasenbewegungs-Methoden
Die BubbleChart-Klasse enthält auch Methoden, um die Blasen zum Massenmittelpunkt zu bewegen und auf Kollisionen mit anderen Blasen zu prüfen. Die center_of_mass-Methode berechnet den Massenmittelpunkt aller Blasen, und die center_distance-Methode berechnet die Entfernung zwischen einer Blase und dem Massenmittelpunkt. Die outline_distance-Methode berechnet die Entfernung zwischen der Kontur einer Blase und den Konturen anderer Blasen, und die check_collisions-Methode prüft, ob eine neue Blasenposition mit anderen Blasen kollidiert.
def center_of_mass(self):
return np.average(
self.bubbles[:, :2], axis=0, weights=self.bubbles[:, 3]
)
def center_distance(self, bubble, bubbles):
return np.hypot(bubble[0] - bubbles[:, 0],
bubble[1] - bubbles[:, 1])
def outline_distance(self, bubble, bubbles):
center_distance = self.center_distance(bubble, bubbles)
return center_distance - bubble[2] - \
bubbles[:, 2] - self.bubble_spacing
def check_collisions(self, bubble, bubbles):
distance = self.outline_distance(bubble, bubbles)
return len(distance[distance < 0])
Definieren der Blasen-Kollisions-Methode
Die BubbleChart-Klasse enthält auch eine Methode, um Blasen-Kollisionen zu prüfen und kollidierende Blasen umzugehen. Die collides_with-Methode berechnet die Entfernung zwischen einer neuen Blasenposition und den Positionen anderer Blasen. Wenn die Entfernung kleiner als Null ist, bedeutet dies, dass es eine Kollision gibt, und die Methode gibt den Index der kollidierenden Blase zurück. Die collapse-Methode bewegt die Blasen zum Massenmittelpunkt und um kollidierende Blasen herum, und die plot-Methode zeichnet die Blasen auf dem Diagramm.
def collides_with(self, bubble, bubbles):
distance = self.outline_distance(bubble, bubbles)
idx_min = np.argmin(distance)
return idx_min if type(idx_min) == np.ndarray else [idx_min]
def collapse(self, n_iterations=50):
"""
Bewege Blasen zum Massenmittelpunkt.
Parameters
----------
n_iterations : int, Standardwert: 50
Anzahl der Bewegungen, die ausgeführt werden sollen.
"""
for _i in range(n_iterations):
moves = 0
for i in range(len(self.bubbles)):
rest_bub = np.delete(self.bubbles, i, 0)
## versuche, direkt zum Massenmittelpunkt zu bewegen
## Richtungsvektor von der Blase zum Massenmittelpunkt
dir_vec = self.com - self.bubbles[i, :2]
## Verkürze den Richtungsvektor, um die Länge 1 zu haben
dir_vec = dir_vec / np.sqrt(dir_vec.dot(dir_vec))
## Berechne die neue Blasenposition
new_point = self.bubbles[i, :2] + dir_vec * self.step_dist
new_bubble = np.append(new_point, self.bubbles[i, 2:4])
## Prüfe, ob die neue Blase mit anderen Blasen kollidiert
if not self.check_collisions(new_bubble, rest_bub):
self.bubbles[i, :] = new_bubble
self.com = self.center_of_mass()
moves += 1
else:
## Versuche, um eine Blase zu bewegen, mit der du kollidierst
## finde die kollidierende Blase
for colliding in self.collides_with(new_bubble, rest_bub):
## Berechne den Richtungsvektor
dir_vec = rest_bub[colliding, :2] - self.bubbles[i, :2]
dir_vec = dir_vec / np.sqrt(dir_vec.dot(dir_vec))
## Berechne den orthogonalen Vektor
orth = np.array([dir_vec[1], -dir_vec[0]])
## Teste, in welche Richtung zu gehen
new_point1 = (self.bubbles[i, :2] + orth *
self.step_dist)
new_point2 = (self.bubbles[i, :2] - orth *
self.step_dist)
dist1 = self.center_distance(
self.com, np.array([new_point1]))
dist2 = self.center_distance(
self.com, np.array([new_point2]))
new_point = new_point1 if dist1 < dist2 else new_point2
new_bubble = np.append(new_point, self.bubbles[i, 2:4])
if not self.check_collisions(new_bubble, rest_bub):
self.bubbles[i, :] = new_bubble
self.com = self.center_of_mass()
if moves / len(self.bubbles) < 0.1:
self.step_dist = self.step_dist / 2
def plot(self, ax, labels, colors):
"""
Zeichne das Blasen-Diagramm.
Parameters
----------
ax : matplotlib.axes.Axes
labels : Liste
Labels der Blasen.
colors : Liste
Farben der Blasen.
"""
for i in range(len(self.bubbles)):
circ = plt.Circle(
self.bubbles[i, :2], self.bubbles[i, 2], color=colors[i])
ax.add_patch(circ)
ax.text(*self.bubbles[i, :2], labels[i],
horizontalalignment='center', verticalalignment='center')
Erstellen eines BubbleChart-Objekts und Zeichnen des Diagramms
Um das gepackte Blasen-Diagramm zu erstellen, müssen wir ein BubbleChart-Objekt erstellen und die collapse-Methode aufrufen, um die Blasen zum Massenmittelpunkt zu bewegen. Anschließend können wir eine matplotlib-Figur erstellen und einem Axes-Objekt hinzufügen. Schließlich rufen wir die plot-Methode auf, um die Blasen auf dem Diagramm zu zeichnen.
bubble_chart = BubbleChart(area=browser_market_share['market_share'],
bubble_spacing=0.1)
bubble_chart.collapse()
fig, ax = plt.subplots(subplot_kw=dict(aspect="equal"))
bubble_chart.plot(
ax, browser_market_share['browsers'], browser_market_share['color'])
ax.axis("off")
ax.relim()
ax.autoscale_view()
ax.set_title('Browser market share')
plt.show()
Zusammenfassung
In diesem Lab haben wir gelernt, wie man mit Matplotlib in Python ein gepacktes Blasen-Diagramm erstellt. Wir haben die Daten als Dictionary definiert, das die Browser-Namen, die Marktanteile und die Farbe für jede Blase enthält. Anschließend haben wir eine BubbleChart-Klasse definiert, um die Anfangspositionen der Blasen einzurichten, die maximale Schrittweite zu berechnen, die Blasen zum Massenmittelpunkt zu bewegen und auf Kollisionen mit anderen Blasen zu prüfen. Schließlich haben wir das Diagramm mit matplotlib geplottet.