Visualization with Matplotlib and Seaborn

Turn pandas tables into clear charts with Python. Build figures and axes in Matplotlib, draw line, scatter and bar charts, and plot straight from pandas after aggregating and reshaping the data. Use seaborn for statistical plots, histograms, box plots and heatmaps, compare groups with small multiples and facets, and finish each figure with labels and annotations before exporting it for a report or the web.

IntermediateLesson 7 of 8 in Data Analysis with Python Course

What you will learn

  1. Create a figure and its axes with Matplotlib's object-oriented interface, draw line, scatter and bar charts on them, and control titles, labels, ticks, limits, legends and styles.
    • Set up a figure and its axes
      Understand how a Matplotlib chart is built from a figure, one or more axes and the elements drawn on them, and choose between the pyplot and object-oriented ways of writing plotting code.
    • Draw line and scatter plots
      Draw values along an ordered axis with ax.plot and individual observations with ax.scatter, and control color, line style, markers, marker size and transparency.
    • Compare categories with bar charts
      Draw vertical, horizontal, grouped and stacked bar charts with ax.bar and ax.barh, and label the bars with their values.
    • Label, scale and style a plot
      Set titles, axis labels, limits, ticks, tick formats, scales, legends and grids, and change the overall look of plots with style sheets and settings.
  2. Draw charts straight from Series and DataFrames with the pandas plot method, and aggregate, sort and reshape tables first so that each chart shows the intended values.
    • Use the pandas plot method
      Create line, bar, histogram, box, area, pie and scatter plots from a Series or DataFrame, and customize the Matplotlib axes they return.
    • Shape the data before plotting
      Aggregate, count, sort, pivot and melt a table so that it holds exactly the values a chart should show, in the format pandas or seaborn expects.
  3. Use seaborn to map DataFrame columns to positions, colors and styles, show relationships between numeric variables with trend summaries, and compare groups with categorical plots.
    • Map columns to plot features in seaborn
      Name DataFrame columns for position, color, style and size, tell axes-level from figure-level functions, and set seaborn themes and palettes.
    • Show relationships between numeric variables
      Draw scatter plots, aggregated line plots with uncertainty bands, regression lines and pair plots with seaborn, and read what the bands and lines do and do not show.
    • Compare groups with categorical plots
      Compare a numeric variable across categories with bar, count, point, strip and swarm plots, and choose their estimator, error bars, order and orientation.
  4. Show how a numeric variable is distributed with histograms, density curves, box plots and violin plots, and display a table of values or correlations as a heatmap.
    • Show a distribution with histograms and density curves
      Build histograms in Matplotlib, pandas and seaborn, choose bins and scales, and add or compare smoothed density curves.
    • Summarize and compare distributions with box plots
      Read and draw box plots from quartiles and the 1.5 × IQR rule, compare groups with them, and use violin and strip plots to show what a box hides.
    • Display a grid of values as a heatmap
      Turn a pivot table or a correlation matrix into a heatmap with seaborn or Matplotlib, and control annotations, number formats, color scales and color limits.
  5. Arrange small multiples with Matplotlib subplots and seaborn facets, point out what matters with text, arrows and reference lines, and save figures in the right format and size for reports and the web.
    • Arrange several plots in one figure
      Create grids of Axes with plt.subplots, share scales between panels, fill the panels in a loop, fix spacing and titles, and build panels of unequal size.
    • Facet data with seaborn
      Split a plot into panels by one or two categorical variables with the col, row and col_wrap arguments of figure-level functions or with FacetGrid, and customize the resulting grid.
    • Add annotations and reference lines
      Place text, arrows, reference lines, shaded ranges and value labels on a plot, in data coordinates or in coordinates relative to the axes.
    • Save figures for reports and the web
      Export figures with savefig in raster or vector formats, control size, resolution, margins and background, and save at the right moment in scripts, notebooks and loops.

Matplotlib and Seaborn study guide

5 chapters

1

Build plots with Matplotlib figures and axes

A plotting command needs somewhere to draw. Matplotlib makes that place explicit: a figure holds one or more plotting areas, and each area holds the marks and labels. Start with one area, then use the same objects to add lines, points, bars, and useful settings. Keeping a name for the figure and each plotting area makes it easier to change the right chart when a notebook grows or a figure contains several panels.

1.1 Set up a figure and its axes

Matplotlib is the standard plotting library for Python, and pandas and seaborn both draw with it. It is imported by convention as import matplotlib.pyplot as plt. In a Jupyter notebook a chart appears below the cell that draws it; in a script, plt.show() displays the open figures and, in a normal script, waits until their windows are closed.

A Figure is the whole canvas: the image that is shown or saved. An Axes is one plotting area inside the figure, with its own data, title, axis labels and limits; one figure can hold several. An Axis (singular) is one number line of an Axes, the x-axis or the y-axis, with its ticks and tick labels. Every visible item, such as a line, a marker, a text or a bar, is called an artist.

fig, ax = plt.subplots() creates a figure with one Axes and returns both objects. figsize=(width, height) sets the figure size in inches. The default is 6.4 × 4.8 inches at 100 dots per inch, so a default figure is 640 × 480 pixels on screen; plt.subplots(figsize=(8, 4)) makes a wider, flatter figure.

Matplotlib offers two styles. In the object-oriented style you call methods on explicit objects: ax.plot(...), ax.set_title(...). In the pyplot style, functions such as plt.plot(...) and plt.title(...) act on the "current" Axes, usually the one created last. Both draw the same charts; the object-oriented style is clearer as soon as a figure has more than one Axes or plotting code goes into a function, so this course uses it.

The two styles use different names for the same settings: plt.title, plt.xlabel and plt.xlim correspond to ax.set_title, ax.set_xlabel and ax.set_xlim. A frequent error is ax.title("Rainfall"): on an Axes, title is an attribute that holds a text object, so calling it raises TypeError: 'Text' object is not callable. Use ax.set_title("Rainfall").

months = [1, 2, 3, 4, 5, 6]; temp_c = [3, 5, 9, 13, 17, 20], then

fig, ax = plt.subplots(figsize=(8, 4))
ax.plot(months, temp_c)
ax.set_title("Mean monthly temperature")
ax.set_xlabel("Month")
ax.set_ylabel("Temperature (°C)")

.

Drawing calls add to an Axes; they do not replace what is there. A second ax.plot(...) on the same ax adds a second line to the same chart. To get a separate chart, create a new figure with another plt.subplots() call, or draw on a different Axes of a multi-panel figure.

pyplot keeps every figure it created open until it is closed with plt.close(fig) or plt.close("all"). Open figures use memory, and once more than 20 are open Matplotlib warns about it. Code that creates figures in a loop should close each figure after saving it.

Key Takeaways

  • A figure is the canvas; an Axes is a plotting area.
  • Call methods on the Axes that should receive the change.
  • Drawing again on the same Axes adds artists.
  • Close saved figures in loops.

1.2 Draw line and scatter plots

ax.plot(x, y) draws markers or straight line segments that join the points in the order they are given. A line plot suits a quantity measured along an ordered variable such as time or distance. With one argument, ax.plot(y), the x-values default to 0, 1, 2, ….

Because points are joined in the order given, unsorted x-values produce a zigzag that runs back and forth across the chart. For x = [3, 1, 2] the line goes from x = 3 back to x = 1 and then forward to x = 2. Sort the data by x first, for example with df.sort_values("x").

Style arguments: color (a name such as "black" or "tab:orange", or a hex code such as "#1f77b4"), linestyle ("-" solid, "--" dashed, ":" dotted, "-." dash-dot), linewidth, marker ("o" circle, "s" square, "^" triangle) and markersize. A short format string combines marker and line style: ax.plot(x, y, "o--") draws circles joined by a dashed line. Without a color, each new line takes the next color of the default cycle, which starts with "tab:blue" and "tab:orange".

Give each line a label and call ax.legend() to show a legend:

ax.plot(months, north, marker="o", label="North")
ax.plot(months, coast, linestyle="--", label="Coast")
ax.legend()

. If no artist has a label, ax.legend() draws nothing and Matplotlib warns that no artists with labels were found.

ax.scatter(x, y) draws one unconnected marker per observation and suits the relationship between two numeric variables. Example: daily temperature [12, 15, 18, 21, 24, 27, 30, 22] °C and bike rentals [180, 220, 260, 310, 330, 360, 340, 250]; ax.scatter(temp_c, rentals) shows rentals mostly rising with temperature, and the correlation of the two lists is about 0.92.

In ax.scatter, s sets each marker's area in points squared; the default is 36, the area of a marker 6 points wide. Doubling s doubles the area, so the marker's width grows only by a factor of about 1.4. s can be one number or one value per point, which lets marker size show a third variable.

c colors the points: one color for all, or one number per point mapped through a colormap such as cmap="viridis". Keep the returned object and add a color key: sc = ax.scatter(temp_c, rentals, c=rain_mm, cmap="viridis"); fig.colorbar(sc, ax=ax, label="Rain (mm)").

When many points overlap (overplotting), dense regions turn into solid blobs and hide how many points they contain. Lower the opacity with alpha=0.3, use smaller markers, or show density instead, for example with a hexagonal binning plot (df.plot.hexbin) or a two-dimensional histogram.

ax.plot(x, y, "o") with a marker and no line also draws points, and it is faster for very many points because all markers share one size and color. Use ax.scatter when size or color must vary from point to point.

Key Takeaways

  • Lines connect points in their supplied order.
  • Scatter size is area in points squared.
  • A numeric color mapping needs a color bar.
  • Use labels and a legend to identify series.
  • Transparency helps reveal overlapping observations.

1.3 Compare categories with bar charts

ax.bar(categories, heights) draws one vertical bar per category; ax.barh(categories, widths) draws horizontal bars, which leave room for long category names. When the categories are strings, Matplotlib places them at equally spaced positions in the order given and uses them as tick labels. When they are numbers, the bars stand at those numeric positions on an ordinary numeric axis.

Bars start at a baseline of 0 by default, so a bar's length shows its value. The width argument is measured in x-axis units and is 0.8 by default. String categories are placed one unit apart, so the default leaves a gap of 0.2 between bars, and width=1 makes neighboring bars touch.

200 commuters were asked how they usually travel: car 84, bus 52, bike 38, walk 26. ax.barh(["Car", "Bus", "Bike", "Walk"], [84, 52, 38, 26]) draws four horizontal bars. The shares are 42%, 26%, 19% and 13%, which add up to 100%.

ax.barh puts the first category at the bottom of the axis, because the y-axis grows upward. To read a ranked list from the top, as in the commuting example, call ax.invert_yaxis(), or reverse both the categories and their values before plotting, so that each value stays with its category.

Grouped bars place several series side by side in each category. Use numeric positions and shift each series by half a bar width:

x = np.arange(3)
ax.bar(x - 0.2, north, width=0.4, label="North")
ax.bar(x + 0.2, coast, width=0.4, label="Coast")
ax.set_xticks(x, labels=["Jan", "Feb", "Mar"])
ax.legend()

. The North bars stand at −0.2, 0.8 and 1.8, the Coast bars at 0.2, 1.2 and 2.2, centered on each tick.

Stacked bars draw a second series on top of the first with bottom=: ax.bar(days, car); ax.bar(days, bus, bottom=car). If a day has 40 car trips and 25 bus trips, the bus segment runs from 40 to 65, and the total bar height is 65.

