Introduction: Beyond Basic Plots

You've mastered creating basic visualizations and validating their consistency. Now you're ready for something more powerful: sophisticated matplotlib features that transform simple plots into publication-quality visualizations. Advanced features like regression lines with confidence intervals, outlier detection, threshold highlighting with shaded regions, and dual-axis plots are notoriously difficult to code manually — each requires memorizing complex syntax and understanding statistical formulas.

Here's the game-changer: you don't need to remember any of that. Simply describe the visual outcome you want, and Claude handles the implementation. Want to add a regression line with a confidence band and automatically detect outliers? Just ask. Need to highlight critical ranges with shaded regions? Describe what matters. Let's progressively enhance penguins visualizations, adding layers of sophistication with simple, descriptive prompts!

Your Foundation: Starting with a Clean Plot

Before adding advanced features, you need a solid baseline. Here's a simple scatter plot showing the relationship between flipper length and body mass in the penguins dataset — our foundation for enhancement:

import pandas as pd
import matplotlib.pyplot as plt

# Load the Palmer Penguins dataset
df = pd.read_csv('penguins.csv')

# Remove rows with missing values for plotting
df = df.dropna()

# Create a basic scatter plot of Body Mass vs Flipper Length
plt.figure(figsize=(10, 6))
plt.scatter(df['flipper_length_mm'], df['body_mass_g'], alpha=0.6, edgecolors='w')

plt.title('Penguin Body Mass vs Flipper Length')
plt.xlabel('Flipper Length (mm)')
plt.ylabel('Body Mass (g)')
plt.grid(True, linestyle='--', alpha=0.7)

plt.tight_layout()
plt.savefig('plot.png')
plt.show()

This baseline has everything you need: clear axis labels, visible pattern showing that flipper length and body mass are positively correlated, and a clean presentation. The relationship is clear — longer flippers correlate with heavier body mass.

What makes this a good foundation? It's uncluttered, the pattern is evident, and there's room to add analytical depth. When planning to add sophisticated features, always start by confirming your baseline communicates its core message clearly. If your foundation is messy, adding complexity will only make things worse. But with a clean starting point like this, advanced features can transform a simple plot into a rich, multi-layered analysis.

Enhancing with Regression Lines, Confidence Bands, and Outlier Detection

Let's add statistical depth to our plot. You can enhance it with three powerful features at once: a regression line summarizing the relationship, a confidence interval showing uncertainty, and automatic outlier detection. Here's how to prompt Claude:

> Modify and run plot.py to add a regression line with a 95% confidence band and annotate any outliers.

Claude implements all three enhancements automatically:

● Read(plot.py)
  ⎿ Read 21 lines

⏺ Now I'll modify the plot to add a regression line with 95% confidence band and 
  annotate outliers:

● Update(plot.py)
  ⎿ Updated plot.py with 41 additions and 2 removals

● Bash(python plot.py)
  ⎿ (No content)

● Bash(ls -lh plot.png)
  ⎿ -rw-r--r--. 1 runner runner 98K Dec 29 17:31 plot.png

● Read(plot.png)
  ⎿ Read image (97.4KB)

⏺ Done! I've successfully modified and run plot.py with the following enhancements:

  Changes made:
  1. Regression line - Added a red line showing the linear relationship (R² = 0.762)
  2. 95% confidence band - Added a pink shaded region showing the uncertainty around 
     the regression
  3. Outlier detection & annotation - Identified points with residuals > 2 standard 
     deviations and marked them with:
    - Red circles with black edges
    - Index numbers for identification

  The plot shows a strong positive correlation between flipper length and body mass, 
  with several outliers detected both above and below the regression line. Outliers 
  include penguins with unusually high or low body mass for their flipper length.

  The enhanced plot has been saved as plot.png.
Understanding What Claude Implemented

