5
votes

Tracer deux dataframes obtenues à partir d'une boucle dans le même graphe Python

Je voudrais tracer deux dfs avec deux couleurs différentes. Pour chaque df , j'aurais besoin d'ajouter deux marqueurs. Voici ce que j'ai essayé:

for stats_file in stats_files:
    data = Graph(stats_file)
    Graph.compute(data)
    data.servers_df.plot(x="time", y="percentage", linewidth=1, kind='line')
    plt.plot(data.first_measurement['time'], data.first_measurement['percentage'], 'o-', color='orange')
    plt.plot(data.second_measurement['time'], data.second_measurement['percentage'], 'o-', color='green')
plt.show()

En utilisant ce morceau de code, j'obtiens le servers_df tracé avec des marqueurs, mais sur des graphiques séparés. Comment puis-je avoir les deux graphiques en un seul pour mieux les comparer?

Merci.


2 commentaires

Il semble que votre question concerne le matplotlib et les pandas. Si ce n'est pas le cas, supprimez les balises ajoutées et indiquez les bibliothèques que vous comptez utiliser. Veuillez également fournir un exemple complet comprenant un jeu de données sur les jouets et le résultat attendu.


Quant à la question - il semble que vous devriez créer fig, ax = plt.subplots() puis utiliser data.servers_df.plot(..., ax=ax) et ax.plot(...) dans votre boucle.


4 Réponses :


3
votes

DataFrame.plot() renvoie par défaut un objet matplotlib.axes.Axes . Vous devez ensuite tracer les deux autres tracés sur cet objet:

colors = ['C0', 'C1', 'C2']  # matplotlib default color palette
                             # assuming that len(stats_files) = 3
                             # if not you need to specify as many colors as necessary 

ax = plt.subplot(111)
for stats_file, c in zip(stats_files, colors):
    data = Graph(stats_file)
    Graph.compute(data)
    data.servers_df.plot(x="time", y="percentage", linewidth=1, kind='line', ax=ax)
    ax.plot(data.first_measurement['time'], data.first_measurement['percentage'], 'o-', color=c)
    ax.plot(data.second_measurement['time'], data.second_measurement['percentage'], 'o-', color='green')
plt.show()

Si vous voulez les tracer les uns sur les autres avec des couleurs différentes, vous pouvez faire quelque chose comme ceci:

for stats_file in stats_files:
    data = Graph(stats_file)
    Graph.compute(data)
    ax = data.servers_df.plot(x="time", y="percentage", linewidth=1, kind='line')
    ax.plot(data.first_measurement['time'], data.first_measurement['percentage'], 'o-', color='orange')
    ax.plot(data.second_measurement['time'], data.second_measurement['percentage'], 'o-', color='green')
plt.show()

Cela change simplement la couleur du servers_df.plot . Si vous voulez changer la couleur des deux autres, vous pouvez simplement utiliser la même logique: créer une liste de couleurs que vous voulez qu'ils prennent à chaque itération, itérer sur cette liste et transmettre la valeur de color au paramètre de color à chaque itération .


3 commentaires

Merci pour votre réponse. Si j'utilisais cette partie de code, j'obtiendrais 3 graphiques: 2 vides (dont je suppose que ce seraient les sous-graphiques) et un graphique qui appartiendra au deuxième fichier. Une idée de pourquoi cela arriverait?


Si ax = data.servers_df.plot(x="time", y="percentage", linewidth=1, kind='line', ax=ax) ax = ax dans ax = data.servers_df.plot(x="time", y="percentage", linewidth=1, kind='line', ax=ax) , j'obtiendrais les deux graphiques, mais l'un sous l'autre. Je voudrais les superposer en utilisant différentes couleurs.


Je l'ai un peu changé, voyez si ça aide maintenant :)



1
votes

Vous pouvez créer un objet Axes pour le traçage en premier lieu, par exemple

import pandas as pd
import numpy as np 
from matplotlib import pyplot as plt 


df_one = pd.DataFrame({'a':np.linspace(1,10,10),'b':np.linspace(1,10,10)})
df_two = pd.DataFrame({'a':np.random.randint(0,20,10),'b':np.random.randint(0,5,10)})

dfs = [df_one,df_two]
fig,ax = plt.subplots(figsize=(8,6))

colors = ['navy','darkviolet']
markers = ['x','o']
for ind,item in enumerate(dfs):
    ax.plot(item['a'],item['b'],c=colors[ind],marker=markers[ind])

comme vous pouvez le voir, dans le même ax , les deux dataframes sont tracés avec des couleurs et des marqueurs différents.

production


0 commentaires

4
votes

TL; DR