bars = ax.bar(...) returns a container of bars; ax.bar_label(bars) writes each value at the end of its bar. fmt controls the text: fmt="%.1f" writes 3.14 as "3.1", and fmt="{:.0f} km" writes it as "3 km".

Matplotlib draws bars in the order of the data, not in order of size. For a ranked chart, sort the values first, for example with sorted() on pairs or sort_values() in pandas. The yerr= argument adds error bars of a given length to each bar, and ax.errorbar(x, y, yerr=...) does the same for points.

A bar chart compares values of separate categories, so its bars stand apart with gaps. A histogram, by contrast, shows how one numeric variable is distributed over adjacent intervals, and its bars touch. Drawing measurements as one bar per row of data is a bar chart of raw values, not a histogram.

Key Takeaways

  • Keep categories paired with their values when sorting.
  • Grouped bars use offsets around category ticks.
  • Stacked bars use cumulative bottoms.
  • Bar labels belong to the returned container.

1.4 Label, scale and style a plot

Set text with ax.set_title("..."), ax.set_xlabel("...") and ax.set_ylabel("..."), or with one call: ax.set(title="Monthly rainfall", xlabel="Month", ylabel="Rainfall (mm)"). Put the unit in the axis label, for example "Rainfall (mm)" or "Distance (km)", so each tick value has a meaning.

Matplotlib chooses axis limits from the data plus a small margin. Set them yourself with ax.set_xlim(1, 12) and ax.set_ylim(0, 120), or fix one end only with ax.set_ylim(bottom=0). ax.set(xlim=(1, 12), ylim=(0, 120)) does the same in one call.

ax.set_xticks([1, 4, 7, 10]) chooses tick positions, and ax.set_xticks([1, 2, 3], labels=["Jan", "Feb", "Mar"]) also replaces their labels. Rotate crowded labels with ax.tick_params(axis="x", labelrotation=45). Tick formatters change how values are written: ax.yaxis.set_major_formatter(PercentFormatter(xmax=1, decimals=0)), with PercentFormatter imported from matplotlib.ticker, labels the value 0.25 as "25%".

ax.set_yscale("log") puts the y-axis on a logarithmic scale, where equal distances stand for equal ratios: the step from 10 to 100 is as long as the step from 100 to 1,000. It suits values that span several orders of magnitude, such as city populations. A logarithmic axis cannot show zero or negative values.

ax.legend() places the legend where it covers the fewest points (loc="best", the default for an Axes legend). Choose a spot with loc="upper left", add a heading with title="Station" and spread entries over columns with ncols=2. ax.legend(bbox_to_anchor=(1.02, 1), loc="upper left") puts the legend just outside the right edge of the plotting area.

ax.grid(True, alpha=0.3) adds light grid lines at the ticks; ax.grid(axis="y") draws only horizontal ones, which helps reading bar heights.

Style sheets change the default look of every later chart: plt.style.use("ggplot"). plt.style.available lists the installed styles; the seaborn-like styles that ship with Matplotlib are named, for example, "seaborn-v0_8-whitegrid". To apply a style to one block of code only, use with plt.style.context("ggplot"):.

Single default settings live in plt.rcParams, for example plt.rcParams["font.size"] = 12 or plt.rcParams["figure.figsize"] = (8, 4). They apply to figures created afterwards, and plt.rcdefaults() restores Matplotlib's defaults.

fig, ax = plt.subplots(figsize=(8, 4))
ax.plot([1, 2, 3, 4], [62, 48, 55, 40], marker="o", label="North")
ax.set(title="Monthly rainfall, January to April", xlabel="Month", ylabel="Rainfall (mm)", ylim=(0, 70))
ax.set_xticks([1, 2, 3, 4], labels=["Jan", "Feb", "Mar", "Apr"])
ax.legend()
ax.grid(axis="y", alpha=0.3)

.

In a figure with several Axes, pyplot functions such as plt.title or plt.xlabel change only the current Axes, usually the one created last, so a title can land on the wrong panel. Calling the methods of the intended Axes, such as axes[0].set_title(...), avoids this.

Key Takeaways

  • Tick formatting changes labels without changing values.
  • Log scales show equal ratios as equal distances.
  • Styles and rcParams set defaults for later charts.
2

Plot data directly from pandas

A pandas table often already holds the labels and values a chart needs. Its plotting methods use those labels to build a Matplotlib chart, which you can then finish with the same methods as a hand-built plot. The important work often happens before drawing: deciding what one row represents, calculating the right summary, and arranging the table so that groups, series, and their order match the question.

2.1 Use the pandas plot method

Build the wide rainfall table with one column per station:

import pandas as pd
wide = pd.DataFrame({
    "North": [62, 48, 55, 40],
    "Coast": [110, 95, 80, 60],
    "Valley": [20, 15, 30, 45]
}, index=pd.Index(["Jan", "Feb", "Mar", "Apr"], name="month"))

Every pandas Series and DataFrame has a .plot method that draws with Matplotlib and returns the Matplotlib Axes it drew on. df.plot(kind="bar") and df.plot.bar() are the same call. The kinds are "line" (the default), "bar", "barh", "hist", "box", "kde" or "density", "area", "pie", "scatter" and "hexbin".

By default the index becomes the x-axis and every numeric column becomes one line, with a legend built from the column names. A Series plots its values against its index. To choose columns, pass x="month" and y="rain_mm", or a list such as y=["North", "Coast"].

a table wide with the index Jan, Feb, Mar, Apr and the columns North [62, 48, 55, 40], Coast [110, 95, 80, 60] and Valley [20, 15, 30, 45], all in millimeters of rain. ax = wide.plot(marker="o", figsize=(8, 4), title="Monthly rainfall"); ax.set_ylabel("Rainfall (mm)") draws three labeled lines in one Axes and then sets the y-label with an ordinary Matplotlib method.

Common arguments of .plot: title, xlabel, ylabel, xlim, ylim, figsize, color, legend=False, rot (tick-label rotation in degrees), grid=True and logy=True. ax= draws into an existing Axes, for example one panel of plt.subplots(1, 2), instead of a new figure.

subplots=True draws each column in its own Axes and returns a NumPy array of Axes instead of a single one; layout=(2, 2) arranges them in a grid and sharey=True gives them one y-scale. For the three-station table, wide.plot(subplots=True, layout=(1, 3), sharey=True) gives one panel per station.

Scatter and hexbin plots exist only for DataFrames and need both x and y: days.plot.scatter(x="temp_c", y="rentals", c="rain_mm", colormap="viridis") colors the points by rain. A Series has no scatter plot, so s.plot.scatter() raises an error. df.plot.hist(bins=5) and df.plot.box() give a histogram and a box plot of each numeric column.

s.plot.pie() draws one wedge per value, sized by its share of the total. Since pie charts need a Series of nonnegative parts of one whole, a column of counts such as s.value_counts() is a typical input.

Bar plots in pandas treat the index as categories and place the bars at positions 0, 1, 2, … whatever the index values are. Line plots use the actual index values when they are numbers or dates. A pandas line and a pandas bar drawn on the same Axes therefore line up only when the line's x-values match the bar positions, as with a default index 0, 1, 2, …; for years such as 2020 to 2023 the line sits far to the right of the bars. Plot both against the same positions when combining them.

With a DatetimeIndex, .plot() puts dates on the x-axis and labels them automatically. Daily data are often clearer after resampling, for example to monthly means with s.resample("MS").mean().plot().

.plot draws numeric columns only. If numbers were read as text, for example because a column contains "12 mm", the column is skipped, and when no numeric data is left pandas raises TypeError: no numeric data to plot. Convert the column first, for example with pd.to_numeric(...).

Key Takeaways

  • Pandas plots numeric data and uses the index by default.
  • Pass an Axes with ax= to reuse a panel.
  • Separate subplots return an array of Axes.
  • Pandas bars and numeric lines use different position rules.

2.2 Shape the data before plotting

A chart draws the values that are in the table, so summarize first. Example: a long table rain with 12 rows, one per station and month, and the columns month, station and rain_mm. rain.groupby("station")["rain_mm"].mean() gives one mean per station: Coast 86.25 mm, North 51.25 mm and Valley 27.5 mm. Adding .plot.bar() draws three bars.

Plotting raw rows by mistake gives individual readings instead of the requested means: rain.plot.bar(x="station", y="rain_mm") draws 12 bars with repeated station names instead of three means.

Sort before plotting to get ranked bars: means.sort_values(ascending=False).plot.bar() puts the largest mean on the left. For a horizontal chart, means.sort_values().plot.barh() puts the largest at the top, because the first value is drawn at the bottom.

s.value_counts() counts how often each category occurs and lists the counts from most to least frequent. For the travel modes "bus", "car", "bus", "bike", "bus", "car" it gives bus 3, car 2, bike 1, ready for .plot.bar(). Use .sort_index() or .reindex([...]) when the categories have a natural order, such as days of the week.

A DataFrame in wide format, with one column per series, gives one line or bar color per column in pandas. Reshape a long table with rain.pivot(index="month", columns="station", values="rain_mm"). When some index and column pair occurs more than once, pivot raises an error; use pivot_table(..., aggfunc="mean") instead, or groupby(["month", "station"])["rain_mm"].mean().unstack().

pivot and pivot_table sort the new index, so string months come out in alphabetical order, Apr, Feb, Jan, Mar, and a line plot then runs through the months in the wrong order. Restore the real order with wide.reindex(["Jan", "Feb", "Mar", "Apr"]), or store the month as an ordered categorical or as a month number before pivoting.

On a wide table, wide.plot.bar() draws grouped bars, one group per index label and one color per column, while wide.plot.bar(stacked=True) stacks the columns. The transpose wide.T.plot.bar() swaps the roles: one group per station, one color per month.

For shares within each group, normalize a cross-tabulation: pd.crosstab(trips["region"], trips["mode"], normalize="index") divides every count by its row total, so each row sums to 1. If region N has two car trips and one bus trip, its row is car 0.67 and bus 0.33 (rounded). .plot.bar(stacked=True) then draws bars of equal total height that show each region's mix.

seaborn works best with long (tidy) data: one row per observation and one column per variable. wide.reset_index().melt(id_vars="month", var_name="station", value_name="rain_mm") turns the 4 × 3 wide table back into 12 rows with three columns, so station can be used for color or facets.

Key Takeaways

  • Aggregate rows before plotting the required summary.
  • A duplicate pivot pair requires an aggregation rule.
  • Wide data suit series columns; long data suit semantic mappings.
  • Restore meaningful category order after reshaping.
  • Normalize each row to compare group shares.
3

Make statistical plots with seaborn

Statistical charts connect table columns to visual features and often calculate a summary while drawing. Seaborn handles both jobs through named arguments. A short call can show groups in different colors, average repeated observations, or split a table into panels. Read these defaults carefully: a chart of individual observations and a chart of group means can start from the same rows but answer different questions.

3.1 Map columns to plot features in seaborn

seaborn is a plotting library built on Matplotlib that works directly with pandas DataFrames and computes common statistical summaries itself. It is imported by convention as import seaborn as sns. A typical call names the table and its columns: sns.scatterplot(data=days, x="temp_c", y="rentals").

Besides x and y, columns can be mapped to other features (semantic mappings): hue sets the color, style the marker or dash pattern, and size the marker size or line width. seaborn picks the colors and builds the legend itself. A categorical hue column gets distinct colors; a numeric one gets a gradient.

Each mapping needs a column in long format. With the long rainfall table, sns.lineplot(data=rain, x="month", y="rain_mm", hue="station", marker="o") draws one colored line per station with a legend. If hue names a column that is not in the table, seaborn raises a ValueError saying it could not interpret the value.

