1
votes

Comment tracer un tracé linéaire avec des points sur des points spécifiques avec des couleurs et des types de lignes spécifiques pour chaque ligne en utilisant Seaborn?

J'ai le dataframe suivant

sns.lineplot(x="x", y="y", hue="cat", data=data_tmp)
sns.scatterplot(x="point",y="y",hue="cat", data=data_tmp[data_tmp.point==data_tmp.x])
plt.show()

Je voudrais produire un lineplot avec différentes couleurs et styles de lignes par chat . Mais je voudrais donner les couleurs et styles de lignes spécifiques par cat tels qu'ils sont définis dans le dataframe . Enfin, je voudrais marquer les points sur chaque ligne avec la même couleur.

J'ai seulement essayé:

import pandas as pd



 data_tmp = pd.DataFrame({'x': [0,14,28,42,56, 0,14,28,42,56],
                         'y': [0, 0.003, 0.006, 0.008, 0.001, 0*2, 0.003*2, 0.006*2, 0.008*2, 0.001*2],
                         'cat': ['A','A','A','A','A','B','B','B','B','B'],
                         'color': ['#B5D8F0','#B5D8F0','#B5D8F0','#B5D8F0','#B5D8F0','#247AB2','#247AB2','#247AB2','#247AB2','#247AB2'],
                         'point': [14,14,14,14,14,28,28,28,28,28],
                         'linestyles':['-','-','-','-','-','--','--','--','--','--']})

Des idées?


0 commentaires

3 Réponses :


1
votes

Voici comment je pourrais faire cela. Vous devez utiliser la colonne cat pour contrôler les différents paramètres de tracé (couleur, style, taille du marqueur), puis créer des objets de mappage (ici dicts) qui indiquent la valeur de paramètre à utiliser pour chaque catégorie. La couleur est facile. Le style de ligne est plus difficile, car Seaborn ne propose que des tirets comme paramètre configurable, qui doit être donné dans le format avancé Matplotlib de (segment, gap) . La fonction matplotlib.lines._get_dash_pattern traduit la valeur de la chaîne (par exemple - ) dans ce format, bien que la valeur renvoyée doive être manipulée avec précaution. Pour la taille du marqueur, le lineplot n'offre malheureusement pas la possibilité de changer la taille du marqueur avec la catégorie (même si vous pouvez changer le style du marqueur), vous devez donc utiliser un nuage de points code> en haut. Le dernier bit est la légende, vous voudrez probablement la désactiver pour le deuxième tracé, pour éviter de le répéter, mais le problème est que la première légende ne contiendra pas les marqueurs. Si cela vous dérange, vous pouvez toujours modifier la légende manuellement. Dans l'ensemble, cela pourrait ressembler à ceci:

import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
import seaborn as sns

# Converts a line style to a format acceptable by Seaborn
def get_dash_pattern(style):
    _, dash = mpl.lines._get_dash_pattern(style)
    return dash if dash else (None, None)

data_tmp = pd.DataFrame({
    'x': [0,14,28,42,56, 0,14,28,42,56],
    'y': [0, 0.003, 0.006, 0.008, 0.001, 0*2, 0.003*2, 0.006*2, 0.008*2, 0.001*2],
    'cat': ['A','A','A','A','A','B','B','B','B','B'],
    'color': ['#B5D8F0','#B5D8F0','#B5D8F0','#B5D8F0','#B5D8F0',
              '#247AB2','#247AB2','#247AB2','#247AB2','#247AB2'],
    'point': [14,14,14,14,14,28,28,28,28,28],
    'linestyles':['-','-','-','-','-','--','--','--','--','--']})
# Extract plot features as dicts
feats = (data_tmp[['cat', 'color', 'linestyles', 'point']]
         .set_index('cat').drop_duplicates().to_dict())
palette, dashes, sizes = feats['color'], feats['linestyles'], feats['point']
# Convert line styles to dashes
dashes = {k: get_dash_pattern(v) for k, v in dashes.items()}
# Lines
lines = sns.lineplot(x="x", y="y", hue="cat", style="cat", data=data_tmp,
                     palette=palette, dashes=dashes)
# Points
sns.scatterplot(x="x", y="y", hue="cat", size="cat", data=data_tmp,
                palette=palette, sizes=sizes, legend=False)
# Fix legend
for t, l in zip(lines.legend().get_texts(), lines.legend().get_lines()):
    l.set_marker('o')
    l.set_markersize(sizes.get(l.get_label(), 0) / t.get_fontsize())
plt.show()

Résultat:

 Final plot


1 commentaires

Peut-être que la façon dont j'ai formulé la question était trompeuse. En ce qui concerne les points, je voulais dire que je voudrais des points où l'axe des x est égal à la variable point dans l'ensemble de données pour chaque ligne. Mais ta réponse m'a quand même aidé à comprendre



1
votes

Voici ma solution avec l'aide de @jdehesa

J'ai également mis la légende en dehors de l'intrigue ici et un peu de polissage des étiquettes

def get_dash_pattern(style):
    _, dash = mpl.lines._get_dash_pattern(style)
    return dash if dash else (None, None)

palette = dict(zip(data_tmp.cat, data_tmp.color))
dashes = dict(zip(data_tmp.cat, data_tmp.linestyles))
dashes = {k: get_dash_pattern(v) for k, v in dashes.items()}

ax = sns.lineplot(x="x", y="y", hue="cat", data=data_tmp, palette=palette, style='cat',  dashes=dashes)
ax = sns.scatterplot(x="point", y="y", hue="cat", data=data_tmp[data_tmp.point == data_tmp.x], palette=palette,
                     legend=False)

ax.set_title('title')
ax.set_ylabel('y label')
ax.set_xlabel('x label')
ax.legend(loc=(1.04, 0))
plt.show()

entrez description de l'image ici


0 commentaires

3
votes

Peut-être que vous souhaitez utiliser matplotlib directement, comme

import pandas as pd
import matplotlib.pyplot as plt


df = pd.DataFrame({'x': [0,14,28,42,56, 0,14,28,42,56],
                   'y': [0, 0.003, 0.006, 0.008, 0.001, 0*2, 0.003*2, 0.006*2, 0.008*2, 0.001*2],
                   'cat': ['A','A','A','A','A','B','B','B','B','B'],})


d = {"A" : {"color": '#B5D8F0', "markersize":  5, "linestyle": "-"},
     "B" : {"color": '#247AB2', "markersize": 10, "linestyle": "--"}}

for n, grp in df.groupby("cat"):
    plt.plot(grp.x, grp.y, marker="o", label=n, **d[n])

plt.legend()
plt.show()

entrez la description de l'image ici


0 commentaires