Search code examples
pythonpandasmatplotlibscatter-plot

How to create a scatter plot by category and order the values


I have a data table and I want to produce a scatter plot with the year of an activity on the x-axis, school class on the y-axis, and the theme of cultural activities as a category.

This is what my data looks like:

id année suivi thematique itinéraire segpa classe ordre classe couleur
1 2022-2023 Spectacle vivant False 6ème 6 - 6ème #cf84c4
2 2022-2023 Spectacle vivant True 4ème 4 - 4ème #cf84c4
3 2022-2023 Education aux médias et à l'information False 5ème 5 - 5ème #00b6cf
4 2022-2023 Education aux médias et à l'information False 4ème 4 - 4ème #00b6cf
5 2019-2020 Livres et lecture False 6ème 6 - 6ème #bd9f38
6 2022-2023 Spectacle vivant True 4ème 4 - 4ème #cf84c4
7 2022-2023 Spectacle vivant False 6ème 6 - 6ème #cf84c4
8 2019-2020 Spectacle vivant False 6ème 6 - 6ème #cf84c4
...

I have many problems. I couldn't figure how to order the x-and y-axes. I also couldn't figure how to categorize my data. I don't know how to size the point with the count of value or add a legend.

The values in x are interval of years.

The best I could do:

Actual situation

In python, I tried this:

from matplotlib import pyplot as plt

# ajout d'une colonne couleur au soustableau
soustableau['couleur'] = soustableau['thematique itinéraire'].map({'Patrimoine':'#51b76a', 
                                                                   'Arts visuels':'#889cf0', 
                                                                   'Livres et lecture':'#bd9f38', 
                                                                   'Culture scientifique':'#e58370',
                                                                   'Spectacle vivant':'#cf84c4',
                                                                   '''Education aux médias et à l'information''':'#00b6cf' })

# liste des périodes ordonnées
ordre_annee = ['2019-2020','2020-2021','2021-2022','2022-2023']

# problème : ordonner l'axe des x !!
# faire une légende

viz = soustableau.plot(
   x='année suivi', 
   y='ordre classe', 
   c = 'couleur',
   kind='scatter',
   #label='couleur',
   legend=True,
   figsize=(15, 10),
   fontsize=15, 
   title='itinéraire des classes par année scolaire'
   
)

viz.margins(0.1)

plt.show()

Seems like seaborn is the library I should use, but I couldn't find a proper example. I've read this post.


Solution

  • Use Categoricals to ensure a custom sorted order, and compute a groupby.size for the size:

    df['année suivi'] = pd.Categorical(df['année suivi'])
    
    order = ['CM2', '6ème', '5ème', '4ème', '3ème', '2nde', '1ère']
    df['classe'] = pd.Categorical(df['classe'], categories=order, ordered=True)
    
    (df.groupby(['année suivi', 'classe', 'couleur'], as_index=False).size()
       .assign(size=lambda d: d['size']*500)
       .plot(x='année suivi', 
             y='classe', 
             c='couleur',
             kind='scatter',
             s='size',
             legend=True,
             #figsize=(15, 10),
             fontsize=15, 
             title='itinéraire des classes par année scolaire'
       )
    )
    

    NB. the logic was not fully clear, so I grouped by year/class/color, but use whichever groups make sense, for instance "thematique itinéraire" could be used.

    Output:

    enter image description here

    A different example with seaborn.scatterplot:

    import seaborn as sns
    
    sns.scatterplot(df.groupby(['année suivi', 'classe', 'thematique itinéraire'],
                               as_index=False).size(),
                    x='année suivi', y='classe',
                    hue='thematique itinéraire', size='size',
                    style='thematique itinéraire'
                    )
    

    Output:

    enter image description here