Notice what Claude handled automatically: calculating regression coefficients, computing the 95% confidence interval at each point, implementing outlier detection using residual analysis (identifying points more than 2 standard deviations from the regression line), implementing the fill_between() method with appropriate transparency, and choosing colors that stand out. You didn't need to remember scipy.stats.linregress(), calculate prediction intervals, or manage matplotlib's layering system. You simply described what you wanted to see.

Here's the enhanced visualization:

The regression line (in red) shows the overall trend with an R² = 0.762, indicating that flipper length explains about 76% of the variation in body mass. The confidence band (the pink shaded region) visualizes the uncertainty in this relationship — narrower where we have more data points, wider at the extremes.

The outlier detection reveals penguins that don't fit the general pattern. Each outlier is marked with a red circle and labeled with its index number, making it easy to investigate these unusual cases. These could be measurement errors, different subspecies, or genuinely exceptional individuals worth closer examination.

Highlighting Critical Ranges with Shaded Regions

Sometimes you need to draw attention to specific value ranges — perhaps categorizing data into low, normal, and high categories, or marking danger zones in safety data. Let's create a sophisticated visualization that highlights different body mass ranges using shaded regions and threshold lines:

> Highlight low and high body mass ranges on a body_mass vs flipper_length scatter plot using shaded regions and axhline/axvline, then label those regions.

Claude implements the range highlighting with statistical thresholds:

● Write(body_mass_ranges_plot.py)
  ⎿ Wrote 100 lines to body_mass_ranges_plot.py

● Bash(python body_mass_ranges_plot.py)
  ⎿ Body Mass Range Statistics:
    ==================================================
    Minimum Body Mass: 2700g
    Maximum Body Mass: 6300g
    Mean Body Mass: 4202g
    Median Body Mass: 4050g
    
    25th percentile (low threshold): 3550g
    75th percentile (high threshold): 4775g
    
    Penguins in low body mass range (<3550g): 77 (23.1%)
    Penguins in normal range (3550-4775g): 173 (52.0%)
    Penguins in high body mass range (>4775g): 83 (24.9%)

● Read(body_mass_ranges_plot.png)
  ⎿ Read image (573.6KB)

⏺ Done! I've created a comprehensive scatter plot with shaded regions highlighting 
  different body mass ranges.

  Key features:

  1. Shaded regions (using axhspan):
    - Blue region: Low body mass (<3,550g) - bottom 25%
    - Green region: Normal body mass range (3,550-4,775g) - middle 50%
    - Red region: High body mass (>4,775g) - top 25%
  2. Reference lines (using axhline and axvline):
    - Blue dashed line: Low threshold at 3,550g
    - Red dashed line: High threshold at 4,775g
    - Purple dotted line: Median flipper length at 197mm
  3. Color-coded scatter points:
    - Points colored to match their body mass range
    - Easy visual identification of which range each penguin falls into
  4. Labeled regions:
    - "HIGH BODY MASS" label in top left
    - "NORMAL RANGE" label in middle left
    - "LOW BODY MASS" label in bottom left
    - "Short Flippers" and "Long Flippers" labels at top

  Statistics:
  - 77 penguins (23.1%) in low body mass range
  - 173 penguins (52.0%) in normal range
  - 83 penguins (24.9%) in high body mass range

  The plot has been saved as body_mass_ranges_plot.png.
Understanding Range-Based Visualization

Here's the range-based visualization Claude created:

The visualization uses multiple techniques to highlight ranges. The axhspan() function creates the three horizontal shaded regions (blue for low, green for normal, red for high body mass), while axhline() draws the dashed threshold lines at the 25th and 75th percentiles. The axvline() adds a vertical reference line at the median flipper length, helping identify penguins with short versus long flippers.

Notice how the scatter points are color-coded to match their body mass range — this redundant encoding (both shaded background and point color) makes the categories immediately obvious. The text labels in each region eliminate any ambiguity about what each zone represents.

