5.4.16 · D3Scientific Computing (Python)

Worked examples — 2D plots — line, scatter, bar, histogram, contour, imshow

3,085 words14 min readBack to topic

You have read the parent note and met the six plot types. Now we grind through every messy case you will actually hit: the degenerate ones (empty data, one bin, flat surface), the sign/orientation traps (upside-down images, negative extents), the limiting cases (many bins vs few), a real-world word problem, and an exam twist. Each example first asks you to guess, then shows the reasoning step-by-step, then verifies by plugging numbers back.

We will use only ideas already defined: a plot is a mapping from numbers to pixels; a histogram counts samples into bins of width ; density=True divides each count by so total area is ; a contour at level is the set ; imshow shows an array as colored cells with Z[row, col] = Z[y, x].


The scenario matrix

Every plotting bug or exam question lives in one of these cells. The examples below are labelled with the cell they cover.

# Cell class Concrete trap / question Example
C1 Line — resolution limit few points look jagged, many look smooth Ex 1
C2 Histogram — bin arithmetic which bin does a value land in? edge rule Ex 2
C3 Histogram — normalization does density=True really give area ? Ex 3
C4 Histogram — degenerate bin, or all samples identical Ex 4
C5 Bar — geometry left edge, width, gaps, negative height Ex 5
C6 Contour — the level set which are on level ? radius formula Ex 6
C7 imshow — orientation signs origin upper vs lower, row↔y flip Ex 7
C8 imshow — extent mapping array index → real coordinate, incl. negatives Ex 8
C9 Real-world word problem temperature log: choose the right plot + numbers Ex 9
C10 Exam twist mix meshgrid shape + contour count Ex 10

Ex 1 — Line resolution (cell C1)

Forecast: Guess the number of segments and whether 5 points can look smooth.

  1. Find the spacing. With points over , the gap between consecutive points is Why this step? np.linspace(a, b, n) puts points at the two ends and inside, so there are gaps — not . Dividing by is the whole trick.
  2. List the points. , giving . Why this step? These are exactly the peaks/zeros of sine, so the "curve" becomes a zig-zag of straight lines between them.
  3. Count segments. A line plot draws for , i.e. segments. Why this step? The parent formula: points connectors. Look at the red zig-zag in the figure — 4 straight pieces, no curve at all.
Figure — 2D plots — line, scatter, bar, histogram, contour, imshow

Verify: . Segment count . The eye only sees a smooth sine once segments are tiny (Ex needs ~200 points, so ~199 segments). Units: in radians, dimensionless. ✔


Ex 2 — Which bin? (cell C2)

Forecast: Guess whether lands in the same bin as .

  1. Bin width. . Why this step? Everything depends on ; get it wrong and every index shifts.
  2. Bin edges. — indices . Why this step? Each interval is half-open (closed left, open right), so a value exactly on an edge goes to the bin on its right, except the very last edge.
  3. Place the values. The formula for the index is .
    • : → bin 1 .
    • : → bin 2 .
    • : naively , but there is no bin 5. Matplotlib puts the max value into the last bin, so → bin 4 . Why this step? This is the classic "edge counted twice or lost" trap. The half-open rule stops double-counting; the last bin is closed on the right so the maximum isn't dropped.

Verify: and land in different bins (1 vs 2) — the boundary at belongs to the right bin. And is rescued into bin 4, not an illegal bin 5. ✔


Ex 3 — Does density=True give area 1? (cell C3)

Forecast: Guess the total area before computing — it should be a clean number.

  1. Bin width. . Why this step? Area of a bar height ; we need to turn heights into areas.
  2. Density heights. Each becomes : Why this step? Dividing by is the parent's normalization: it converts counts into a probability density so we can overlay a theoretical PDF (Probability density functions and normalization).
  3. Sum the areas. Area . Why this step? Because . The counts must sum to , so the areas must sum to 1.