When x holds strings, seaborn places the categories in the order they first appear in the data, so months stored as "Jan", "Feb", "Mar" in that row order stay in calendar order. The categorical functions, such as barplot, boxplot and countplot, accept order=["Mon", "Tue", "Wed"] to set the category order, and hue_order sets the order of the hue groups in every function that has hue. lineplot has no order argument: to fix the order of month names there, make the x-column an ordered categorical, for example pd.Categorical(rain["month"], categories=["Jan", "Feb", "Mar", "Apr"], ordered=True).

Axes-level functions, such as scatterplot, lineplot, histplot, boxplot, barplot and heatmap, draw into one Matplotlib Axes, accept ax= to choose that Axes and return it. Figure-level functions, relplot, displot, catplot and lmplot, create their own figure, can split it into panels with col and row, and return a seaborn FacetGrid object.

Figure-level functions are sized per panel: height is each panel's height in inches and aspect its width-to-height ratio, so each panel is height × aspect inches wide; the defaults are 5 and 1. Because they create their own figure, they cannot draw into an existing Axes: relplot, displot and catplot warn and ignore ax=, and lmplot rejects it with a TypeError. They place the legend outside the panels.

sns.set_theme() switches all later charts, including plain Matplotlib ones, to seaborn's look: the "darkgrid" style, the "notebook" context and seaborn's default palette. style can be "darkgrid", "whitegrid", "dark", "white" or "ticks"; context can be "paper", "notebook", "talk" or "poster" and scales fonts and lines, for example from a 12-point base font for "notebook" to 18 points for "talk".

palette chooses the colors for hue, for example palette="colorblind", "Set2" or "viridis". In seaborn 0.13, passing palette without hue is deprecated; to color bars by category, set hue to the same column as x and add legend=False: sns.barplot(data=rain, x="station", y="rain_mm", hue="station", legend=False).

The result can be finished with Matplotlib:

ax = sns.scatterplot(...)
ax.set(xlabel="Temperature (°C)", ylabel="Rentals per day", title="Rentals and temperature")

. For a figure-level result, use the grid's methods, such as g.set_axis_labels("Temperature (°C)", "Rentals per day"), and g.figure.suptitle("...") for an overall title.

Key Takeaways

  • Semantic mappings connect columns to visual features.
  • Axes-level functions accept an existing Axes.
  • Figure-level functions create and size their own panels.
  • Themes affect later charts across both libraries.

3.2 Show relationships between numeric variables

sns.scatterplot(data=days, x="temp_c", y="rentals", hue="weekday", size="rain_mm") draws one point per row, colored and sized by further columns. Combining hue and style with the same column gives each group a distinct color and marker, which still reads in grayscale.

sns.lineplot aggregates by default: when several rows share an x-value, it draws the line through the mean of their y-values and shades a band for the 95% confidence interval of that mean, computed by bootstrapping. Worked example: at x = 1 the y-values are 10, 12 and 14, at x = 2 they are 20, 21 and 25; the line passes through 12 and 22.

The default band shows the uncertainty of each mean, not the range of the data. errorbar="sd" shades one standard deviation above and below the mean instead, errorbar=None removes the band, and estimator=None (together with units=) draws each individual series without averaging. With one row per x-value there is nothing to average and no band.

sns.regplot(data=days, x="temp_c", y="rentals") draws a scatter plot with a least-squares straight line and a shaded 95% confidence band for that line; order=2 fits a quadratic curve instead. sns.lmplot does the same as a figure-level function, so it can also split the data by hue, col or row.

A fitted line summarizes the data with the model you chose. A straight line can be drawn through curved data, so look at the points around the line before trusting it. A strong trend shows that the variables are associated in this data, without establishing a cause.

sns.pairplot(df) draws a grid with a scatter plot for every pair of numeric columns and each column's distribution on the diagonal: histograms by default, density curves when hue is set. Four numeric columns give a 4 × 4 grid of 16 panels. corner=True keeps only the lower triangle, and vars=[...] limits the columns. It returns a PairGrid.

sns.jointplot(data=days, x="temp_c", y="rentals") draws a scatter plot with each variable's histogram along its edges; kind="hex" replaces the points with hexagonal bins, which helps with large data sets.

sns.relplot(..., kind="scatter") and sns.relplot(..., kind="line") are the figure-level versions of scatterplot and lineplot; scatter is the default kind. Use them when the same relationship should be shown in separate panels for each group.

sns.regplot(data=days, x="temp_c", y="rentals") shows rentals rising from 180 at 12 °C toward about 350 at the warmest days, with a correlation of about 0.92. The 30 °C day has fewer rentals (340) than the 27 °C day (360), so the points flatten at the top; a quadratic fit (order=2) can be compared with the straight line.

Key Takeaways

  • Default seaborn lines average repeated observations.
  • A confidence band describes uncertainty in an estimate.
  • Use units and no estimator to preserve individual trajectories.
  • Inspect points as well as fitted lines.
  • Pair plots compare variables and their distributions.

3.3 Compare groups with categorical plots

seaborn's categorical functions place each category at positions 0, 1, 2, … on the categorical axis. Even numbers are treated as labels: years 2020, 2021 and 2023 are drawn equally spaced, with no gap for 2022. native_scale=True keeps a numeric axis with real spacing.

sns.barplot(data=rain, x="station", y="rain_mm") draws one bar per station whose height is the mean of its rows, with an error bar for the 95% confidence interval of that mean. With the rainfall table the bars are Coast 86.25, North 51.25 and Valley 27.5 mm. estimator="median" or estimator="sum" changes the summary; errorbar="sd" or errorbar=None changes or removes the error bars.

sns.countplot(data=trips, x="mode") counts the rows in each category and needs no numeric column; sns.barplot summarizes a numeric column. Use countplot for "how many", barplot for "how much on average".

sns.pointplot shows each group's mean as a point with an error bar and joins the points of each hue group with a line. It makes changes across categories easy to compare, for example the mean rainfall of three stations in each of four months.

A bar of means hides the spread and the number of observations: a mean of 3 rows looks as solid as a mean of 300. Showing the data is often better: sns.stripplot draws every observation as a point with a little random jitter, and sns.swarmplot arranges the points so that they do not overlap. A strip plot can be drawn over a box plot or bar chart on the same Axes.

With hue, bar, box and violin plots place the groups side by side within each category (dodging) by default. Point, strip and swarm plots draw the groups at the same position unless dodge=True is set, so their points can overlap. Set the category order with order=[...] and the group order with hue_order=[...].

Orientation follows the data: put the categories on the y-axis and the numbers on the x-axis, sns.barplot(data=rain, x="rain_mm", y="station"), to get horizontal bars with readable long labels. orient="y" (or "h") states this explicitly.

sns.catplot is the figure-level function for all categorical plots. Its kind can be "strip" (the default), "swarm", "box", "violin", "boxen", "point", "bar" or "count", and col or row splits the plot into panels.

Key Takeaways

  • Count plots count rows; bar plots summarize numeric values.
  • Strip and swarm plots reveal observations.
  • Dodging separates hue groups within a category.
4

Visualize distributions and grids of values

A distribution chart describes a collection of measurements, while a heatmap describes a table through color. These plots compress many values, so their settings affect what you can read. Bin edges decide which observations are counted together; quartiles and whiskers summarize different parts of a sample; a color scale maps numbers to shades. Work through those calculations before interpreting the finished image.

4.1 Show a distribution with histograms and density curves

A histogram splits the range of a numeric variable into adjacent intervals called bins and draws a bar over each bin whose height is the number of observations in it. It shows the shape of a distribution: where values are centered, how spread out they are, whether they are skewed, and gaps or unusual values.

counts, edges, patches = ax.hist(data, bins=5) draws the histogram and returns the count in each bin and the bin edges. With an integer, the bins have equal width from the minimum to the maximum; the default is 10 bins. Each bin includes its left edge and excludes its right edge, except the last bin, which includes both.

20 commute times in minutes: 12, 15, 18, 20, 22, 22, 25, 27, 28, 30, 31, 33, 35, 38, 40, 42, 45, 50, 55, 62. With bins=5 the edges are 12, 22, 32, 42, 52 and 62, and the counts are 4, 7, 4, 3 and 2. The value 22 falls in the second bin because bins exclude their right edge, and 62 counts in the last bin because the last bin includes it.

The number and position of bins change the picture. The same 20 times with edges [10, 20, 30, 40, 50, 60, 70] give the counts 3, 6, 5, 3, 2 and 1. Too few bins hide the shape; too many make a jagged chart with many near-empty bins. Try several settings, and prefer round bin edges that readers can interpret, such as 10-minute steps.

density=True in Matplotlib, or stat="density" in seaborn, scales the bars so that their total area is 1: each height is count ÷ (n × bin width). For the commute data with five 10-minute bins, the second bar's height is 7 ÷ (20 × 10) = 0.035 per minute. A density height is not a probability; height × bin width is the proportion of observations in the bin.

sns.histplot(data=commutes, x="minutes") draws a histogram with seaborn; bins and binwidth control the bins. stat chooses the height: "count" (default), "probability" or "proportion" (heights sum to 1), "percent" (heights sum to 100) and "density" (area 1). For the five commute bins, "probability" gives 0.2, 0.35, 0.2, 0.15 and 0.1.

To compare groups, sns.histplot(data=commutes, x="minutes", hue="mode") overlays one histogram per group; multiple="stack" stacks them, multiple="dodge" places them side by side, and element="step" draws outlines that overlap more readably. Groups of different sizes are compared fairly with stat="density", common_norm=False, which scales each group to an area of 1.

A kernel density estimate (KDE) is a smooth curve that estimates the shape of the distribution; the area under it is 1. sns.kdeplot(data=commutes, x="minutes") draws it, and sns.histplot(..., kde=True) adds it to a histogram. bw_adjust above 1 makes the curve smoother, below 1 more detailed.

A KDE curve extends beyond the smallest and largest values, so it can show density below 0 minutes for times that cannot be negative. cut=0 stops the curve at the data limits. For small samples, the curve can suggest a shape that the data do not support.

In pandas, commutes["minutes"].plot.hist(bins=5, edgecolor="white") draws a histogram (default 10 bins), and df.hist() draws one histogram per numeric column in a grid. In seaborn, sns.displot is the figure-level version: kind="hist" (default), kind="kde" or kind="ecdf", where an ECDF shows for every value the proportion of observations at or below it.

Key Takeaways

  • Histogram boundaries determine bin membership.
  • Density uses area to represent a share.
  • A KDE smooths a distribution and depends on bandwidth.
  • Normalize groups independently to compare shapes.

4.2 Summarize and compare distributions with box plots

A box plot summarizes a distribution: the box runs from the first quartile (Q1) to the third quartile (Q3), a line inside marks the median, whiskers extend toward the smallest and largest typical values, and points beyond the whiskers are drawn one by one as possible outliers (fliers). The interquartile range IQR = Q3 − Q1 is the box's length and spans the middle half of the data.

By default Matplotlib, pandas and seaborn use whis=1.5: the fences are Q1 − 1.5 × IQR and Q3 + 1.5 × IQR. Each whisker ends at the most extreme data value inside its fence, not at the fence itself, and every value outside the fences is drawn as a separate point.

11 delivery times in minutes: 14, 16, 17, 18, 19, 20, 21, 22, 24, 25, 41. Matplotlib computes Q1 = 17.5, median = 20 and Q3 = 23, so IQR = 5.5. The fences are 17.5 − 8.25 = 9.25 and 23 + 8.25 = 31.25. The lower whisker ends at 14, the upper whisker at 25, and 41 is drawn as an outlier point.