Votre appel à data.servers_df.plot() crée toujours un nouveau tracé, et plt.plot() trace sur le dernier tracé créé. La solution est de créer un axe dédié sur lequel tout doit être tracé.

Préface

J'ai supposé que vos variables sont les suivantes

  • data.servers_df : Dataframe avec deux colonnes flottantes "time" et "percentage"
  • data.first_measurements : Un dictionnaire avec les touches "time" et "pourcentage", qui sont chacune une liste de flottants
  • data.second_measurements : Un dictionnaire avec les clés "time" et "percentage" , qui sont chacune une liste de flottants

J'ai sauté la génération de stat_files car vous n'avez pas montré ce que fait Graph() , mais j'ai simplement créé une liste de data factices.

Si data.first_measurements et data.second_measurements sont également des dataframes, faites-le moi savoir et il existe une solution encore plus intéressante.

Théorie - Derrière les rideaux

Chaque tracé matplotlib (ligne, barre, etc.) vit sur un élément matplotlib.axes.Axes . Ce sont comme des axes réguliers d'un système de coordonnées. Maintenant, deux choses se produisent ici:

  • Lorsque vous utilisez plt.plot() , il n'y a aucun axe spécifié et donc, matplotlib recherche l'élément axes courant (en arrière-plan), et s'il n'y en a pas, il en créera un vide et l'utilisera, et définir est comme défaut. Le deuxième appel à plt.plot() trouve alors ces axes et les utilise.
  • DataFrame.plot() d'autre part, crée toujours un nouvel élément axes si aucun ne lui est donné (possible via l'argument ax )

Donc, dans votre code, data.servers_df.plot() crée d'abord un élément axes derrière les rideaux (qui est alors la valeur par défaut), et les deux appels plt.plot() obtiennent les axes par défaut et tracent dessus - c'est pourquoi vous obtenez deux parcelles au lieu d'un.

Solution

La solution suivante crée d'abord un matplotlib.axes.Axes dédié à l'aide de plt.subplots() . Cet élément d'axe est ensuite utilisé pour dessiner toutes les lignes sur. Notez en particulier ax=ax dans data.server_df.plot() . Notez que j'ai changé l'affichage de vos marqueurs de o- à o (car nous ne voulons pas afficher une ligne ( - ) mais uniquement des marqueurs ( o )). Des données simulées peuvent être trouvées ci-dessous

import random

import pandas as pd
import matplotlib.pyplot as plt

# Generation of dummy data
random.seed(1)
NUMBER_OF_DATA_FILES = 2
X_LENGTH = 10


class Data:
    def __init__(self):
        self.servers_df = pd.DataFrame(
            {
                'time': range(X_LENGTH),
                'percentage': [random.randint(0, 10) for _ in range(X_LENGTH)]
            }
        )
        self.first_measurement = {
            'time': self.servers_df['time'].values[:X_LENGTH // 2],
            'percentage': self.servers_df['percentage'].values[:X_LENGTH // 2]
        }
        self.second_measurement = {
            'time': self.servers_df['time'].values[X_LENGTH // 2:],
            'percentage': self.servers_df['percentage'].values[X_LENGTH // 2:]
        }


stat_files = [Data() for _ in range(NUMBER_OF_DATA_FILES)]

entrez la description de l'image ici

Données factices

fig, ax = plt.subplots()  # Here we create the axes that all data will plot onto
for i, data in enumerate(stat_files):
    y_column = f'percentage_{i}'  # Make the columns identifiable
    data.servers_df \
        .rename(columns={'percentage': y_column}) \
        .plot(x='time', y=y_column, linewidth=1, kind='line', ax=ax)
    ax.plot(data.first_measurement['time'], data.first_measurement['percentage'], 'o', color='orange')
    ax.plot(data.second_measurement['time'], data.second_measurement['percentage'], 'o', color='green')
plt.show()

0 commentaires

0
votes

Vous devez créer l'intrigue avant. Ensuite, vous pouvez explicitement vous référer à ce graphique lors du traçage des graphiques. df.plot(..., ax=ax) ou ax.plot(x, y)

import matplotlib.pyplot as plt

(fig, ax) = plt.subplots(figsize=(20,5))

for stats_file in stats_files:
    data = Graph(stats_file)
    Graph.compute(data)
    data.servers_df.plot(x="time", y="percentage", linewidth=1, kind='line', ax=ax)
    ax.plot(data.first_measurement['time'], data.first_measurement['percentage'], 'o-', color='orange')
    ax.plot(data.second_measurement['time'], data.second_measurement['percentage'], 'o-', color='green')
plt.show()


0 commentaires