How to Create a Multiline Plot Using Seaborn

How do I create a multiline plot using seaborn?

Seaborn favors the "long format" as input. The key ingredient to convert your DataFrame from its "wide format" (one column per measurement type) into long format (one column for all measurement values, one column to indicate the type) is pandas.melt. Given a data_preproc structured like yours, filled with random values:

num_rows = 20
years = list(range(1990, 1990 + num_rows))
data_preproc = pd.DataFrame({
'Year': years,
'A': np.random.randn(num_rows).cumsum(),
'B': np.random.randn(num_rows).cumsum(),
'C': np.random.randn(num_rows).cumsum(),
'D': np.random.randn(num_rows).cumsum()})

A single plot with four lines, one per measurement type, is obtained with

sns.lineplot(x='Year', y='value', hue='variable', 
data=pd.melt(data_preproc, ['Year']))

(Note that 'value' and 'variable' are the default column names returned by melt, and can be adapted to your liking.)

Creating multiple lines in lineplot in seaborn from dataset

How about transposing you DataFrame?

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

df = pd.DataFrame(np.random.rand(3, 10)).T
print(df)

DataFrame:

          0         1         2
0 0.341005 0.925077 0.541746
1 0.324769 0.558320 0.902804
2 0.647871 0.630663 0.607212
3 0.722298 0.745091 0.630445
4 0.209836 0.386576 0.076790
5 0.347911 0.237178 0.446102
6 0.174991 0.777129 0.109934
7 0.022564 0.388223 0.464438
8 0.359771 0.722761 0.837942
9 0.091696 0.474859 0.840078

Plot

sns.lineplot(data=df.iloc[:, :2])

Result:

enter image description here

plot multiple lines in seaborn lineplot

IMO, it's a bit of a mess on a single plot, but here we go. You can use one of the default categorial color maps and a dictionary to get a single color for each model. You can use groupby to plot each model separately and knowing there are 3 lines for each we can plan to cycle the linestyles to achieve different linestyles for each of the columns.

The default legend will be total garbage, so we can construct it ourselves to indicate what model each color represents and what linestyle is used for each measurement.

import matplotlib.pyplot as plt
from matplotlib.patches import Patch
from matplotlib.lines import Line2D

colors = dict(zip(df.model.unique(), plt.cm.tab10.colors))
linestyles = ["-", "--", "-."]
ycols = ['precision', 'recall', 'f1']

# Construct legend ourself
legend_elements = ([Patch(facecolor=color, label=model)
for model,color in colors.items()]
+ [Line2D((0,1),(0,0), color='black', linestyle=linestyle, label=col)
for linestyle,col in zip(linestyles, ycols)])

fix, ax = plt.subplots()
ax.set_prop_cycle(plt.cycler('linestyle', linestyles))
for model, gp in df.groupby('model'):
gp.plot(x='K', y=ycols,
ax=ax,
color=colors[model],
legend=False)

ax.legend(handles=legend_elements, bbox_to_anchor=(1,1))
plt.show()

Sample Image

How to create a multi-line plot for my dataset?

Reorganize df which is pivot table to classic data frame and plot as you want:

import matplotlib.pylab as plt
import pandas as pd
import seaborn as sns

df = pd.DataFrame(columns=["Event1", "Event2", "Event3"],
data=[[15,1,22],
[16,1.26,80],
[27,0,15]])
df = df.set_index([["Series1", "Series2", "Series3"]])
print(df)

# reorganize df to classic table
df2=df.stack().reset_index()
df2.columns = ['Series','Event','Values']
print(df2)

plt.figure(figsize=(12,8))
ax = sns.pointplot(x='Event', y='Values', hue='Series',data=df2)
ax.grid(b=True, which='major', color='#d3d3d3', linewidth=1.0)
ax.grid(b=True, which='minor', color='#d3d3d3', linewidth=0.5)
plt.show()

enter image description here

df2:

    Series   Event  Values
0 Series1 Event1 15.00
1 Series1 Event2 1.00
2 Series1 Event3 22.00
3 Series2 Event1 16.00
4 Series2 Event2 1.26
5 Series2 Event3 80.00
6 Series3 Event1 27.00
7 Series3 Event2 0.00
8 Series3 Event3 15.00

How to plot a multiple line plot in Seaborn using specific columns?

Here I assume that the years are strings and the values are integers.

Seaborn expects data in tidy format, so first you might transform your dataframe.

import seaborn as sns
import pandas as pd


df = pd.DataFrame(
[
{"name": "A", "2015": 99, "2016": 98, "2017": 95, "2018": 99},
{"name": "B", "2015": 76, "2016": 89, "2017": 83, "2018": 85},
{"name": "C", "2015": 88, "2016": 89, "2017": 91, "2018": 91},
]
)

df.set_index("name", inplace=True)
tidy = df.stack().reset_index().rename(columns={"level_1": "year", 0: "values"})

Here is the outcome

    name    year    values
0 A 2015 99
1 A 2016 98
2 A 2017 95
3 A 2018 99
4 B 2015 76
5 B 2016 89
6 B 2017 83
7 B 2018 85
8 C 2015 88
9 C 2016 89
10 C 2017 91
11 C 2018 91

Then, you can

  1. filter it for the years you want
  2. pass it as a data parameter
  3. specify the columns at x, y, and hue
sns.lineplot(
data=tidy[tidy["year"].isin(["2016", "2018"])], x="year", y="values", hue="name"
)

The result

enter image description here

create seaborn lineplot with multiple lines and hue

For hue to work properly, all data should be provided at once. Also, hue should refer to an array of the same length as x and y, so repeating the line title for each entry in the arrays of x and y values.

Here is a possible adaption of the first few lines of save_graph:

import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np

def save_graph(properties):
plt.figure()
x_values = np.concatenate([iteration_values.x_values
for iteration_values in properties.graph_iteration_values])
y_values = np.concatenate([iteration_values.y_values
for iteration_values in properties.graph_iteration_values])
line_titles = np.concatenate([[iteration_values.line_title] * len(iteration_values.x_values)
for iteration_values in properties.graph_iteration_values])
sns_plot = sns.lineplot(x=x_values, y=y_values, hue=line_titles)
...

resulting lineplot with hue per line

Another option is to draw multiple plots on the same graph, not using hue but set the label:

def save_graph(properties):
plt.figure()
ax = None
for iteration_values in properties.iteration_values:
ax = sns.lineplot(x=iteration_values.x_values, y=iteration_values.y_values,
label=iteration_values.line_title, ax=ax)
...

This will loop through the current color cycle and also create the correct legend.

Plot multiple line graph from Pandas into Seaborn

The seaborn lineplot() documentation says:

Passing the entire wide-form dataset to data plots a separate line for each column

Since you want a line for each row instead, you need to transpose your dataframe, so try this:

sns.lineplot(data=ibd_panda_conv.T, dashes=False)

Seaborn multi line plot with only one line colored

You can use pandas groupby to plot:

fig,ax=plt.subplots()
for c,d in df.groupby('country'):
color = 'red' if c=='US' else 'grey'
d.plot(x='year',y='pop', ax=ax, color=color)

ax.legend().remove()

output:

enter image description here

Or you can define a specific palette as a dictionary:

palette = {c:'red' if c=='US' else 'grey' for c in df.country.unique()}

sns.lineplot(x='year', y='pop', data=df, hue='country',
palette=palette, legend=False)

Output:

enter image description here



Related Topics



Leave a reply



Submit