This technique is valuable whenever you need to categorize continuous data into meaningful ranges. Claude automatically calculated the percentile thresholds (3,550g and 4,775g), determined appropriate colors and transparency levels, and positioned the labels to avoid overlapping with data points. You didn't need to remember percentile calculations or matplotlib's text positioning syntax — you simply described wanting to highlight different ranges.

Creating a Dual-Axis Plot

Sometimes you want to compare two variables with dramatically different scales or even different units. Average body mass (in grams) and average flipper length (in millimeters) are perfect examples. Plotting them on the same y-axis would compress one variable so much that you couldn't see its patterns.

The solution is a dual-axis plot using matplotlib's twinx() function, which creates two separate y-axes sharing the same x-axis. This allows you to compare variables with incompatible scales side by side, revealing whether their patterns align or diverge.

Let's prompt Claude to create this sophisticated visualization showing species averages:

> Create a dual-axis plot from penguins.csv showing average body_mass_g (bars) and flipper_length_mm (line) by species using twinx, with a clear shared legend.

Claude implements the dual-axis structure with aggregated data:

● Write(dual_axis_plot.py)
  ⎿ Wrote 61 lines to dual_axis_plot.py

● Bash(python dual_axis_plot.py)
  ⎿ Summary Statistics by Species:
    ==================================================
      species  body_mass_g  flipper_length_mm
    0  Adelie      3700.66             189.95
    1  Chinstrap   3733.09             195.82
    2  Gentoo      5076.02             217.19

● Read(dual_axis_plot.png)
  ⎿ Read image (199.1KB)

⏺ Done! I've created a dual-axis plot showing the relationship between average body 
  mass and flipper length by species.

  Key features:
  - Blue bars (left y-axis): Average body mass in grams
  - Orange line (right y-axis): Average flipper length in millimeters
  - Shared legend: Both metrics clearly labeled in the upper left
  - Color-coded axes: Each y-axis matches its data color for easy reading

  Insights from the data:
  - Gentoo penguins are significantly larger with ~5,076g body mass and 217mm flippers
  - Adelie and Chinstrap have similar body masses (~3,700g)
  - Chinstrap penguins have slightly longer flippers (196mm) than Adelie (190mm)
  - Both metrics show the same ranking: Gentoo > Chinstrap > Adelie

  The plot has been saved as dual_axis_plot.png.
Interpreting the Dual-Axis Visualization

Here's the dual-axis visualization:

The left y-axis (in blue) shows body mass ranging from 3,500g to 5,500g, while the right y-axis (in orange) shows flipper length ranging from 185mm to 220mm. The blue bars represent average body mass for each species, and the orange line with markers shows average flipper length. The color-coding (blue axis label and bars for body mass, orange axis label and line for flipper length) helps viewers track which data belongs to which axis.

This plot reveals important relationships you couldn't easily see otherwise: both variables follow the same ranking pattern across species (Gentoo > Chinstrap > Adelie), suggesting that body mass and flipper length are closely related traits. The bars make it easy to compare absolute body mass values, while the line with markers helps you track the trend in flipper length across species.

Claude also automatically computed the species averages, created the dual-axis structure, implemented a shared legend combining both datasets, and matched axis colors to their corresponding data. You didn't need to remember how to use twinx(), manually calculate group means, or figure out legend positioning — you simply described wanting to compare two different metrics by species.

Summary: Focus on Outcomes, Not Syntax

You've learned to leverage Claude Code for sophisticated matplotlib features that would require extensive syntax knowledge to code manually. The key shift: describe the visual outcome you want; Claude handles the implementation. Whether adding regression lines with confidence intervals and outlier detection, highlighting ranges with shaded regions and threshold lines, or creating dual-axis comparisons of aggregated data, you focus on articulating insights, not memorizing syntax.

In the upcoming practice exercises, you'll apply these techniques to create publication-quality visualizations. Remember: describe what you want to see, and let Claude handle the complexity!

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal