Créer des graphiques à bulles empaquetées avec Python

Beginner

This tutorial is from open-source community. Access the source code

Introduction

Dans ce laboratoire, nous allons apprendre à créer un graphique à bulles empaquetées à l'aide de Matplotlib en Python. Le graphique à bulles empaquetées est un type de graphique qui affiche des données dans des bulles de différentes tailles, la taille de la bulle représentant l'amplitude des données. Ce graphique est utile pour afficher des données scalaires, où les données sont une seule valeur numérique associée à un élément.

Conseils sur la machine virtuelle

Une fois le démarrage de la machine virtuelle terminé, cliquez dans le coin supérieur gauche pour basculer vers l'onglet Carnet d'adresses pour accéder à Jupyter Notebook pour la pratique.

Parfois, vous devrez peut-être attendre quelques secondes pour que Jupyter Notebook ait fini de charger. La validation des opérations ne peut pas être automatisée en raison des limitations de Jupyter Notebook.

Si vous rencontrez des problèmes pendant l'apprentissage, n'hésitez pas à demander à Labby. Donnez des commentaires après la session, et nous résoudrons rapidement le problème pour vous.

Importation des bibliothèques requises

Pour créer un graphique à bulles empaquetées, nous devons importer les bibliothèques matplotlib.pyplot et numpy. La bibliothèque numpy est utilisée pour effectuer des opérations mathématiques sur des tableaux, ce qui est utile pour calculer les tailles des bulles.

import matplotlib.pyplot as plt
import numpy as np

Définir les données

Les données que nous utiliserons pour cet exemple sont les parts de marché des différents navigateurs de bureau. Nous définirons les données comme un dictionnaire contenant les noms des navigateurs, les parts de marché et la couleur de chaque bulle.

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']
}

Définir la classe BubbleChart

La classe BubbleChart est utilisée pour créer le graphique à bulles empaquetées. La classe prend en entrée un tableau des aires des bulles et une valeur d'espacement entre les bulles. La méthode __init__ configure les positions initiales des bulles et calcule la distance maximale de déplacement, qui est la distance que chaque bulle peut parcourir en une seule itération.

class BubbleChart:
    def __init__(self, area, bubble_spacing=0):
        """
        Configuration pour l'effondrement des bulles.

        Paramètres
        ----------
        area : array-like
            Aire des bulles.
        bubble_spacing : float, valeur par défaut : 0
            Espacement minimal entre les bulles après effondrement.

        Notes
        -----
        Si "area" est trié, les résultats peuvent sembler étranges.
        """
        area = np.asarray(area)
        r = np.sqrt(area / np.pi)

        self.bubble_spacing = bubble_spacing
        self.bulles = np.ones((len(area), 4))
        self.bulles[:, 2] = r
        self.bulles[:, 3] = area
        self.maxstep = 2 * self.bulles[:, 2].max() + self.bubble_spacing
        self.step_dist = self.maxstep / 2

        ## calculer la disposition initiale en grille pour les bulles
        length = np.ceil(np.sqrt(len(self.bulles)))
        grille = np.arange(length) * self.maxstep
        gx, gy = np.meshgrid(grille, grille)
        self.bulles[:, 0] = gx.flatten()[:len(self.bulles)]
        self.bulles[:, 1] = gy.flatten()[:len(self.bulles)]

        self.com = self.center_of_mass()

Définir les méthodes de mouvement des bulles

La classe BubbleChart contient également des méthodes pour déplacer les bulles vers le centre de masse et vérifier s'il y a des collisions avec d'autres bulles. La méthode center_of_mass calcule le centre de masse de toutes les bulles, et la méthode center_distance calcule la distance entre une bulle et le centre de masse. La méthode outline_distance calcule la distance entre la périphérie d'une bulle et les périphéries d'autres bulles, et la méthode check_collisions vérifie si une nouvelle position de bulle entre en collision avec d'autres bulles.

    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])

Définir la méthode de collision des bulles

