Search code examples
pythonpandasseabornfacet-grid

Change the line style of the same line in a plot Seaborn Facetgrid using a dataframe


I am trying to create a plot like

this one

where the line style changes after a predetermined x-value. I am using Seaborn Facetgrid with a pandas dataframe input in tidy format.

My input dataframe looks like this:

>>> print(plot_df)
dataset  x  y  style
dogs     1  2  solid
dogs     2  3  solid
dogs     3  1  solid
dogs     5  6  dashed
cats ....

I have tried to use hue_kws as below but this has no effect.

style_list = plot_df[style].tolist()
g = sns.FacetGrid(plot_df, hue="dataset", hue_kws={"ls":style_list})
g.map(plt.plot, "x", "y").add_legend()

How can I achieve this successfully?

EDIT: Thank you for the suggestion of the other similar question I had not found that. However it does not answer my question as that question relies on using the hue parameter to change the linestyle. Not only would this result in a different colour for the dashed section of the line (which I don't want) it would also clash with my use of the hue section to differentiate by dataset.

Note: I am also using the row and column functionality of Facetgrid but I have excluded these for simplicity.


Solution

  • I think your problem is that you only have one point labeled 'dashed', when you need at least 2 points to draw a line. I would suggest the following:

    cutoff_x = 3
    d = '''
    dataset  x  y
    dogs     1  2
    dogs     2  3
    dogs     3  1
    dogs     5  6'''
    df1 = pd.read_csv(StringIO(d), sep='\\s+', header=0)
    
    dataset    x   y
    0  dogs    1   2
    1  dogs    2   3
    2  dogs    3   1
    3  dogs    5   6
    
    df2 = df1.loc[df1['x']>=cutoff_x].assign(style='dashed')
    
    dataset    x   y   style
    2  dogs    3   1   dashed
    3  dogs    5   6   dashed
    
    df = df1.drop(df1.loc[df1['x']>cutoff_x].index).assign(style='solid').append(df2, ignore_index=True)
    
    dataset    x   y   style
    0  dogs    1   2   solid
    1  dogs    2   3   solid
    2  dogs    3   1   solid
    3  dogs    3   1   dashed
    4  dogs    5   6   dashed
    
    g = sns.FacetGrid(df, hue="dataset")
    g.map_dataframe(sns.lineplot, "x", "y", style="style")
    

    enter image description here