2

I have a long form data table and I want to plot results from different simulations. At the same time, the visualization should be split into facets by another variable.

Here's an example:

import seaborn as sns
import pandas as pd
import numpy as np

sim = ['a'] * 100 + ['b'] * 100 + ['c'] * 100
var = (['u'] * 50 + ['v'] * 50)*3

x = np.linspace(0, 50, 50)
x = np.hstack([x]*6)

y = np.random.rand(300)

df = pd.DataFrame({'x':x, 'y':y, 'sim':sim, 'var':var})

sns.relplot(data=df, x='x', y='y', kind='line', col='var', hue='sim')

The created plot looks like this:

Plot

Now, I want all lines to be a of a certain color, while one specific line should be of another specific color.

Maybe there is a way to create a color palette that only consists of one color? And then map another sns.lineplot on top with another color? Maybe it would be easier to manually create the plot with matplotlib, but my actual dataframe contains a lot more variables and simulations, which is why seaborn comes in handy.

leomfn
  • 155
  • 1
  • 11
  • 2
    Here's a [great answer](https://stackoverflow.com/questions/67611640/how-to-add-additional-plots-to-a-seaborn-facetgrid-and-specify-colors) to your question: draw the graph without setting hue, and add an additional lineplot. – r-beginners Aug 24 '21 at 08:08
  • Thanks a lot, the `units` argument seems perfect for this case. – leomfn Aug 24 '21 at 08:18

2 Answers2

2

EDIT CODE BASE COMMENT

if you want color df['sim] == 'a' use this code:

import seaborn as sns
import pandas as pd
import numpy as np

sim = ['a'] * 100 + ['b'] * 100 + ['c'] * 100
var = (['u'] * 50 + ['v'] * 50)*3

x = np.linspace(0, 50, 50)
x = np.hstack([x]*6)

y = np.random.rand(300)

df = pd.DataFrame({'x':x, 'y':y, 'sim':sim, 'var':var})

g = sns.relplot(data=df, x='x', y='y', kind='line', col='var',
                units='sim', estimator=None, color='0.7')

for i , ax in enumerate(g.axes.flatten()):
    sns.lineplot(data=df[df['sim']=='a'], x='x', y='y', ax=ax, color='red', estimator=None, label='a', lw=2)
    ax.legend(title='sim', bbox_to_anchor=(1, 1), loc='upper left') if i == 1 else ax.legend().remove()

output:

enter image description here

I'mahdi
  • 23,382
  • 5
  • 22
  • 30
  • Thanks for this idea, however, the 'blue' lines get combined to one mean blue line and the confidence band. – leomfn Aug 24 '21 at 08:23
  • 1
    @klooth, I edit the code block, maybe this helps you – I'mahdi Aug 24 '21 at 09:40
  • Thanks, this also seems like a great idea. Do you know (1) how to change other properties like linewidth of this single line you specified with clr and (2) how to set specific colors (e. g., 'blue' for the single line and 'grey' for the others? Is it possible at all using this approach?In my answer below, this is really easy, however, it's not totally clear to me, in what order the lines are plotted and which index refers to the line I want to change. Thanks for your time! – leomfn Aug 24 '21 at 11:04
  • No problem! However, I don't think that you have to put in much more work. I found a usable solution already and, maybe, using seaborn was not the best option for this case in the first place. – leomfn Aug 24 '21 at 12:16
  • @klooth, I edit code and solve your (1) and (2) problems, is this good work? is this usable solution? am I much more working? – I'mahdi Aug 25 '21 at 07:17
1

Based on r-beginner's comment and this answer, using the units argument can be used to categorize the data without assigning colors as hue would. The single line's color can be changed afterwards by setting a color on a specific line on each of the facetgrids axes. The code could look like this:

import seaborn as sns
import pandas as pd
import numpy as np

sim = ['a'] * 100 + ['b'] * 100 + ['c'] * 100
var = (['u'] * 50 + ['v'] * 50)*3

x = np.linspace(0, 50, 50)
x = np.hstack([x]*6)

y = np.random.rand(300)

df = pd.DataFrame({'x':x, 'y':y, 'sim':sim, 'var':var})

# setting units instead of hue; estimator has to be None
g = sns.relplot(data=df, x='x', y='y', kind='line', col='var',
                units='sim', estimator=None, color='0.7')

# change the color of line with index 1 in each facet/axis
for ax in g.axes.flatten():
    for i, l in enumerate(ax.get_lines()):
        if i == 1:
            l.set_color('blue')

This is the resulting plot: plot

leomfn
  • 155
  • 1
  • 11