Quartiles depend on the method. The plotting libraries use linear interpolation between sorted values (the NumPy and pandas default), which gives 17.5 and 23 above. The hand method of taking the medians of the lower and upper halves without the overall median gives Q1 = 17 and Q3 = 24 for the same data. Both are valid; small differences between a hand calculation and a plot come from this.

Draw the summary with the library you are using: ax.boxplot([north, coast], tick_labels=["North", "Coast"]) in Matplotlib (the argument was called labels before version 3.9); rain.boxplot(column="rain_mm", by="station") in pandas, which also adds the overall title "Boxplot grouped by station"; sns.boxplot(data=rain, x="station", y="rain_mm") in seaborn, with hue for a second grouping. whis=(0, 100) draws the whiskers to the minimum and maximum, and showfliers=False hides the outlier points.

Side-by-side box plots compare groups at a glance: compare the medians, the box lengths (spread of the middle half) and the overlap of the boxes. A median close to one end of the box, or one whisker much longer than the other, points to a skewed distribution.

A box shows only five numbers and the outliers. It does not show the number of observations, and very different shapes can have the same box: a distribution with two separate peaks and one with a single peak can share Q1, the median and Q3. Overlaying the points, sns.stripplot(data=rain, x="station", y="rain_mm", color="black", alpha=0.5), or using a violin plot reveals this.

sns.violinplot(data=rain, x="station", y="rain_mm") draws a mirrored density curve for each group with a small box plot inside (inner="box", the default); inner="quart" marks the quartiles with lines instead. With a two-level hue, split=True puts one group on each side of the violin. Like a KDE, the violin can extend beyond the data; cut=0 stops it at the observed minimum and maximum.

A point flagged by the 1.5 × IQR rule is unusual relative to the rest of the data, a reason to investigate the value. Check it: it may be a data-entry mistake or a real, important value, such as one delivery delayed by a road closure. Removing points only because the plot marks them distorts the analysis.

Key Takeaways

  • Box length is the IQR.
  • Whiskers end at observations inside the fences.
  • Quartile methods can differ.
  • Hidden fliers remain in the underlying data.
  • Points and violins reveal information a box hides.

4.3 Display a grid of values as a heatmap

A heatmap shows a table of numbers as a grid of colored cells: rows and columns are two categories (or binned variables), and each cell's color stands for its value. It suits patterns in two-way tables, such as visitors by day and time of day, and correlation matrices.

sns.heatmap(table) takes a wide table, uses its index as row labels and its columns as column labels, and adds a color bar as the key. The table usually comes from pivot_table: visits.pivot_table(index="day", columns="slot", values="visitors", aggfunc="mean").

a museum counts visitors per half-day. Saturday morning 120 and 140, Saturday afternoon 200; Sunday morning 90, Sunday afternoon 160; Monday morning 40, Monday afternoon 70 and 90. The pivot table of means is Mon 40 and 80, Sat 130 and 200, Sun 90 and 160 (AM and PM). sns.heatmap(pt, annot=True, fmt=".0f", cmap="Blues") shows the busiest cell, Saturday afternoon, as the darkest. The pivot sorts the days alphabetically (Mon, Sat, Sun); pt.reindex(["Sat", "Sun", "Mon"]) would restore a chosen order.

annot=True writes each value in its cell, and fmt sets the number format. The default ".2g" keeps two significant digits, so 43.25 is shown as "43" and 1234 as "1.2e+03". Use fmt=".0f" for whole numbers or fmt=".2f" for two decimals; fmt="d" works only for integer data and raises a ValueError for floats.

A correlation heatmap starts from corr = df.corr(numeric_only=True), a square, symmetric table whose defined coefficients range from −1 to 1. Nonconstant numeric columns have 1 on the diagonal; constant columns have undefined correlations. In pandas 2 and later, numeric_only defaults to False, so df.corr() raises an error when the table has a text column. Draw it with sns.heatmap(corr, annot=True, fmt=".2f", cmap="vlag", vmin=-1, vmax=1, center=0).

eight days with temperature (°C), bike rentals, rain (mm) and wind (km/h). The correlation matrix gives temperature and rentals 0.92, rentals and rain −0.82, rain and wind 0.75, and temperature and wind −0.38. With the "vlag" colormap, the strong positive pair shows deep red, the strong negative pair deep blue, and the weak temperature–wind pair a pale tint close to the white center.