La classe BubbleChart contient également une méthode pour vérifier les collisions entre les bulles et déplacer les bulles en collision. La méthode collides_with calcule la distance entre une nouvelle position de bulle et les positions des autres bulles. Si la distance est inférieure à zéro, cela signifie qu'il y a une collision, et la méthode renvoie l'index de la bulle en collision. La méthode collapse déplace les bulles vers le centre de masse et autour des bulles en collision, et la méthode plot trace les bulles sur le graphique.

    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):
        """
        Déplace les bulles vers le centre de masse.

        Paramètres
        ----------
        n_iterations : int, valeur par défaut : 50
            Nombre de mouvements à effectuer.
        """
        for _i in range(n_iterations):
            moves = 0
            for i in range(len(self.bulles)):
                rest_bulles = np.delete(self.bulles, i, 0)
                ## essayez de vous déplacer directement vers le centre de masse
                ## vecteur direction de la bulle vers le centre de masse
                dir_vec = self.com - self.bulles[i, :2]

                ## raccourcir le vecteur direction pour qu'il ait une longueur de 1
                dir_vec = dir_vec / np.sqrt(dir_vec.dot(dir_vec))

                ## calculer la nouvelle position de la bulle
                new_point = self.bulles[i, :2] + dir_vec * self.step_dist
                new_bulle = np.append(new_point, self.bulles[i, 2:4])

                ## vérifiez si la nouvelle bulle entre en collision avec d'autres bulles
                if not self.check_collisions(new_bulle, rest_bulles):
                    self.bulles[i, :] = new_bulle
                    self.com = self.center_of_mass()
                    moves += 1
                else:
                    ## essayez de vous déplacer autour d'une bulle avec laquelle vous entrez en collision
                    ## trouver la bulle en collision
                    for colliding in self.collides_with(new_bulle, rest_bulles):
                        ## calculer le vecteur direction
                        dir_vec = rest_bulles[colliding, :2] - self.bulles[i, :2]
                        dir_vec = dir_vec / np.sqrt(dir_vec.dot(dir_vec))
                        ## calculer le vecteur orthogonal
                        orth = np.array([dir_vec[1], -dir_vec[0]])
                        ## tester dans quelle direction aller
                        new_point1 = (self.bulles[i, :2] + orth *
                                      self.step_dist)
                        new_point2 = (self.bulles[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_bulle = np.append(new_point, self.bulles[i, 2:4])
                        if not self.check_collisions(new_bulle, rest_bulles):
                            self.bulles[i, :] = new_bulle
                            self.com = self.center_of_mass()

            if moves / len(self.bulles) < 0.1:
                self.step_dist = self.step_dist / 2

    def plot(self, ax, labels, colors):
        """
        Trace le graphique à bulles.

        Paramètres
        ----------
        ax : matplotlib.axes.Axes
        labels : list
            Etiquettes des bulles.
        colors : list
            Couleurs des bulles.
        """
        for i in range(len(self.bulles)):
            circ = plt.Circle(
                self.bulles[i, :2], self.bulles[i, 2], color=colors[i])
            ax.add_patch(circ)
            ax.text(*self.bulles[i, :2], labels[i],
                    horizontalalignment='center', verticalalignment='center')

Créer un objet BubbleChart et tracer le graphique

Pour créer le graphique à bulles empaquetées, nous devons créer un objet BubbleChart et appeler la méthode collapse pour déplacer les bulles vers le centre de masse. Nous pouvons ensuite créer une figure matplotlib et y ajouter un objet d'axes. Enfin, nous appelons la méthode plot pour tracer les bulles sur le graphique.

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()

Résumé

Dans ce laboratoire, nous avons appris à créer un graphique à bulles empaquetées à l'aide de Matplotlib en Python. Nous avons défini les données sous forme d'un dictionnaire contenant les noms des navigateurs, la part de marché et la couleur de chaque bulle. Nous avons ensuite créé une classe BubbleChart pour configurer les positions initiales des bulles, calculer la distance maximale de déplacement, déplacer les bulles vers le centre de masse et vérifier s'il y a des collisions avec d'autres bulles. Enfin, nous avons tracé le graphique à l'aide de matplotlib.