Visualizing Relationships with Seaborn
Visualizing relationships between variables is a fundamental part of data analysis. Seaborn makes it easy to create informative plots that reveal correlations, trends, and patterns in your data. In this article, we'll explore how to use Seaborn to create scatter plots, line plots, and joint plots to visualize these relationships effectively.
1. Scatter Plots
Scatter plots are one of the most basic and commonly used plots to visualize the relationship between two continuous variables. They allow you to inspect how variables are associated and identify unusual observations, but they do not by themselves show that one variable affects another. Seaborn’s scatterplot() function simplifies the creation of scatter plots and offers extensive customization options.
1.1 Creating a Basic Scatter Plot
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
# Deterministic, local sample with the same columns used throughout this lesson.
rng = np.random.default_rng(20261011)
days = ["Thur", "Fri", "Sat", "Sun"]
row_count = 96
tips = pd.DataFrame({
"day": np.repeat(days, row_count // len(days)),
"sex": np.tile(np.repeat(["Female", "Male"], 12), 4),
"smoker": np.tile(["No", "Yes"], row_count // 2),
"size": np.tile([2, 2, 3, 4, 2, 3], row_count // 6),
})
day_effect = tips["day"].map({"Thur": 0, "Fri": 2, "Sat": 6, "Sun": 5}).to_numpy()
tips["total_bill"] = np.round(10 + day_effect + rng.gamma(2.4, 5.0, row_count), 2)
tips["tip"] = np.round(tips["total_bill"] * rng.normal(0.16, 0.025, row_count), 2)
tips["time"] = np.where(tips["day"].eq("Thur"), "Lunch", "Dinner")
# Create a scatter plot
sns.scatterplot(x="total_bill", y="tip", data=tips)
# Adding the title
plt.title("Scatter Plot of Total Bill vs Tip")
plt.xlabel("Total bill (currency units)")
plt.ylabel("Tip (currency units)")
# Display the plot
plt.show()

Figure 1: Scatter Plot of Total Bill vs Tip.
Explanation:
- x="total_bill": Sets the total bill amount as the x-axis variable.
- y="tip": Sets the tip amount as the y-axis variable.
- data=tips: Specifies the dataset to use.
This scatter plot shows the relationship between the total bill and the tip amount. Each point represents a single observation from the dataset. From the plot, you can observe that as the total bill increases, the tip amount tends to increase as well, indicating a positive correlation.
1.2 Adding Hue for Categorical Separation
You can use the hue parameter to add color coding based on a categorical variable. Repeating that mapping with style makes the grouping available without color.
# Scatter plot with hue for categorical separation
sns.scatterplot(x="total_bill", y="tip", hue="sex", style="sex", data=tips)
# Adding the title
plt.title("Scatter Plot of Total Bill vs Tip by Recorded Sex")
plt.xlabel("Total bill (currency units)")
plt.ylabel("Tip (currency units)")
# Display the plot
plt.show()
Figure 2: Scatter Plot of Total Bill vs Tip by Recorded Sex.
Explanation:
- hue="sex" and style="sex": Use both color and marker shape for the recorded category.
- The plot now shows the two synthetic groups without making color the only cue.
The grouping can reveal patterns worth investigating, but this synthetic fixture cannot support population claims and an observational grouping would not establish a causal difference.
1.3 Customizing Markers and Styles
Seaborn allows customization of markers and styles to differentiate groups within the data further. You can use the style parameter to change marker shapes based on another categorical variable.
# Scatter plot with custom markers and styles
sns.scatterplot(x="total_bill", y="tip", hue="sex", style="smoker", data=tips, markers=["o", "s"])
# Adding the title
plt.title("Scatter Plot with Custom Markers and Styles")
plt.xlabel("Total bill (currency units)")
plt.ylabel("Tip (currency units)")
# Display the plot
plt.show()

Figure 3: Scatter Plot with Custom Markers and Styles.
Explanation:
- style="smoker": Changes marker styles based on whether the customer is a smoker or not.
- markers=["o", "s"]: Specifies the marker types for the different categories in the
smokervariable.
In this plot, you can inspect how smoking status and the recorded sex category relate to bill and tip amounts. Treat any visible difference as exploratory, especially with small groups.
2. Line Plots
Line plots are useful for visualizing trends over time or continuous data. They are particularly effective when you have a time series or ordered data. Seaborn’s lineplot() function is designed to handle such data gracefully.
2.1 Creating a Basic Line Plot
# Deterministic repeated measurements for two events and six subjects.
fmri = pd.DataFrame([
{
"timepoint": timepoint,
"signal": np.sin(timepoint / 3) + (0.25 if event == "stim" else 0) + subject * 0.015,
"event": event,
"subject": f"S{subject + 1}",
}
for event in ["cue", "stim"]
for subject in range(6)
for timepoint in range(15)
])
# Create a basic line plot
sns.lineplot(x="timepoint", y="signal", data=fmri, seed=20261011)
plt.title("Signal Over Time")
plt.xlabel("Timepoint (index)")
plt.ylabel("Signal (arbitrary units)")
plt.show()

Figure 4: Basic Line Plot of Signal Over Time.
Explanation:
- x="timepoint": Represents the time variable on the x-axis.
- y="signal": Represents the signal measurement on the y-axis.
- data=fmri: Specifies the dataset to use.
This plot shows how the signal changes over time across all observations in the dataset.
2.2 Grouping Data with Hue
You can group data using the hue parameter to compare trends across different categories, such as different events or subjects.
# Line plot with grouping by hue
sns.lineplot(x="timepoint", y="signal", hue="event", style="event", data=fmri, seed=20261011)
plt.title("Signal Over Time Grouped by Event")
plt.xlabel("Timepoint (index)")
plt.ylabel("Signal (arbitrary units)")
plt.show()

Figure 5: Line Plot Grouped by Event.
Explanation:
- hue="event": Colors the lines based on the
eventvariable. - Each line represents the average signal over time for a specific event type.
Grouping by event allows you to compare how different events influence the signal over time.
2.3 Adding Confidence Intervals
With repeated x-values, lineplot() estimates the mean by default and draws a bootstrap 95% confidence interval for that estimator. You can change the estimator and error-bar method or remove the interval using errorbar; name the meaning in the surrounding text.
# Line plot without confidence intervals
sns.lineplot(x="timepoint", y="signal", hue="event", style="event", data=fmri, errorbar=None)
plt.title("Line Plot Without Confidence Intervals")
plt.xlabel("Timepoint (index)")
plt.ylabel("Signal (arbitrary units)")
plt.show()

Figure 6: Line Plot Without Confidence Intervals.
Explanation:
- errorbar=None: Removes the confidence intervals from the plot.
Removing intervals can reduce visual overlap, but it also hides information about uncertainty. Do so only when the uncertainty is communicated elsewhere or is not part of the claim.
3. Joint Plots
Joint plots combine scatter plots and histograms (or other plots) to provide a more comprehensive view of the relationship between two variables, including their distributions. Seaborn's jointplot() function creates these plots efficiently.
3.1 Creating a Basic Joint Plot
# Creating a basic joint plot
sns.jointplot(x="total_bill", y="tip", data=tips)
# Display the plot
plt.show()

Figure 7: Basic Joint Plot of Total Bill vs Tip.
Explanation:
- x="total_bill" and y="tip": Specify the variables for the x and y axes.
- The central plot is a scatter plot, while the margins display histograms of each variable.
This plot helps you understand not only the relationship between the two variables but also their individual distributions.
3.2 Choosing Different Kinds of Joint Plots
You can change the kind of plot displayed in the joint plot to better suit your data.
# Joint plot with hex bins
sns.jointplot(x="total_bill", y="tip", data=tips, kind="hex")
# Display the plot
plt.show()

Figure 8: Joint Plot with Hex Bins.
Explanation:
- kind="hex": Changes the central plot to a hexbin plot, which is useful for large datasets to show density.
Other kinds include "reg" for regression plots and "kde" for kernel density estimates.
3.3 Adding Regression Lines
You can add a regression line to the joint plot to visualize trends more clearly.
# Joint plot with regression line
sns.jointplot(x="total_bill", y="tip", data=tips, kind="reg")
# Display the plot
plt.show()

Figure 9: Joint Plot with Regression Line.
Explanation:
- kind="reg": Adds a regression line and confidence interval to the central plot.
This helps in identifying the nature of the relationship between the variables, whether it's linear or not.
The fitted line summarizes a model under its assumptions. It does not establish that total bill causes the tip value, and the confidence band does not cover every source of uncertainty.
4. Conclusion
Seaborn provides powerful tools for visualizing relationships between variables. By mastering scatter plots, line plots, and joint plots, you can gain deeper insights into your data and effectively communicate these insights to others. These plots help in:
- Identifying Correlations: Understanding how variables relate to each other.
- Detecting Trends: Observing changes over time or other continuous variables.
- Exploring Distributions: Analyzing the distribution of individual variables alongside their relationships.
In the next article, we'll explore how to visualize categorical data using Seaborn's specialized plots, such as bar plots, box plots, and violin plots.
Accessibility and verification
All nine examples use deterministic local data. Grouped scatter and line plots repeat color with marker or line style. For real data, label currency or measurement units, describe the main relationship in text, preserve uncertainty, and address overplotting with transparency, smaller marks, binning, or aggregation as appropriate.
APIs and all nine examples checked with Seaborn 0.13.2, Matplotlib 3.11.2, NumPy 2.5.3, pandas 3.0.6, and SciPy 1.18.1 on 2026-10-11.