Without vmin and vmax, the colors stretch from the smallest to the largest value in that table, so the same color can mean different values in two heatmaps. Fix the limits to compare heatmaps, and use vmin=-1, vmax=1 for correlations. A sequential colormap such as "rocket" (seaborn's default), "viridis" or "Blues" suits values that run from low to high; a diverging colormap such as "vlag", "coolwarm" or "RdBu_r", with center at the meaningful midpoint, suits values above and below a reference such as 0. With center set and no cmap, seaborn uses the diverging "icefire".

Useful options: linewidths=0.5 draws thin lines between cells, square=True makes the cells square, cbar_kws={"label": "Visitors"} labels the color bar, and missing values (NaN) are left blank. mask=np.triu(np.ones_like(corr, dtype=bool)) hides the upper triangle and the diagonal of a correlation matrix, which repeat the lower triangle.

In Matplotlib, im = ax.imshow(values, cmap="viridis"); fig.colorbar(im, ax=ax) draws a heatmap of a 2-D array, with row 0 at the top; "viridis" is Matplotlib's default colormap. imshow labels the axes with row and column numbers, so set names yourself: ax.set_xticks(range(len(cols)), labels=cols). ax.pcolormesh is an alternative when cells have unequal sizes.

A correlation coefficient measures the strength of a linear association only. A correlation near 0 does not rule out a strong curved relationship, and one outlier can raise or lower a coefficient a lot. Check the matching scatter plots, for example with a pair plot, before reading a correlation heatmap.

Key Takeaways

  • Heatmap colors represent table values.
  • Fix color limits for comparisons across plots.
  • Correlation scales span −1 to 1.
  • Check scatter plots before interpreting correlations.
5

Build multi-panel figures, annotate them and export them

A useful figure often needs several views of the same data. Panels let you compare groups, annotations connect a claim to a particular value, and export settings turn the result into an image that fits its destination. Keep control of the figure throughout this process. The object that holds your plots also holds their overall size and is the most reliable way to save exactly the result you have built.

5.1 Arrange several plots in one figure

Small multiples are a set of charts of the same kind, one for each subset of the data, drawn with the same scales and placed side by side so that the subsets can be compared. In Matplotlib they are built as a grid of Axes in one figure.

fig, axes = plt.subplots(2, 3, figsize=(12, 6)) returns a figure and a 2 × 3 NumPy array of Axes. axes[0, 0] is the top-left panel and axes[1, 2] the bottom-right. With one row or one column the array is one-dimensional, so plt.subplots(1, 3) gives axes[0], axes[1] and axes[2]. axes.flat runs through all panels row by row.

The array itself cannot draw: axes.plot(...) raises AttributeError: 'numpy.ndarray' object has no attribute 'plot'. Index one panel first, as in axes[0, 1].plot(...).

sharex=True and sharey=True give all panels the same x- or y-limits, so equal heights mean equal values in every panel and only the outer panels show tick labels. Without shared axes, each panel scales to its own data, and a small range can look as large as a big one.

fig, axes = plt.subplots(2, 2, sharey=True, layout="constrained"), then for ax, (name, grp) in zip(axes.flat, rain.groupby("station")): ax.plot(grp["month_num"], grp["rain_mm"], marker="o"); ax.set_title(name). The three stations fill three of the four panels; axes[1, 1].axis("off") hides the empty fourth one.

Labels of neighboring panels can overlap. layout="constrained" in plt.subplots or plt.figure adjusts the spacing automatically; fig.tight_layout(), called after drawing, is the older alternative. fig.suptitle("Monthly rainfall by station") adds one title for the whole figure, and fig.supxlabel(...) and fig.supylabel(...) add shared axis labels.

Panels of different sizes: plt.subplots(1, 2, gridspec_kw={"width_ratios": [2, 1]}) makes the left panel twice as wide as the right. fig, axd = plt.subplot_mosaic([["top", "top"], ["left", "right"]]) returns a dictionary of Axes, here a wide panel axd["top"] above two smaller ones.

pandas and seaborn axes-level plots can fill chosen panels with ax=: wide["North"].plot(ax=axes[0, 0]) or sns.histplot(data=commutes, x="minutes", ax=axes[0, 1]). This is how plots from all three libraries are combined in one figure.

Key Takeaways

  • Index an Axes array before drawing.
  • Shared scales support panel comparisons.
  • Constrained layout makes room for labels.

5.2 Facet data with seaborn

Faceting draws the same plot once for each level of a categorical variable, each in its own panel, with shared axes. seaborn's figure-level functions do this with col= (panels side by side), row= (panels stacked) and col_wrap= (start a new row after that many columns).

sns.relplot(data=rain, x="month_num", y="rain_mm", col="station", col_wrap=2, kind="line", height=3, aspect=1.5) draws three panels, two in the first row and one in the second. Each panel is 3 inches tall and 3 × 1.5 = 4.5 inches wide, so the figure is about 9 × 6 inches.

row and col together make a grid with one panel per combination of levels: two seasons as rows and three stations as columns give 2 × 3 = 6 panels. col_wrap cannot be combined with row.

The same arguments work for every kind of plot: sns.displot(data=commutes, x="minutes", col="mode") gives one histogram per travel mode, and sns.catplot(data=rain, x="station", y="rain_mm", col="season", kind="box") gives box plots per season.

Panels share their x- and y-axes by default, so heights can be compared across panels. Letting each panel scale to its own data shows detail within small groups but makes comparisons across panels misleading at a glance. With relplot and displot, pass facet_kws={"sharey": False}; catplot takes sharey=False directly, and passing it in facet_kws as well raises a TypeError.

sns.FacetGrid builds the grid directly and then draws into every panel: g = sns.FacetGrid(commutes, col="mode", height=3); g.map_dataframe(sns.histplot, x="minutes"); g.add_legend(). g.map(plt.scatter, "temp_c", "rentals") passes the named columns as positional arguments to a plotting function.

Customize the grid with its methods: g.set_titles("{col_name}") sets panel titles from the level names, g.set_axis_labels("Month", "Rainfall (mm)") labels all axes, and g.set(ylim=(0, 120)) applies an Axes setting to every panel. g.axes_dict["Coast"] or g.axes.flat reaches single Axes, and g.figure.suptitle("Rainfall by station", y=1.02) adds an overall title above the panels.

hue and col both split by a variable. hue overlays the groups in one Axes, which makes direct comparison easy for a few groups; col separates them, which stays readable when lines or points would overlap or when there are many groups. Both can be used at once, for example col="station", hue="season".

Figure-level functions do not draw into an existing Axes (relplot, displot and catplot ignore ax= with a warning, lmplot rejects it) and do not take Matplotlib's figsize (passing it raises an error): size the grid with height and aspect. To place a faceted plot next to other plots in one Matplotlib figure, build the panels with plt.subplots and axes-level functions instead.

Key Takeaways

  • Facets split rows into panels by group.
  • Panel dimensions use height and aspect.
  • Grid methods customize the whole display.
  • Figure-level charts cannot fill an existing Axes.

5.3 Add annotations and reference lines

ax.text(x, y, "text") writes text at a point given in data coordinates, the same units as the plotted values. ha ("left", "center", "right") and va ("top", "center", "bottom") align the text to that point; fontsize and color style it.

With transform=ax.transAxes, positions are fractions of the Axes instead: (0, 0) is the lower-left corner and (1, 1) the upper-right. ax.text(0.02, 0.95, "n = 20", transform=ax.transAxes, va="top") keeps a note in the top-left corner whatever the data and limits are. Text in data coordinates moves when the limits change and can end up outside the plotting area.

ax.annotate("Wettest month", xy=(1, 110), xytext=(2, 115), arrowprops=dict(arrowstyle="->")) writes the text at xytext and draws an arrow to the point xy; both are in data coordinates by default. textcoords="offset points" makes xytext an offset from xy in points, for example xytext=(10, 10) for 10 points right and up.

Reference lines span the whole Axes: ax.axhline(50, color="gray", linestyle="--", label="Target") draws a horizontal line at y = 50, and ax.axvline(...) a vertical one. ax.axvspan(6, 8, alpha=0.2) shades the range from x = 6 to x = 8, for example a holiday period. ax.hlines(y, xmin, xmax) draws horizontal lines over a limited range.

on the histogram of the 20 commute times, the mean is 650 ÷ 20 = 32.5 minutes and the median 30.5 minutes. ax.axvline(32.5, color="black", linestyle="--"); ax.text(33.5, 6.5, "mean 32.5 min") marks the mean, which lies to the right of the median because a few long commutes pull it up.

Bar values: ax.bar_label(bars, fmt="%.0f") labels the bars returned by ax.bar. For bars drawn by pandas or seaborn, the bars are stored in ax.containers, so ax.bar_label(ax.containers[0]) labels the first series. padding=3 moves the labels 3 points away from the bar ends.

Shapes come from matplotlib.patches: ax.add_patch(Rectangle((x, y), width, height, fill=False, edgecolor="red")) outlines a region in data coordinates, and Circle and Polygon work the same way.

Text can be computed from the data with f-strings, so labels stay correct when the data change: ax.text(..., f"mean {commutes['minutes'].mean():.1f} min"). Annotations are drawn on top of the data; place them in empty areas and keep them few, so they point out what matters.

Key Takeaways

  • Data coordinates anchor text to measurements.
  • Axes coordinates anchor text to the panel.
  • An annotation separates the target point from the text position.
  • Compute changing labels from the data.

5.4 Save figures for reports and the web

fig.savefig("rainfall.png") saves the figure; the file extension sets the format: PNG and JPEG are raster images made of pixels, while SVG and PDF are vector graphics made of shapes. format="pdf" sets the format explicitly.

Raster images have a fixed number of pixels and blur when enlarged; vector files stay sharp at any size and suit reports, print and documents. PNG is a good raster format for charts on the web and in slides. JPEG compression is lossy and blurs thin lines and text, so it is a poor choice for charts.

Pixel size = figure size in inches × dpi (dots per inch). fig, ax = plt.subplots(figsize=(8, 5)) saved with dpi=150 gives 8 × 150 by 5 × 150 = 1200 × 750 pixels. Without dpi, savefig uses the figure's own dpi, 100 by default, so the same figure becomes 800 × 500 pixels. For vector formats, dpi affects only embedded raster parts.

Text and line widths are set in points (1 point = 1/72 inch), relative to the figure's inches. Raising dpi adds pixels without changing how large the text looks relative to the chart; enlarging figsize instead makes the text relatively smaller. Choose figsize for the final display size and dpi for the sharpness.

bbox_inches="tight" trims empty margins and includes items that stick out of the figure, such as a legend placed outside the Axes; the saved image is then a little smaller or larger than figure size × dpi. pad_inches=0.1 sets the margin kept around it.

transparent=True saves without a background, which suits slides with a colored background; facecolor="white" forces a white background, which matters when a dark notebook theme would otherwise leak into the file.

plt.savefig saves the current figure, so call it before a blocking plt.show(): once the window is closed, pyplot no longer tracks that figure, and a later plt.savefig(...) saves a new, empty one. In a Jupyter notebook, pyplot also lets go of the figure at the end of the cell, so plt.savefig in a later cell saves an empty image. Keeping the figure in a variable avoids both problems: fig.savefig(...) still works after plt.show() or in a later notebook cell.

seaborn results are saved the same way: an axes-level plot through its figure, ax.figure.savefig("box.png", dpi=200), and a figure-level grid with g.savefig("facets.png", dpi=200), which uses tight bounding boxes by default.

for name, grp in rain.groupby("station"):
    grp = grp.sort_values("month_num")
    fig, ax = plt.subplots(figsize=(6, 4))
    ax.plot(grp["month_num"], grp["rain_mm"], marker="o")
    ax.set(title=name, xlabel="Month", ylabel="Rainfall (mm)")
    fig.savefig(f"rain_{name}.png", dpi=150, bbox_inches="tight")
    plt.close(fig)

. Closing each figure keeps memory use low and avoids the warning about more than 20 open figures.

Key Takeaways

  • Save the figure object you built.
  • Inches times dpi gives uncropped raster dimensions.
  • Tight bounding boxes change the exported boundary.
  • Vector output preserves shapes.
  • Close each figure after batch export.

Matplotlib and Seaborn examples

5 Walkthroughs

1

Build plots with Matplotlib figures and axes

15 steps
Build, label, and diagnose a Matplotlib figure.
  1. 1
    IntroductionBuild one chart at a time

    A plotting command needs somewhere to draw. Matplotlib makes that place explicit: a figure holds one or more plotting areas, and each area holds the marks and labels. Start with one area, then use the same objects to add lines, points, bars, and useful settings. Keeping a name for the figure and each plotting area makes it easier to change the right chart when a notebook grows or a figure contains several panels.

  2. 2
    ExplanationKeep hold of the canvas

    A Figure holds the full image. An Axes holds one chart and its coordinate axes. Create both explicitly so later commands have a clear destination.

    import matplotlib.pyplot as plt
    fig, ax = plt.subplots(figsize=(7, 4))
    

    The width and height are in inches. The variable ax points to the plotting area inside fig; it is the object that will receive the line and its labels.

  3. 3
    ExampleDraw into that area

    Add a short temperature series to the Axes you just created. Each pair becomes a point on the line.

    ax.plot([1, 2, 3], [8, 11, 10])
    ax.set(title="Daily temperature",
           xlabel="Day", ylabel="Temperature (°C)")
    

    Calling ax.plot again would add another line to this same area. In a script, plt.show() displays the figure; a notebook normally displays it below the cell.

  4. 4
    ChallengeFix a title call

    The call ax.title("Daily temperature") raises a "Text object is not callable" error. How should it be changed?

    ---reveal---

    Use ax.set_title("Daily temperature"). The Axes attribute title is already a text object; set_title is the method that changes it. The pyplot equivalent is plt.title(...), but it works on whichever Axes is current.

  5. 5
    ExplanationKeep the observations paired

    A line connects points in input order. If the distance column runs 4, 1, 3 km, the line moves backward before it moves forward. Sort complete observations by distance, preserving each elevation beside its original distance.

    route = route.sort_values("distance_km")
    ax.plot(route["distance_km"], route["elevation_m"])
    

    A scatter plot needs no connecting order because each marker is a separate observation.

  6. 6
    ExampleGive each series a key

    Line styles and marker styles can identify series as well as color. Add a label when drawing, then ask the Axes to build its legend.

    ax.plot([1, 2, 3], [4, 8, 7], "o--", label="East")
    ax.plot([1, 2, 3], [6, 7, 9], "s-", label="West")
    ax.legend(title="Site")
    

    For a scatter plot, numeric c values need a color bar to explain their gradient. Lower alpha when overlapping points hide the sample.

  7. 7
    ChallengePredict a size change

    A scatter marker uses s=25. You change it to s=100 with the same marker shape. How does its width change?

    ---reveal---

    The width doubles. The area has grown by a factor of four, and linear dimensions grow by the square root of that factor. Scatter s is measured in points squared; reading it as a width would incorrectly predict a fourfold increase.

  8. 8
    ExplanationPlace categories and values

    Bars use separate category positions. Start with one number per category; strings become equally spaced labels in the supplied order. A horizontal chart gives long names room.

    fig, ax = plt.subplots()
    bars = ax.barh(["Bus", "Rail", "Walk"], [48, 37, 25])
    ax.invert_yaxis()
    ax.bar_label(bars)
    

    The inversion puts the first category at the top. Reversing names alone would attach the values to the wrong categories.

  9. 9
    ExampleBuild a stack from its base

    Suppose weekday trips consist of 32 bus trips and 18 rail trips. The second bar segment must start at the top of the first.

    ax.bar(["Weekday"], [32], label="Bus")
    ax.bar(["Weekday"], [18], bottom=[32], label="Rail")
    ax.legend()
    

    The rail segment has height 18 and ends at 50. If a third mode is added, its baseline is the cumulative total of the two segments already drawn.

  10. 10
    ChallengeLocate the grouped bars

    Two bars each have width 0.4 and should be centered together at category position 1. Where should their centers be?

    ---reveal---

    Use 0.8 and 1.2, half a width either side of the tick. Their inner edges meet at 1, and the pair is centered on the category. Using positions 1 and 1.4 would make a neighboring pair but shift its overall center away from the category tick.

  11. 11
    ExplanationSeparate positions from labels

    Ticks mark coordinate positions; their labels are the text shown there. Supply both together when replacing numeric month positions with names.

    ax.set_xticks([1, 2, 3], labels=["Jan", "Feb", "Mar"])
    ax.set_ylabel("Rainfall (mm)")
    ax.grid(axis="y", alpha=0.3)
    

    A formatter changes how existing numbers are displayed. It does not rescale the data, so check whether percentages are stored as fractions or as numbers from 0 to 100.

  12. 12
    ExampleChoose a scale with meaning

    Equal steps on a linear scale mean equal differences. Equal steps on a logarithmic scale mean equal ratios.

    ax.set_yscale("log")
    

    Values 5, 50, and 500 have equal spacing because each is ten times the previous value. Zero and negative values cannot appear on an ordinary log scale. Styles control appearance separately: use a style context when a different look should apply to only one block of code.

  13. 13
    ChallengeLabel the intended panel

    A two-panel figure needs a title on its first panel, but plt.title(...) changes the second one. How can the code target the first panel reliably?

    ---reveal---

    Call axes[0].set_title(...). The named Axes is explicit, so the current pyplot state no longer decides the destination. This matters whenever a figure has several panels or a helper function creates or selects another Axes.

  14. 14
    ChallengeExplain a numeric color key

    A scatter chart uses point color for rain depth and marker area for rental volume. Its legend names stations but gives no numeric color key. What does the figure still need?

    ---reveal---

    Add a color bar attached to the scatter result and label it "Rainfall (mm)". The station legend explains groups, while the color bar explains numeric shades. Keeping the returned scatter object lets fig.colorbar use the same mapping as the plotted points.

  15. 15
    RecapCheck the result you built

    A chart has a canvas, a plotting area, and artists attached to that area. Check that each series keeps the intended observation pairs, that the labels identify variables and units, and that numeric color mappings have a key. When a change affects the wrong place, inspect which Axes received the method call. When a shape looks wrong, inspect the order and coordinates of the data before changing its style.

2

Plot data directly from pandas

9 steps
Prepare the right values and shape before drawing.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionLet the table supply the chart
  2. 2
    ExplanationUse the table labels
  3. 3
    ExampleChoose numeric columns
  4. 4
    ChallengeAlign lines and bars
  5. 5
    ExplanationSummarize before drawing
  6. 6
    ExampleChoose a shape for the next library
  7. 7
    ChallengeRepair a repeated pivot pair
  8. 8
    ChallengeSummarize and reshape together
  9. 9
    RecapCheck the result you built
3

Make statistical plots with seaborn

12 steps
Connect seaborn mappings and statistical defaults to the chart.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionRead what the function computes
  2. 2
    ExplanationMap variables to features
  3. 3
    ExamplePick the owner of the layout
  4. 4
    ChallengeFit the function to the layout
  5. 5
    ExplanationRead the line estimator
  6. 6
    ExamplePreserve each trajectory
  7. 7
    ChallengeInterpret a narrow band
  8. 8
    ExplanationCount rows or summarize values
  9. 9
    ExampleShow the observations
  10. 10
    ChallengeChoose the summary
  11. 11
    ChallengeExplain the changing bars
  12. 12
    RecapCheck the result you built
4

Visualize distributions and grids of values

12 steps
Work from observations to distributions and color grids.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionRead compressed data carefully
  2. 2
    ExplanationCount a bin correctly
  3. 3
    ExampleConvert count to density
  4. 4
    ChallengeCompare unequal-width bins
  5. 5
    ExplanationBuild fences from the box
  6. 6
    ExampleFind the observed whisker end
  7. 7
    ChallengeLook inside an identical box
  8. 8
    ExplanationStart from the numeric grid
  9. 9
    ExampleFix the color meaning
  10. 10
    ChallengeDiagnose matching shades
  11. 11
    ChallengeCheck two summaries together
  12. 12
    RecapCheck the result you built
5

Build multi-panel figures, annotate them and export them

16 steps
Arrange panels, anchor annotations, and export the result.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionPrepare a figure for sharing
  2. 2
    ExplanationCreate addressable panels
  3. 3
    ExampleFill the grid with groups
  4. 4
    ChallengeKeep scale comparisons fair
  5. 5
    ExplanationLet seaborn split the table
  6. 6
    ExampleCustomize the grid as a grid
  7. 7
    ChallengeChange sharing through the right argument
  8. 8
    ExplanationChoose what anchors the text
  9. 9
    ExampleAttach a label to a peak
  10. 10
    ChallengeKeep a filtered label accurate
  11. 11
    ExplanationChoose dimensions before pixels
  12. 12
    ExampleSave the retained figure
  13. 13
    ChallengeCombine layout and export decisions
  14. 14
    ChallengeFinish a reproducible batch
  15. 15
    TipInspect the saved result
  16. 16
    RecapCheck the result you built

Matplotlib and Seaborn practice questions

50 Practice Questions in 5 sets

Set 1: Read plots and check the basics10 Practice Questions

Question 1 of 10

You want the number of observations in each equipment category. Which seaborn plot directly provides this?
  1. A count plot of category
  2. A point plot of mean values
  3. A bar plot of averages
  4. A box plot of measurements
Show answerHide answer
Answer: A
A count plot calculates the number of rows in each category and needs no numeric response column. A bar plot normally displays a numeric variable's mean, so its bars would answer a question about average measurements instead of category frequencies.

Question 2 of 10

With the default Matplotlib backend, what does df.plot(y="depth_mm") return when it draws one panel?
  1. A seaborn FacetGrid
  2. A Matplotlib Axes
  3. A pandas Series
  4. A Matplotlib Figure
Show answerHide answer
Answer: B
The ordinary pandas plot returns the Axes it drew on, which you can customize with methods such as set_ylabel. It does not return the whole Figure; reach that through the Axes' figure attribute when you need to save the image.

Question 3 of 10

For plt.subplots(2, 3), how do you select the bottom-right panel?
  1. axes[2, 3]
  2. axes[1, 3]
  3. axes[2, 1]
  4. axes[1, 2]
Show answerHide answer
Answer: D
The Axes array uses zero-based row and column indexes. The second row is index 1 and the third column is index 2, so the bottom-right panel is axes[1, 2]. Using 2 and 3 counts from one and points beyond this array's bounds.

Question 4 of 10

A y-axis stores shares as fractions. What formatter setting displays 0.32 as "32%"?
  1. PercentFormatter(xmax=0.32)
  2. PercentFormatter(xmax=32)
  3. PercentFormatter(xmax=1)
  4. PercentFormatter(xmax=100)
Show answerHide answer
Answer: C
With xmax=1, one whole unit means 100%, so 0.32 is formatted as 32%. Setting xmax=100 would be appropriate for values already stored on a 0–100 scale; with fractions it would label 0.32 as 0.32% instead.

Question 5 of 10

What does the default shaded band around a seaborn mean line describe?
  1. The complete range of recorded values
  2. Uncertainty in the estimated means
  3. The middle half of all observations
  4. One standard deviation of all observations
Show answerHide answer
Answer: B
The default band is a bootstrapped 95% confidence interval for the mean at each x. It describes uncertainty in that estimate. A standard deviation band describes spread among observations and is requested with errorbar="sd"; it has a different interpretation.

Question 6 of 10

Sensor readings repeat for each station-hour pair. What table operation gives one mean for each pair in a wide station-by-hour table?
  1. pivot_table(..., aggfunc="mean")
  2. value_counts() on station names
  3. melt(...) with station identifiers
  4. pivot(...) without an aggregation
Show answerHide answer
Answer: A
A pivot table can combine repeated station-hour pairs with a mean and arrange those means into rows and columns. An ordinary pivot requires each pair to be unique, so it cannot decide what to do with multiple readings in the same cell.

Question 7 of 10

You want separate categorical box-plot panels with independent y-scales. What is the correct seaborn figure-level configuration?
  1. catplot(kind="box", col="site", facet_kws={"sharey": False})
  2. boxplot(col="site", sharey=False)
  3. catplot(kind="box", row="site", col_wrap=2)
  4. catplot(kind="box", col="site", sharey=False)
Show answerHide answer
Answer: D
Use catplot for categorical facets and pass sharey=False directly. Unlike relplot and displot, catplot supplies this argument to its grid itself, so also providing it through facet_kws creates a duplicate-argument error. A single axes-level box plot cannot create facets through col.

Question 8 of 10

A strip plot uses hue for shift, but both shifts occupy the same position within each category. What separates the groups side by side?
  1. Set native_scale=True.
  2. Set jitter=False.
  3. Set dodge=True.
  4. Set errorbar=None.
Show answerHide answer
Answer: C
Dodging shifts hue groups to separate positions inside each category. Strip plots do not do this by default, so explicitly enable it. Turning off jitter only removes random point displacement; it would leave the groups sharing the same category center.

Question 9 of 10

A pivot table of means has floating-point values such as 26.0. What heatmap format displays whole-number labels without changing its data type?
  1. fmt=".2f"
  2. fmt="d"
  3. fmt=".0f"
  4. fmt=".0g"
Show answerHide answer
Answer: C
The floating-point format .0f displays zero decimal places and works with means stored as floats. The integer format d requires integer data and can raise an error even for 26.0. Formatting the displayed text does not change the table's values.

Question 10 of 10

Readings are 8, 12, 16, and 24 minutes. A filter removes readings at least 20 minutes. A mean line must match the remaining rows, and a sample-size note must stay in the panel's upper-left corner when limits change. What should the updated figure use?
  1. A mean line at 15 and an "n = 3" note in Axes coordinates.
  2. A mean line at 12 and an "n = 3" note in data coordinates.
  3. A mean line at 12 and an "n = 4" note in Axes coordinates.
  4. A mean line at 12 and an "n = 3" note in Axes coordinates.
Show answerHide answer
Answer: D
The remaining values sum to 36 over three observations, so their mean is 12 minutes and the note must show "n = 3". Axes coordinates keep that note near the corner as limits change. The original four-value mean is 15, which would retain the excluded observation in the summary.
Set 2: Apply plotting choices to new data10 Practice Questions

Save this lesson to see every answer and practice every set.

Question 1 of 10

What coordinate system keeps a note near a panel's upper-left corner when data limits change?
  1. The x-variable's units
  2. The y-variable's units
  3. Axes coordinates
  4. Data coordinates
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

In ax.scatter(x, y, s=64), what does 64 specify?
  1. Marker area in points squared
  2. Marker width in points
  3. Marker opacity as a percentage
  4. Marker radius in points
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

With edges [0, 5, 10, 15], which bin contains the value 5?
  1. No bin because it is an edge
  2. Both bins touching the value 5
  3. The bin from 0 to below 5
  4. The bin from 5 to below 10
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

A box has Q1 = 12 and Q3 = 20. The observed values above Q3 are 24, 30, and 35. Where does the default upper whisker end?
  1. 24
  2. 30
  3. 32
  4. 35
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

A chart stores shares as fractions and has a target at 75%. What combination places the target correctly and labels the y-axis in percentages?
  1. ax.axhline(0.75) and PercentFormatter(xmax=100)
  2. ax.axhline(0.75) and PercentFormatter(xmax=1)
  3. ax.axhline(75) and PercentFormatter(xmax=100)
  4. ax.axhline(75) and PercentFormatter(xmax=1)
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

A route table has distances [4, 1, 3] km and paired elevations [90, 40, 75] m. What order should a forward-moving line use?
  1. (1, 40), (3, 75), (4, 90)
  2. (1, 90), (3, 40), (4, 75)
  3. (1, 40), (4, 90), (3, 75)
  4. (4, 90), (1, 40), (3, 75)
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

Measurements occur in years 2017, 2018, and 2022. A seaborn categorical plot spaces them equally. What preserves the actual gaps?
  1. sharey=True
  2. errorbar=None
  3. dodge=True
  4. native_scale=True
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

A faceted chart has two row levels and four column levels. How many panels does it create?
  1. 8
  2. 6
  3. 4
  4. 2
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

A region has 9 train trips and 3 walking trips; another has 12 train trips and 12 walking trips. You want equal-height stacked bars comparing travel mix. What should the train segments be?
  1. 0.30 and 0.40
  2. 0.43 and 0.57
  3. 0.75 and 0.50
  4. 9.00 and 12.00
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

A report needs a 900 × 600 pixel PNG with an outside legend fully visible. The planned canvas is 6 × 4 inches. What plan best controls both dimensions and clipping?
  1. Use 100 dpi, reserve space for the legend within the canvas, and save without tight cropping.
  2. Use 150 dpi, reserve space for the legend within the canvas, and save without tight cropping.
  3. Use 150 dpi, put the legend beyond the canvas, and save without tight cropping.
  4. Use 150 dpi, put the legend beyond the canvas, and force tight cropping to preserve the canvas size.
Show answerHide answer

Save this lesson to see this answer.

Set 3: Connect tables, summaries, and charts10 Practice Questions

Save this lesson to see every answer and practice every set.

Question 1 of 10

A default seaborn line plot has repeated measurements at the same x. What does the line show at that x?
  1. The sum of the y-values
  2. The median of the y-values
  3. The first recorded y-value
  4. The mean of the y-values
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

What does a second ax.plot(...) call do to an existing Axes?
  1. Replaces the old line
  2. Creates a second Axes
  3. Adds another series
  4. Clears its axis labels
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

A notebook creates and stores fig in one cell. A later cell needs to save that exact chart after pyplot has released it. What call is reliable?
  1. fig.savefig("chart.png")
  2. plt.savefig("chart.png")
  3. plt.show("chart.png")
  4. plt.figure().savefig("chart.png")
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

A stacked chart has a base segment of 28 and a second segment of 17. What baseline and top does the second segment have?
  1. Baseline 0; top 17
  2. Baseline 28; top 45
  3. Baseline 28; top 17
  4. Baseline 17; top 45
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

A helper function calls plt.title("Depth") after creating a second figure. The title should belong to the first figure's Axes, stored as first_ax. How should the title be set?
  1. first_ax.title("Depth")
  2. first_ax.set_title("Depth")
  3. plt.figure().suptitle("Depth")
  4. plt.title("Depth") after the helper
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

A delivery time lies beyond a box plot's upper fence. What should you do before removing it?
  1. Delete it because the fence marks invalid data.
  2. Replace it with the upper whisker endpoint.
  3. Investigate whether the recorded time is valid.
  4. Keep only values within the interquartile range.
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

An arrow should point at (8, 42), with text 12 points above it. What should xy and xytext be with textcoords="offset points"?
  1. xy=(8, 42), xytext=(0, 12)
  2. xy=(8, 42), xytext=(8, 54)
  3. xy=(8, 54), xytext=(0, 12)
  4. xy=(0, 12), xytext=(8, 42)
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

Two groups have 40 and 200 observations. A five-minute bin contains 10 from the first group and 20 from the second. The histograms must each have area one. What density heights should that bin have, and which normalization setting is needed?
  1. 0.25 and 0.10 per minute; common_norm=False.
  2. 0.05 and 0.02 per minute; common_norm=True.
  3. 0.01 and 0.02 per minute; common_norm=True.
  4. 0.05 and 0.02 per minute; common_norm=False.
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

A Series indexed by years 2018, 2020, and 2024 is drawn as pandas bars. A line using those numeric years is added to the same Axes. How can both series align while retaining the year labels?
  1. Convert only the bar heights to a numeric array before plotting.
  2. Plot both at positions 0, 1, 2 and label those ticks with years.
  3. Sort both series by year and keep their existing coordinates.
  4. Set identical y-limits and keep their existing coordinates.
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

A 6 × 3 inch PNG at 100 dpi uses 12-point labels that look correctly sized relative to the chart. You need 1200 × 600 pixels and will keep the font at 12 points. What figure size and resolution preserve the label proportions?
  1. 6 × 3 inches at 200 dpi.
  2. 12 × 6 inches at 100 dpi.
  3. 6 × 3 inches at 100 dpi.
  4. 12 × 6 inches at 200 dpi.
Show answerHide answer

Save this lesson to see this answer.

Set 4: Diagnose chart settings and comparisons10 Practice Questions

Save this lesson to see every answer and practice every set.

Question 1 of 10

Two samples have the same quartiles and whisker endpoints but different clusters of observations. What display can expose the difference and why?
  1. Hide fliers to reveal the missing clusters.
  2. Increase box width to encode the clusters.
  3. Fix the y-limits to make the boxes different.
  4. Overlay strip plots to reveal individual values.
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

A figure has three plotting panels. How many Axes does it contain?
  1. Three
  2. One
  3. Six
  4. Two
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

A table contains one row per trip and a mode column. What produces the number of trips per mode?
  1. trips["mode"].sort_values()
  2. trips["mode"].unique()
  3. trips["mode"].value_counts()
  4. trips["mode"].drop_duplicates()
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

A long table has height_cm, mass_kg, and species. How can a scatter plot identify species by both color and marker shape?
  1. Map species to size and y.
  2. Map species to hue and size.
  3. Map species to x and style.
  4. Map species to hue and style.
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

A line plot of months uses text names appearing as "May", "Mar", "Apr". You need calendar order and one line per site. What change is suitable?
  1. Pass month order to lineplot and map site to hue.
  2. Make month an ordered categorical and map site to hue.
  3. Sort month names alphabetically and map site to hue.
  4. Map month to hue and sort site names alphabetically.
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

Two series have bar width 0.3 and should sit side by side, centered together at x = 2. Where should their centers be?
  1. 1.7 and 2.3
  2. 2.0 and 2.3
  3. 1.85 and 2.15
  4. 1.85 and 2.3
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

A facet has height 4 inches and aspect 1.25. How wide is that panel?
  1. 5 inches
  2. 3.2 inches
  3. 4 inches
  4. 1.25 inches
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

A ranked horizontal chart must show values 52, 31, and 19 from top to bottom. The original name-value pairs are A–31, B–19, C–52. What preparation and axis setting achieve this?
  1. Sort pairs ascending, draw them, then invert the y-axis.
  2. Sort pairs descending, draw them, then invert the y-axis.
  3. Sort pairs descending, draw them, then invert the x-axis.
  4. Sort names descending, keep values fixed, then draw them.
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

Two adjacent bins have widths 2 and 4 and contain 10 observations each in a sample of 50. Under density scaling, what are their heights and areas?
  1. Heights 0.05 and 0.10; areas 0.10 and 0.40
  2. Heights 0.10 and 0.05; areas 0.20 and 0.20
  3. Heights 0.10 and 0.10; areas 0.20 and 0.40
  4. Heights 0.20 and 0.20; areas 0.40 and 0.80
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

A report needs three site trends in a 2 × 2 grid, comparable in millimeters. Rows arrive in mixed month order. What construction prevents backtracking lines, misleading panel heights, and an empty visible panel?
  1. Sort each site by month, share y-limits, and hide the spare Axes.
  2. Sort each site by month, share y-limits, and repeat one site in the spare Axes.
  3. Sort each site by month, scale each y-axis, and hide the spare Axes.
  4. Sort each site by depth, share y-limits, and hide the spare Axes.
Show answerHide answer

Save this lesson to see this answer.

Set 5: Solve plotting and export problems10 Practice Questions

Save this lesson to see every answer and practice every set.

Question 1 of 10

Which type of seaborn function can draw into a chosen existing Matplotlib Axes?
  1. A PairGrid constructor
  2. An axes-level function
  3. A figure-level function
  4. A FacetGrid constructor
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

On a logarithmic y-axis, a point moves from 3 to 30. What move has the same vertical distance?
  1. 30 to 300
  2. 30 to 57
  3. 30 to 130
  4. 30 to 60
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

A depth column contains strings such as "15 mm" and pandas skips it when plotting. What is the useful repair?
  1. Give the chart a label containing the unit text.
  2. Increase the figure width and rotate the tick labels.
  3. Switch the plot kind from line to horizontal bars.
  4. Remove the unit text and convert values to numbers.
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

A sample of 40 values has 12 observations in a bin of width 6 minutes. What is that bin's density height?
  1. 0.15 per minute
  2. 2.00 per minute
  3. 0.05 per minute
  4. 0.30 per minute
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

A fitted straight line rises overall, but points rise steeply at first and then level off. What should guide the next inspection?
  1. Hide the points and judge the fit from its slope alone.
  2. Interpret the confidence band as containing all possible observations.
  3. Treat the straight line as evidence of a constant rate everywhere.
  4. Inspect curvature and compare the straight fit with a curved fit.
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

A correlation heatmap has a coefficient near zero, but the matching scatter plot shows a clear U shape. How should you interpret the pair?
  1. There is no relationship because the coefficient is near zero.
  2. There is a curved relationship with weak linear association.
  3. There is a strong positive linear relationship throughout.
  4. There is a strong negative linear relationship throughout.
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

Three station charts use separate automatic y-limits. A 4 mm change looks as tall as a 40 mm change. How should you rebuild the figure for direct magnitude comparisons?
  1. Use shared y-limits and keep each station's actual values.
  2. Keep separate limits and give every panel the same height.
  3. Normalize every station to its own maximum and share y-limits.
  4. Keep separate limits and add the same title to each panel.
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

Two sites need comparable slot heatmaps. Site A has duplicate counts 20 and 40 for one slot; site B has 70 for that slot. Each cell must show a mean with whole-number text. What preparation and display settings keep both values and shades comparable?
  1. Aggregate with sum, use fmt=".0f", and match colormap and limits.
  2. Aggregate with mean, use fmt="d", and match colormap and limits.
  3. Aggregate with mean, use fmt=".0f", and match colormap and limits.
  4. Aggregate with mean, use fmt=".0f", and allow separate automatic limits.
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

A table records each device at several times. You need the individual device trajectories, colored by model, without a separate legend entry for every device. How should the line plot be configured?
  1. Use model for hue, omit units, and retain the mean estimator.
  2. Use device for units, model for hue, and estimator=None.
  3. Use device for hue, model for units, and the mean estimator.
  4. Use device for style, model for hue, and the mean estimator.
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

A scatter plot should map sample counts to marker area and rainfall to color. Counts 20 and 80 must give the second marker twice the width of the first, and readers need a numeric rain key. What construction fits?
  1. Use s=counts, c=rain_mm, and a color bar from the scatter result.
  2. Use s=counts**2, c=rain_mm, and a color bar from the scatter result.
  3. Use s=rain_mm, c=counts, and a color bar from the scatter result.
  4. Use s=counts, c=rain_mm, and a legend of the two sample counts.
Show answerHide answer

Save this lesson to see this answer.

Stuck on your own question? Homework Help

Key Terms

78 Key Terms, each with its definition

A

Aggregation
Aggregation combines several rows into a summary, such as a mean, sum, or count, for each defined group.
Aggregation by station turns daily rainfall rows into one mean rainfall value per station.
Annotation
An annotation is text attached to a target location, optionally using an arrow and a separately positioned label.
An annotation can name a peak while placing the text beside it to leave the point visible.
Artist
An artist is an object that Matplotlib draws, such as a line, text label, marker collection, or rectangle.
Adding a reference line creates another artist on the existing plotting area.
Aspect ratio
A facet's aspect ratio is its width divided by its height; multiplying height by aspect gives panel width.
A facet with height 3 inches and aspect 1.5 has a width of 4.5 inches.
Axes
An Axes is one plotting area in a Matplotlib figure, with its own artists, labels, limits, and coordinate system.
Select the right Axes before adding a title to the second panel of a station comparison.
Axes array
An Axes array is a NumPy array of plotting-area objects returned when Matplotlib creates multiple subplots.
Index the Axes array before drawing; the array itself has no plotting method.
Axes coordinates
Axes coordinates locate an element by fractions of the plotting area, from zero at the lower left to one at the upper right.
A sample-size note at axes position (0.02, 0.95) stays near the panel's upper-left corner.
Axes-level function
An axes-level function draws into one Matplotlib Axes, accepts an existing Axes, and returns the plotted Axes.
An axes-level seaborn histogram can fill the right panel of a custom Matplotlib figure.
Axis
An Axis is the x- or y-coordinate axis of an Axes, including its ticks, tick labels, and scale.
A temperature chart's vertical Axis may show tick labels in degrees Celsius.

B

Bandwidth
Bandwidth controls the smoothing of a kernel density estimate; a larger bandwidth produces a smoother curve.
Increasing bandwidth can merge two small bumps that appeared with a more detailed curve.
Bar container
A bar container is the collection returned by a bar-drawing call, holding the bars that can later receive value labels.
Keep the bar container when you want to label one series in a grouped chart.
Baseline
A baseline is the starting value from which a bar extends; ordinary Matplotlib bars start at zero unless changed.
A stack's second segment uses the first segment's value as its baseline.
Bin edge
A bin edge is a boundary of a histogram interval that decides which values belong to that bin.
A value on an internal bin edge belongs to the bin starting there, not the one ending there.

C

Color bar
A color bar is a numeric key that shows how values map to colors in a scatter plot, heatmap, or other image.
A rain color bar lets readers interpret the gradient on a temperature-rental scatter plot.
Color limits
Color limits set the numeric endpoints of a colormap, fixing how values map to colors across one or more plots.
Matching color limits makes a shade of blue represent the same value in two heatmaps.
Column wrapping
Column wrapping limits the number of facet columns and continues the remaining panels on later rows.
Column wrapping at three puts seven station panels into rows containing three, three, and one.
Confidence interval
A confidence interval expresses uncertainty in an estimated quantity through a method designed for repeated sampling.
Seaborn's default line band is a 95% confidence interval for each estimated mean.
Constrained layout
Constrained layout is a Matplotlib layout engine that adjusts panel spacing to make room for labels and decorations.
Constrained layout helps keep long y-axis labels from colliding with the neighboring panel.
Correlation matrix
A correlation matrix is a symmetric table of pairwise linear association coefficients, with defined entries from −1 to 1.
Check scatter plots alongside a correlation matrix because strong curved patterns can have low correlation.
Count plot
A count plot displays the number of rows in each category without needing a separate numeric response variable.
A travel-mode count plot shows how many recorded trips used each type of transport.

D

Data coordinates
Data coordinates locate a mark using the units of the plotted variables, so its screen position depends on axis limits.
An annotation at 20 minutes and 12 observations moves on screen when the axis limits change.
DatetimeIndex
A DatetimeIndex is a pandas index of timestamps that plotting methods can use for a date-based horizontal axis.
Resampling a DatetimeIndex to month starts can produce a chart of monthly means.
Diverging colormap
A diverging colormap uses different color directions on either side of a meaningful center, such as zero.
A diverging colormap separates negative correlations from positive ones around a neutral center.
Dodging
Dodging shifts hue groups to separate positions within each category so their marks can be compared side by side.
Turning on dodging separates the hue groups in a strip plot that would otherwise overlap.
Dpi
Dpi is dots per inch; for a raster export it converts a figure's physical dimensions into pixel dimensions.
A 6-inch-wide figure saved at 200 dpi has a width of 1200 pixels before tight cropping.

E

ECDF
An empirical cumulative distribution function gives the proportion of observed values at or below each possible threshold.
An ECDF value of 0.8 at 40 minutes means 80% of the recorded times are at most 40 minutes.
Estimator
An estimator is the rule used to summarize repeated observations, such as their mean, median, or sum.
Changing the estimator from mean to sum changes what a seaborn bar's height represents.

F

Facet
A facet is a panel that repeats a plot for one subset selected by a grouping variable.
A facet for each travel mode compares the same commute-time distribution across groups.
FacetGrid
A FacetGrid is a seaborn object that holds a figure and group-specific panels with methods for drawing and labeling.
A FacetGrid can apply a histogram function separately to each station's observations.
Fence
A fence is a calculated cutoff for flagging unusual values in a box plot, usually 1.5 IQR beyond a quartile.
The upper fence can fall between observations, so it need not be the upper whisker's endpoint.
Figure
A figure is Matplotlib's whole canvas, containing plotting areas and figure-wide elements such as an overall title.
A figure can hold a rainfall line chart beside a histogram of daily temperatures.
Figure reference
A figure reference is a Python variable that retains a Figure object for later editing or saving even after pyplot releases it.
Keeping the figure reference lets a later notebook cell save the original plot instead of an empty one.
Figure-level function
A figure-level function creates its own figure or grid and can divide the data into panels through row and column mappings.
A figure-level relational plot can give each station a panel with the same axis scales.
Flier
A flier is an observation drawn beyond a box plot's whiskers because it falls outside the selected fence rule.
A genuine traffic delay can appear as a flier and still belong in a set of delivery-time data.

G

Grouped bar chart
A grouped bar chart places separate series side by side around each category position so their values can be compared.
Offsetting two stations' sets of bars around each month keeps the two series from overlapping.

H

Heatmap
A heatmap represents a numeric table through colored cells, with row and column labels identifying each cell's position.
A station-by-month heatmap can reveal a wet season as a band of darker cells.
Histogram
A histogram groups numeric measurements into adjacent intervals and uses bars to show their counts or scaled frequencies.
A histogram with five-minute bins groups nearby commute times into the same interval.
Hue
Hue is a seaborn semantic mapping that represents a variable through color and usually adds a matching legend.
Categorical hue gives stations distinct colors, while numeric hue can show a rainfall gradient.

I

Index
An index labels rows in a pandas object and supplies horizontal coordinates for its default line plot.
A date index lets a rainfall line chart display dates without a separate x column.
Interquartile range
The interquartile range is Q3 minus Q1, measuring the spread of the middle half of an ordered numeric sample.
If Q1 is 16 minutes and Q3 is 24 minutes, the interquartile range is 8 minutes.

K

Kernel density estimate
A kernel density estimate is a smooth estimate of distribution shape formed by combining small curves around observations.
A kernel density estimate may extend below zero even when every measured time is positive.

L

Line plot
A line plot joins observations in their supplied order, making changes along an ordered variable visible.
Sorting distance and elevation together keeps a route's line moving forward along the trail.
Logarithmic scale
A logarithmic scale gives equal visual distances to equal ratios of positive values instead of equal differences.
On a logarithmic scale, 2 to 20 occupies the same distance as 20 to 200.
Long format
Long format stores variables in columns and observations in rows, with a group column identifying each series.
A long table can map the station column to hue and the rainfall column to vertical position.

M

Marker area
Marker area is the size quantity controlled by the scatter argument s, measured in square typographic points.
Doubling marker area makes a marker wider by about 1.4 times, not twice as wide.
Melt
A melt reshapes series columns into a variable-name column and a value column while keeping chosen identifiers.
Melting three station columns creates a station field that seaborn can use for facets.

N

Native scale
Native scale preserves real numeric or date spacing on a seaborn categorical axis instead of using equal category steps.
With native scale, years 2019 and 2023 are farther apart than 2019 and 2020.
Numeric column
A numeric column stores values as numbers that plotting methods can use for measurements and summaries.
A column containing strings like "18 mm" needs cleaning before it becomes a numeric column.

O

Object-oriented interface
The object-oriented interface draws and customizes plots through named Figure and Axes objects and their methods.
Keeping a reference to each Axes lets a plotting function label the intended panel.
Overplotting
Overplotting occurs when marks overlap enough to hide observations or make dense regions difficult to read.
Smaller, partly transparent markers reveal clusters hidden by overplotting in a large sample.

P

Pair plot
A pair plot is a grid comparing pairs of numeric variables, with each variable's own distribution on the diagonal.
Limiting a pair plot to three variables gives nine panels before removing repeated pairs.
Pivot
A pivot rearranges values into rows and columns defined by two identifiers; each identifier pair must be unique.
Repeated readings for one station and month require aggregation before an ordinary pivot.
Plot accessor
The pandas plot accessor provides chart methods on a Series or DataFrame, using Matplotlib by default.
Use the plot accessor on grouped counts, then customize the returned Axes with a unit label.
Probability density
Probability density scales counts by sample size and bin width so that histogram area represents a share of observations.
A density of 0.02 per minute across a ten-minute bin gives a share of 0.2.

Q

Quartile
A quartile is a boundary dividing ordered data into quarters; Q1 and Q3 bound the middle half under the chosen method.
Interpolated quartiles can differ from hand-calculated half-sample medians in a small sample.

R

Raster image
A raster image stores a fixed grid of pixels, so enlarging it can make text and lines look blurred.
A PNG export with enough pixels keeps labels sharp at its intended display size.
Reference line
A reference line marks a meaningful coordinate value, such as a target, mean, or threshold, on a plot.
A vertical reference line at the median helps compare the two sides of a distribution.
Regression line
A regression line is a fitted line that summarizes a modeled relationship between numeric variables in a sample.
A straight regression line can miss a curved pattern that remains visible in the points.
Row normalization
Row normalization divides each entry by its row total so that the row represents shares adding up to one.
Row normalization compares travel-mode mixes across regions with different numbers of trips.

S

Scatter plot
A scatter plot places separate markers at pairs of numeric values to show relationships between observations.
Each marker in a scatter plot can represent one day's temperature and bicycle rentals.
Semantic mapping
A semantic mapping connects a data variable to a visual feature such as position, color, marker style, or size.
Mapping station to both hue and style distinguishes the same groups in two visual ways.
Sequential colormap
A sequential colormap orders colors from low to high values, making magnitudes in a numeric table visible.
A sequential colormap suits nonnegative visitor counts from quiet to busy periods.
Shared axis
A shared axis links coordinate scales across several panels so that corresponding positions represent the same values.
A shared y-axis makes a height of 80 mm occupy the same position in every station panel.
Small multiples
Small multiples repeat the same kind of chart for different subsets, usually using common scales for comparison.
One rainfall panel per station lets readers compare seasonal patterns without overlapping lines.
Stacked bar chart
A stacked bar chart places series on top of cumulative baselines so each bar shows both components and a total.
A 24-trip segment above a 36-trip segment gives a stacked bar with total height 60.
Standard deviation band
A standard deviation band extends a chosen number of standard deviations around a summary to show data spread.
A one-standard-deviation band answers a different question from a confidence band for a mean.
Strip plot
A strip plot draws individual observations by category, usually with random jitter to reduce exact overlap.
A strip plot over a box plot shows individual delivery times beside their summary.
Style sheet
A style sheet is a named set of Matplotlib defaults for visual settings such as colors, grids, fonts, and line widths.
A style context applies a style sheet during one block without changing later charts.
Subplot mosaic
A subplot mosaic defines a layout with repeated names for spanning panels and returns a dictionary of Axes.
A subplot mosaic can place a wide trend chart above two smaller distribution charts.
Swarm plot
A swarm plot shifts individual points along the category direction to avoid overlap when there is enough room.
A swarm plot can show repeated times separately instead of hiding them at one location.

T

Theme
A theme is a collection of plotting defaults for style, text size, and palette that affects charts created afterward.
Setting a seaborn theme also changes the appearance of later plain Matplotlib charts.
Tick
A tick is a marked position on a coordinate axis; its label is the text used to describe that position.
Month numbers can have ticks labeled "Jan", "Feb", and "Mar" without changing their positions.
Tick formatter
A tick formatter converts coordinate values to displayed labels while leaving the underlying numeric data unchanged.
A percent tick formatter can display the fraction 0.4 as "40%" on a share chart.
Tight bounding box
A tight bounding box fits the export around the drawn content and padding, potentially changing the final image dimensions.
A tight bounding box can include an outside legend while removing unused margins.

V

Vector graphic
A vector graphic stores shapes and paths that can be scaled without the pixelation of an enlarged raster image.
An SVG chart keeps its vector text and lines sharp when resized for a report.
Violin plot
A violin plot displays a mirrored density estimate for each group, often with a small summary drawn inside.
A violin plot can reveal two peaks that are hidden by a box plot of the same observations.

W

Whisker
A whisker extends from a box toward the most extreme observation inside its fence under the usual box-plot rule.
An upper fence of 36 minutes and an in-range maximum of 33 put the whisker at 33 minutes.
Wide format
Wide format stores separate series in separate columns, with row identifiers shared across those series.
A wide table with one column per station draws one pandas line per station.

About this lesson

By StudeliReport a mistake

Make your own Study Materials

Turn your notes, slides and documents into Study Guides, Practice Questions, Flashcards and 6 more tools.

Get Started