Verify: Counts sum: ✔. Total area ✔. Note heights are not probabilities themselves (bin 1 height its probability only because ; with they'd differ). ✔


Ex 4 — Degenerate histograms (cell C4)

Forecast: Guess whether makes the area still equal , and whether identical samples crash.

  1. (a) One bin. With the whole range is one bin: raw height . Why this step? Every sample lands in the only bin, so the count is all of them.
  2. Density for one bin. ; height , and area still. Why this step? Normalization is designed to give area 1 for any — even the useless that shows no shape.
  3. (b) All identical. Then , so — division by zero looms. NumPy's fix: it expands the range to (a unit-wide window around the value) so and the count goes into one bin without crashing. Why this step? A degenerate zero-width range would make every height infinite; the auto-padding keeps the plot finite and drawable.

Verify: (a) raw height ; density area regardless of ✔. (b) NumPy uses range , so and the single count is ✔ — no exception thrown.


Ex 5 — Bar geometry with a negative value (cell C5)

Forecast: Guess whether the negative bar points down and where its top/bottom sit.

  1. Position. Category ("B") sits at integer . Bar spans with : left , right . Why this step? Parent anatomy: a bar is a rectangle centered on the category's integer slot.
  2. Height sign. Height means the rectangle grows downward from the baseline : its top is at , its bottom at . Why this step? bar draws from the baseline (default 0) to the value; a negative value simply flips the direction below the axis.
  3. Gap between bars. Neighbours are 1 unit apart (integers 0,1,2); each occupies width , so the empty gap is . Why this step? Width is exactly what makes categories read as separate blocks — the parent's "WHY width matters".

Verify: Left , right ✔. Bar B occupies ✔. Gap so bars don't touch ✔.


Ex 6 — The contour level set (cell C6)

Forecast: Guess the shape of the highest level's contour — a curve or a point?

  1. Write the level equation. The contour at level is , i.e. . Why this step? A contour is a set of points solving an equation — we solve it explicitly.
  2. Take logs to free the exponent. . Why the logarithm? The unknown is trapped in an exponent; is the tool that undoes , turning "-to-the-something " into "something ". No other operation isolates the exponent.
  3. Read off the radius. is a circle of radius centered at the origin. Why this step? is the circle definition — so every level of a Gaussian bump is a circle, as the figure's red ring shows.
  4. Degenerate top. The maximum of is at the origin where . The level solves — a single point, not a curve. Levels give the empty set (no contour drawn). Why this step? This is the limiting case: as the peak, the circle shrinks to a dot; beyond the peak nothing exists to slice.
Figure — 2D plots — line, scatter, bar, histogram, contour, imshow

Verify: ; check ✔. Max value ; level is the single point ; empty ✔.


Ex 7 — imshow orientation flip (cell C7)

Forecast: Guess whether row 0 sits at the top or bottom by default.

  1. Row↔y rule. imshow maps Z[row, col] with row = y, col = x (parent trap #2). Value is at Z[1,0] → row , column . Why this step? We must translate array indices into screen position before we can say "top" or "bottom".
  2. Default origin="upper". Row 0 is drawn at the top, rows increase downward. So row 1 (the row) is at the bottom, column 0 on the left appears bottom-left. Why this step? Image files store row 0 at the top; that's the default and why images look "right" but math matrices look flipped.
  3. origin="lower". Row 0 is drawn at the bottom, rows increase upward. Now row 1 is at the top, column 0 left → appears top-left. Why this step? origin="lower" makes increasing row = increasing (upward), which matches how we plot math where grows up.
Figure — 2D plots — line, scatter, bar, histogram, contour, imshow

Verify: With origin="upper", Z[1,0]=30 is bottom-left; flipping to origin="lower" moves it top-left — the two images are vertical mirror-flips of each other, exactly one row-reversal apart ✔.


Ex 8 — imshow extent mapping with negatives (cell C8)

Forecast: Guess whether cell [0,0] lands exactly at the corner or slightly inside.

  1. Cell width in real units. The x-range spans units across columns, so each cell is wide (same for y). Why this step? extent stretches the whole array to fill ; each of 100 cells gets an equal slice.
  2. Center of the first cell. Column 0 occupies real x from to ; its center is . With origin="lower", row 0 is at the bottom so its y-center is also . So Z[0,0] center . Why this step? Pixel centers, not edges, are the sample locations; the edge is at but the center sits half a cell in.
  3. Center of the last cell. Column 99 spans x from to ; center . Same for row 99 → Z[99,99] center . Why this step? By symmetry the far corner mirrors the near corner; the grid is symmetric about the origin.

Verify: Cell width ; first center , last center ; the two centers are symmetric () and span ✔. This uses the same even-spacing idea as NumPy meshgrid and broadcasting.


Ex 9 — Real-world word problem (cell C9)

Forecast: Guess which of the six plots fits ordered time vs a pile of samples.

  1. Temperature vs time → line. Time is an ordered axis and consecutive readings are connected as a trend, so ax.plot. Why this step? The parent decision table: "trend over an ordered axis → line". Connecting the dots is meaningful here (temperature between hours is continuous).
  2. Reaction times → histogram. 500 independent samples where we care about the shape of the distribution, not order, so ax.hist with bins. Why this step? Table: "distribution/shape of one variable → histogram"; is the parent's bin rule of thumb.
  3. The mean. Mean °C. A line plot shows the trend (when it peaked); a histogram would collapse the 24 ordered readings into value-buckets and lose the daily rhythm — so for time structure, line wins; for typical value, the mean/histogram wins. Why this step? Choosing the plot IS the question — each answers a different thing (WHEN vs HOW-OFTEN).

Verify: → about 22 bins ✔. Mean °C ✔ (units: degrees Celsius). Line for the 24-point ordered series, histogram for the 500-sample pile ✔.


Ex 10 — Exam twist: meshgrid shape meets contour (cell C10)

Forecast: Guess whether X is or — the order trips almost everyone.

  1. Grid shape. meshgrid(xs, ys) returns arrays of shape (len(ys), len(xs)) = (9, 5)rows follow ys, columns follow xs (the parent's , ). So X.shape = Z.shape = (9, 5). Why this step? Contour needs Z shaped (len(y), len(x)); getting it backwards raises a shape error. This is the parent mistake "contour takes my 1D x and y" made concrete.
  2. Number of contour lines. levels=[1, 4, 9] lists 3 explicit levels, so up to 3 contour curves are drawn (one per level that actually intersects the surface). Why this step? Passing a list (not an int) means "draw exactly these levels", unlike levels=8 which means "pick 8 nice levels automatically".
  3. A point on level . Solve . Pick a grid value: ; the point is on the surface's grid (since is one of ys) and satisfies . Another: , and gives . Why this step? The level set is literally the solution set of ; we exhibit members of it to prove the line exists.

Verify: meshgrid(xs, ys) → shape (9,5) ✔ (9 rows, 5 cols). levels=[1,4,9] → 3 lines ✔. On : ✔ and ✔.


Recall Rapid self-test

Bin width for range , ? ::: . Does a value exactly on a bin's left edge go left or right? ::: Right (bins are half-open). Density heights sum-of-areas must equal? ::: (since ). Radius of contour? ::: . meshgrid(xs, ys) gives X of what shape? ::: (len(ys), len(xs)). origin="lower" vs "upper" — which matches math matrices? ::: "lower" (row 0 at bottom, up). Bar at category , width — left edge? ::: .

See also: Matplotlib Figure vs Axes object model · Colormaps and perceptual uniformity (viridis) · Image arrays and pixel coordinates · 3D surface plots (plot_surface) · Seaborn — statistical plotting wrappers.