Exploratory Data Analysis in Python with Seaborn and Matplotlib
Learn exploratory data analysis in Python using pandas, Seaborn, and Matplotlib to examine distributions, relationships, correlations, and outliers.
Once a dataset has been cleaned and validated, the next step is to understand what it contains.
This process is called exploratory data analysis, commonly shortened to EDA. It combines summary statistics, data inspection, and visualisation to uncover patterns, unusual values, group differences, and relationships between variables.
Raw tables are useful, but they rarely reveal the complete story. A carefully selected chart can make a skewed distribution, seasonal pattern, data-quality issue, or relationship visible within seconds.
In this chapter, you will learn how to perform exploratory data analysis in Python using:
- pandas for summaries and data inspection
- Matplotlib for chart structure and customisation
- Seaborn for statistical visualisations
- SciPy for a normal probability plot
By the end of the chapter, you will be able to choose suitable charts, explore numerical and categorical variables, create a correlation heatmap, interpret a Q-Q plot, and communicate findings without overstating what the data proves.
What Is Exploratory Data Analysis?
Exploratory data analysis is the process of examining a dataset before formal modelling or hypothesis testing.
EDA helps you answer questions such as:
- What does a typical observation look like?
- How widely are values distributed?
- Are variables skewed or approximately symmetric?
- Which categories occur most frequently?
- Are there missing values or unusual observations?
- Do two variables appear to move together?
- Do groups show different distributions?
- Are there patterns that deserve further investigation?
EDA is exploratory rather than confirmatory. It helps generate questions and identify promising directions, but a visual pattern alone is not proof of causation or statistical significance.
Why Data Visualisation Matters
The primary purpose of data visualisation is insight, not decoration.
Well-designed charts can help you:
- Understand the shape of a distribution
- Compare groups and categories
- Identify possible outliers
- Detect trends over time
- Explore relationships between variables
- Discover unexpected data-quality problems
- Communicate findings clearly
A chart should answer a question. Adding more colours, labels, or visual effects does not automatically make it more informative.
Prepare the EDA Environment
This chapter assumes that your cleaned dataset is stored in a pandas DataFrame named df.
Import the required libraries:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from scipy import stats
You can set a consistent Seaborn theme for the notebook:
sns.set_theme(style="whitegrid")
The example columns used in this chapter include:
priceagesalarygendercityratingdatesales
Replace these names with columns from your own dataset.
Start EDA with a Data Audit
Visualisation should not be the first action. Begin by confirming the shape, columns, data types, and missing values in the DataFrame.
Preview the Dataset
df.head()
Inspect random records to avoid focusing only on the first rows:
df.sample(5, random_state=42)
Check the Number of Rows and Columns
print(f"Rows: {df.shape[0]}")
print(f"Columns: {df.shape[1]}")
Inspect Data Types
df.info()
This is especially important before plotting because numbers stored as text may be treated as categories.
Review Missing Values
missing_summary = pd.DataFrame({
"missing_count": df.isna().sum(),
"missing_percentage": df.isna().mean().mul(100).round(2)
})
missing_summary.sort_values(
"missing_percentage",
ascending=False
)
Missing values can affect sample sizes and may cause some plots or statistical functions to ignore rows.
Review Numerical Summary Statistics
df.describe()
This shows statistics such as:
- Count
- Mean
- Standard deviation
- Minimum
- Quartiles
- Maximum
For numerical and categorical columns:
df.describe(include="all")
Inspect Categorical Frequencies
df["gender"].value_counts(dropna=False)
To view proportions:
df["gender"].value_counts(
normalize=True,
dropna=False
).mul(100).round(2)
These summaries provide context for the charts that follow.
Choose the Right Chart for the Question
The chart should match the data types and the question you want to answer.
| Analysis goal | Variables | Useful charts |
|---|---|---|
| Examine a numerical distribution | One numerical variable | Histogram, KDE plot, box plot, ECDF |
| Examine category frequencies | One categorical variable | Count plot, bar chart |
| Compare a number across groups | One categorical and one numerical variable | Box plot, violin plot, strip plot, point plot, bar plot |
| Explore a numerical relationship | Two numerical variables | Scatter plot, regression plot |
| Explore change over time | Date/time and numerical variable | Line plot |
| Compare several numerical variables | Multiple numerical variables | Correlation heatmap, pair plot |
| Add a third grouping variable | Two variables plus a category | Hue, marker style, faceting |
Avoid choosing a chart only because it looks impressive. A simple plot that answers a clear question is usually more effective.
Univariate Analysis: Explore One Variable
Univariate analysis examines one variable at a time.
For numerical variables, focus on:
- Centre
- Spread
- Shape
- Skewness
- Gaps
- Extreme values
For categorical variables, focus on:
- Frequency
- Proportion
- Rare categories
- Missing or unexpected labels
Visualise a Numerical Distribution with a Histogram
A histogram groups numerical values into intervals called bins and displays how many observations fall inside each interval.
price = df["price"].dropna()
plt.figure(figsize=(10, 6))
sns.histplot(
data=price,
bins=20,
kde=True
)
plt.title("Distribution of Product Prices")
plt.xlabel("Price")
plt.ylabel("Number of Observations")
plt.tight_layout()
plt.show()
Use the histogram to examine:
- Whether the distribution is symmetric or skewed
- Whether it has one or several peaks
- Whether values are concentrated in a narrow range
- Whether there are gaps or extreme values
The number of bins affects the appearance of the chart. Too few bins can hide structure, while too many can make random variation look meaningful.
You can ask Seaborn to determine the binning automatically:
plt.figure(figsize=(10, 6))
sns.histplot(
data=df,
x="price",
bins="auto"
)
plt.title("Distribution of Product Prices")
plt.xlabel("Price")
plt.ylabel("Number of Observations")
plt.tight_layout()
plt.show()
Add a Kernel Density Estimate
The kde=True argument adds a kernel density estimate to the histogram.
A KDE creates a smooth estimate of the distribution:
plt.figure(figsize=(10, 6))
sns.kdeplot(
data=df,
x="price",
fill=True
)
plt.title("Estimated Density of Product Prices")
plt.xlabel("Price")
plt.ylabel("Density")
plt.tight_layout()
plt.show()
A KDE can make the overall shape easier to see, but it is an estimate rather than a direct count. Its appearance depends on the smoothing bandwidth and can be misleading for small datasets, bounded variables, or strongly discrete values.
Use the histogram alongside the KDE rather than treating the smooth curve as the raw data.
Examine Quartiles and Potential Outliers with a Box Plot
A box plot summarises the median, quartiles, interquartile range, and values beyond the whiskers.
plt.figure(figsize=(8, 6))
sns.boxplot(
data=df,
y="price"
)
plt.title("Box Plot of Product Prices")
plt.ylabel("Price")
plt.tight_layout()
plt.show()
The main components are:
- The line inside the box represents the median
- The box spans the first to the third quartile
- The box width in the value direction represents the interquartile range
- The whiskers extend according to the box-plot rule
- Points beyond the whiskers are potential outliers
A point beyond a whisker is not automatically an error. It may be an unusual but valid observation.
Use an ECDF to View Cumulative Proportions
An empirical cumulative distribution function, or ECDF, shows the proportion of observations at or below each value.
plt.figure(figsize=(10, 6))
sns.ecdfplot(
data=df,
x="price"
)
plt.title("Cumulative Distribution of Product Prices")
plt.xlabel("Price")
plt.ylabel("Cumulative Proportion")
plt.tight_layout()
plt.show()
An ECDF is useful for questions such as:
- What percentage of products cost no more than a certain amount?
- What value contains the lowest 75% of observations?
- How do two complete distributions compare?
Unlike a histogram, an ECDF does not require selecting bins.
Assess Approximate Normality with a Q-Q Plot
A quantile-quantile plot compares the observed quantiles of a variable with the theoretical quantiles of a selected distribution.
The following example compares price with a normal distribution:
price = df["price"].dropna()
plt.figure(figsize=(8, 6))
stats.probplot(
price,
dist="norm",
plot=plt
)
plt.title("Normal Q-Q Plot of Product Prices")
plt.tight_layout()
plt.show()
How to Interpret a Q-Q Plot
- Points that follow the reference line reasonably closely are consistent with an approximately normal distribution.
- A curved pattern may indicate skewness.
- Strong departures at the ends may indicate heavier or lighter tails than a normal distribution.
- Isolated distant points may indicate unusual observations.
A Q-Q plot is a visual diagnostic, not a formal proof that the data is normal.
The interpretation also depends on sample size. Small samples may look irregular because of random variation, while large samples can reveal small departures that may not be practically important.
Examine a Categorical Variable with a Count Plot
A count plot displays the number of observations in each category.
category_order = (
df["city"]
.value_counts()
.index
)
plt.figure(figsize=(12, 6))
sns.countplot(
data=df,
x="city",
order=category_order
)
plt.title("Number of Observations by City")
plt.xlabel("City")
plt.ylabel("Count")
plt.xticks(rotation=45, ha="right")
plt.tight_layout()
plt.show()
Sorting categories by frequency makes large differences easier to see.
Check whether low-frequency categories are genuine, misspelled, or overly specific before combining them.
Bivariate Analysis: Explore Two Variables
Bivariate analysis examines the relationship between two variables.
The appropriate chart depends on whether the variables are:
- Numerical and numerical
- Categorical and numerical
- Categorical and categorical
- Time-based and numerical
Explore Two Numerical Variables with a Scatter Plot
A scatter plot displays one numerical variable on each axis.
plot_data = df.dropna(
subset=["age", "salary"]
)
plt.figure(figsize=(10, 6))
sns.scatterplot(
data=plot_data,
x="age",
y="salary"
)
plt.title("Relationship Between Age and Salary")
plt.xlabel("Age")
plt.ylabel("Salary")
plt.tight_layout()
plt.show()
Look for:
- Upward or downward trends
- Curved relationships
- Clusters
- Changes in spread
- Isolated observations
- Empty regions
A visible trend suggests an association, but it does not show that one variable causes the other.
Add a Category with hue
Use hue to represent a third variable:
plot_data = df.dropna(
subset=["age", "salary", "gender"]
)
plt.figure(figsize=(10, 6))
sns.scatterplot(
data=plot_data,
x="age",
y="salary",
hue="gender",
alpha=0.75
)
plt.title("Age and Salary by Gender")
plt.xlabel("Age")
plt.ylabel("Salary")
plt.legend(title="Gender")
plt.tight_layout()
plt.show()
This can reveal whether groups occupy different regions of the chart.
Do not interpret group differences without considering sample size, role, experience, location, selection effects, and other variables that may influence the result.
Add a Regression Line for Exploration
A regression plot adds a fitted linear trend:
plot_data = df.dropna(
subset=["age", "salary"]
)
plt.figure(figsize=(10, 6))
sns.regplot(
data=plot_data,
x="age",
y="salary",
scatter_kws={"alpha": 0.6}
)
plt.title("Linear Trend Between Age and Salary")
plt.xlabel("Age")
plt.ylabel("Salary")
plt.tight_layout()
plt.show()
The line summarises a linear relationship. It can be unhelpful when the true pattern is curved or when outliers strongly influence the fit.
Use the underlying scatter points to judge whether a straight line is a reasonable summary.
Compare Numerical Distributions Across Categories
Averages can hide important differences in spread, skewness, and outliers.
A grouped box plot shows more of the distribution:
plt.figure(figsize=(12, 6))
sns.boxplot(
data=df,
x="city",
y="rating"
)
plt.title("Rating Distribution by City")
plt.xlabel("City")
plt.ylabel("Rating")
plt.xticks(rotation=45, ha="right")
plt.tight_layout()
plt.show()
This allows you to compare:
- Medians
- Interquartile ranges
- Overall spread
- Potential outliers
- Differences in distribution shape
Show Individual Observations with a Strip Plot
For a smaller dataset, a strip plot displays the individual observations:
plt.figure(figsize=(12, 6))
sns.stripplot(
data=df,
x="city",
y="rating",
jitter=True,
alpha=0.6
)
plt.title("Individual Ratings by City")
plt.xlabel("City")
plt.ylabel("Rating")
plt.xticks(rotation=45, ha="right")
plt.tight_layout()
plt.show()
A strip plot can reveal sample size and overlapping values that an average alone would hide.
For larger datasets, consider a box plot, violin plot, or a sampled subset to reduce overplotting.
Compare Group Means with a Bar Plot
A Seaborn bar plot estimates a summary statistic for each category. The default estimator is the mean.
plt.figure(figsize=(12, 6))
sns.barplot(
data=df,
x="city",
y="rating",
estimator="mean",
errorbar=("ci", 95)
)
plt.title("Mean Rating by City with 95% Confidence Intervals")
plt.xlabel("City")
plt.ylabel("Mean Rating")
plt.xticks(rotation=45, ha="right")
plt.tight_layout()
plt.show()
The bars display estimated means, while the error bars communicate uncertainty around those estimates.
Confidence intervals do not show the full distribution. Combine a bar plot with counts, box plots, or individual observations when group sizes or variation matter.
To deliberately remove uncertainty intervals:
sns.barplot(
data=df,
x="city",
y="rating",
errorbar=None
)
Do this only when the simplified chart still communicates the information responsibly.
Explore Trends Over Time with a Line Plot
A line plot is useful when observations follow a meaningful time order.
First, ensure that the date column is a datetime type:
df["date"] = pd.to_datetime(
df["date"],
errors="coerce"
)
Aggregate daily sales:
daily_sales = (
df.dropna(subset=["date", "sales"])
.groupby("date", as_index=False)["sales"]
.sum()
.sort_values("date")
)
Plot the result:
plt.figure(figsize=(12, 6))
sns.lineplot(
data=daily_sales,
x="date",
y="sales"
)
plt.title("Total Sales Over Time")
plt.xlabel("Date")
plt.ylabel("Total Sales")
plt.tight_layout()
plt.show()
Look for:
- Long-term trends
- Seasonal patterns
- Sudden changes
- Missing periods
- Unusual spikes
- Changes in variability
A line connecting unordered categories can imply a sequence that does not exist. Use line plots only when the order between x-axis values is meaningful.
Multivariate EDA: Explore Several Variables
Multivariate analysis explores more than two variables at once.
Useful tools include:
- Correlation matrices
- Heatmaps
- Pair plots
- Hue and marker mappings
- Faceted charts
- Grouped summaries
Calculate a Correlation Matrix with pandas
A correlation coefficient summarises the direction and strength of an association between two numerical variables.
Calculate the Pearson correlation matrix:
corr_matrix = df.corr(
method="pearson",
numeric_only=True
)
corr_matrix
Pearson correlation measures linear association.
The coefficient ranges from -1 to 1:
- Values near
1indicate a strong positive linear association - Values near
-1indicate a strong negative linear association - Values near
0indicate little linear association
A value near zero does not prove that no relationship exists. The relationship may be non-linear.
Correlation also does not establish causation. A relationship may be influenced by confounding variables, selection effects, reverse direction, or coincidence.
Create a Correlation Heatmap
A heatmap makes a correlation matrix easier to scan.
corr_matrix = df.corr(
method="pearson",
numeric_only=True
)
plt.figure(figsize=(10, 8))
sns.heatmap(
corr_matrix,
annot=True,
fmt=".2f",
vmin=-1,
vmax=1,
center=0,
cmap="coolwarm",
square=True
)
plt.title("Pearson Correlation Matrix")
plt.tight_layout()
plt.show()
The colour scale is fixed between -1 and 1, making the positive and negative correlations easier to compare.
Hide the Repeated Half of the Matrix
A correlation matrix is symmetrical. You can hide the upper triangle to reduce duplication:
corr_matrix = df.corr(
method="pearson",
numeric_only=True
)
mask = np.triu(
np.ones_like(
corr_matrix,
dtype=bool
)
)
plt.figure(figsize=(10, 8))
sns.heatmap(
corr_matrix,
mask=mask,
annot=True,
fmt=".2f",
vmin=-1,
vmax=1,
center=0,
cmap="coolwarm",
square=True
)
plt.title("Lower Triangle of the Correlation Matrix")
plt.tight_layout()
plt.show()
For datasets with many numerical columns, annotations may become unreadable. Remove annot=True, increase the figure size, or display a selected group of features.
Compare Pearson and Spearman Correlation
Pearson correlation focuses on linear association.
Spearman correlation uses ranks and can capture a monotonic relationship that is not necessarily linear:
pearson_corr = df.corr(
method="pearson",
numeric_only=True
)
spearman_corr = df.corr(
method="spearman",
numeric_only=True
)
Compare the results when scatter plots suggest a curved but consistently increasing or decreasing pattern.
Neither method proves causation.
Use a Pair Plot for Several Numerical Variables
A pair plot creates a grid of pairwise charts:
selected_columns = [
"age",
"salary",
"price",
"rating",
"gender"
]
pair_data = df[selected_columns].dropna()
sns.pairplot(
data=pair_data,
hue="gender",
corner=True,
diag_kind="hist"
)
plt.show()
Pair plots are useful for quickly scanning a small collection of features.
They can become slow and visually crowded when the dataset has many columns or observations. Select only the variables relevant to the question.
Use Facets to Compare Groups
Faceting creates separate panels for groups:
sns.relplot(
data=df,
x="age",
y="salary",
col="city",
col_wrap=3,
kind="scatter",
height=4
)
plt.show()
Small multiples make it easier to compare the same relationship under different conditions without placing every group in one crowded chart.
Ensure that panels use comparable scales unless there is a clear reason not to.
Improve Chart Readability
A technically correct chart can still be difficult to interpret.
Write Descriptive Titles and Labels
Avoid titles such as:
Price Plot
Prefer a title that explains what is shown:
Distribution of Product Prices After Data Cleaning
Axis labels should include units when relevant:
plt.xlabel("Age (years)")
plt.ylabel("Annual Salary (€)")
Sort Categories Deliberately
For frequency charts:
order = df["city"].value_counts().index
For comparisons by a calculated metric:
order = (
df.groupby("city")["rating"]
.mean()
.sort_values(ascending=False)
.index
)
Then pass the order to the plotting function:
sns.barplot(
data=df,
x="city",
y="rating",
order=order
)
Handle Overlapping Labels
plt.xticks(
rotation=45,
ha="right"
)
Use plt.tight_layout() before plt.show() to reduce clipped labels.
Avoid Excessive Precision
A heatmap with many decimal places creates visual noise.
Use:
fmt=".2f"
Round summary tables to a sensible number of decimal places:
df.describe().round(2)
Consider Sample Size
A group with two observations should not be interpreted in the same way as a group with hundreds.
Check group sizes:
df.groupby("city").size().sort_values(
ascending=False
)
Consider adding counts to the analysis or excluding groups that do not meet a documented minimum sample-size rule.
Avoid Misleading Axes
Bar charts usually communicate magnitude relative to zero, so truncating the value axis can exaggerate small differences.
For a bar chart, verify the numerical axis begins at zero unless there is a strong reason and the choice is made explicit.
Line charts can sometimes use a narrower range to reveal meaningful variation, but the scale should remain clearly labelled.
Limit Unnecessary Colour
Colour should encode meaning.
Use colour to:
- Distinguish groups
- Show magnitude
- Highlight a specific result
- Separate positive and negative values
Do not assign a different colour to every bar when colour does not represent additional information.
Save a Chart
Use savefig() before show():
plt.figure(figsize=(10, 6))
sns.histplot(
data=df,
x="price",
bins=20
)
plt.title("Distribution of Product Prices")
plt.xlabel("Price")
plt.ylabel("Number of Observations")
plt.tight_layout()
plt.savefig(
"price-distribution.png",
dpi=300,
bbox_inches="tight"
)
plt.show()
A higher DPI produces a sharper raster image for reports and websites.
A Reusable EDA Workflow
The following workflow provides a practical starting point for a new dataset.
Step 1: Understand the Dataset
df.head()
df.shape
df.info()
Step 2: Measure Data Quality
df.isna().sum()
df.duplicated().sum()
Step 3: Review Summary Statistics
df.describe(include="all")
Step 4: Explore Important Numerical Variables
sns.histplot(
data=df,
x="price",
kde=True
)
plt.show()
Step 5: Explore Important Categories
sns.countplot(
data=df,
x="city"
)
plt.xticks(rotation=45)
plt.show()
Step 6: Examine Relationships
sns.scatterplot(
data=df,
x="age",
y="salary",
hue="gender"
)
plt.show()
Step 7: Compare Groups
sns.boxplot(
data=df,
x="city",
y="rating"
)
plt.xticks(rotation=45)
plt.show()
Step 8: Review Correlations
corr_matrix = df.corr(
numeric_only=True
)
sns.heatmap(
corr_matrix,
annot=True,
fmt=".2f",
vmin=-1,
vmax=1,
center=0,
cmap="coolwarm"
)
plt.show()
Step 9: Record Findings and Questions
For every chart, write down:
- What the chart shows
- What surprised you
- What could explain the pattern
- Whether missing values or sample size affect the result
- What should be investigated next
- What the chart does not prove
This turns a notebook from a collection of plots into a structured analysis.
Example EDA Findings
A strong finding is specific and cautious.
Weak statement:
Older customers earn more.
Improved statement:
In this dataset, salary generally increases across the observed age range, although the scatter is wide and the chart does not establish that age causes higher salary.
Weak statement:
City A has the best ratings.
Improved statement:
City A has the highest observed mean rating, but the group contains fewer observations and its uncertainty interval overlaps with several other cities.
Weak statement:
Price is normally distributed.
Improved statement:
The histogram is approximately symmetric and most points in the Q-Q plot follow the reference line, although the upper tail shows a visible departure from normality.
Careful wording makes the analysis more accurate and credible.
Common EDA Mistakes
Treating Correlation as Causation
A high correlation does not prove that changing one variable will change the other.
Use language such as:
- Associated with
- Related to
- Moves with
- Shows a positive or negative relationship
Avoid causal language unless the study design and analysis support it.
Using Only Averages
Two groups can have the same mean but very different distributions.
Use box plots, violin plots, strip plots, counts, or uncertainty intervals to provide context.
Removing Outliers Before Exploring Them
Outliers may represent errors, rare events, or the most interesting observations in the dataset.
Investigate them before deciding how they should be treated.
Plotting Every Column Without a Question
Producing dozens of charts is not the same as performing EDA.
Begin with the analysis goal and select charts that can answer relevant questions.
Ignoring Missing Values
Different plots may use different numbers of observations after dropping missing values.
Track the sample size behind important comparisons.
Overloading a Chart
Too many categories, colours, annotations, and variables can hide the main pattern.
Split a complex chart into several focused charts when necessary.
Calling a Q-Q Plot a Normality Test
A Q-Q plot is a visual diagnostic. It helps assess how closely a sample follows a theoretical distribution, but interpretation is subjective and depends on sample size.
Hiding Uncertainty Without a Reason
Removing error bars can make group estimates look more certain than they are.
Show uncertainty when comparing estimated statistics such as group means.
Exploratory Data Analysis Checklist
Before completing your EDA, confirm that you have:
- Checked the dataset shape and data types
- Measured missing values
- Reviewed numerical summary statistics
- Reviewed category frequencies
- Explored important numerical distributions
- Checked potential outliers
- Compared relevant groups
- Examined important numerical relationships
- Investigated trends over time when dates are available
- Calculated correlations only for suitable numerical variables
- Avoided interpreting correlation as causation
- Considered sample sizes and uncertainty
- Used clear titles and axis labels
- Recorded findings and limitations
- Identified questions for the next stage of analysis
Frequently Asked Questions
What is EDA in Python?
Exploratory data analysis in Python is the process of using data inspection, summary statistics, and visualisation to understand a dataset before formal modelling or testing.
Common tools include pandas, Matplotlib, Seaborn, SciPy, and specialised profiling libraries.
What is the difference between Matplotlib and Seaborn?
Matplotlib is a general plotting library that provides detailed control over chart elements.
Seaborn is built on Matplotlib and provides a higher-level interface for statistical visualisations and DataFrame-oriented plotting.
They are commonly used together.
Which chart should I use to show a distribution?
Use a histogram to show frequencies across intervals.
A KDE can show a smooth estimate of the distribution, a box plot summarises quartiles and potential outliers, and an ECDF shows cumulative proportions.
Using more than one view can provide a better understanding of the same variable.
How do I create a correlation heatmap in Python?
Calculate a numerical correlation matrix with pandas and pass it to Seaborn:
corr_matrix = df.corr(
numeric_only=True
)
sns.heatmap(
corr_matrix,
annot=True,
fmt=".2f",
vmin=-1,
vmax=1,
center=0,
cmap="coolwarm"
)
plt.show()
What does a correlation of zero mean?
A correlation near zero indicates little association of the type measured by the selected coefficient.
For Pearson correlation, that means little linear association. A strong non-linear relationship may still exist.
Does correlation prove causation?
No. Correlation measures association and does not establish a causal relationship.
How do I interpret a Q-Q plot?
Compare the plotted points with the reference line.
Points that approximately follow the line are consistent with the selected theoretical distribution. Systematic curves or departures at the tails indicate differences in shape.
Should I use a bar plot or box plot to compare groups?
Use a bar plot when the estimated group statistic itself is the focus and uncertainty is shown clearly.
Use a box plot when you want to compare medians, spread, and potential outliers. In EDA, box plots or plots of individual observations often provide more information than bars alone.
Why does Seaborn show error bars?
Functions that estimate a statistic, such as a group mean, can display uncertainty or variability around that estimate.
The exact interpretation depends on the selected errorbar setting.
How many charts should an EDA contain?
There is no fixed number.
Include enough charts to answer the important questions without repeating the same information or overwhelming the reader.
From Visualisation to Insight
This chapter completes the first three stages of the data science workflow:
- Environment setup: Create a reliable local or cloud-based Python environment.
- Data cleaning: Transform raw data into a validated dataset.
- Exploratory data analysis: Use statistics and visualisation to understand distributions, relationships, and unusual observations.
You now know how to:
- Inspect a DataFrame before plotting
- Choose charts based on data types and analysis goals
- Explore numerical and categorical distributions
- Compare groups with appropriate context
- Examine numerical relationships with scatter plots
- Visualise trends over time
- Create and interpret a correlation heatmap
- Use a Q-Q plot as a normality diagnostic
- Communicate patterns without confusing association with causation
The next stage is to turn the questions generated during EDA into formal statistical analyses or machine-learning experiments.