Exerciseschevron_rightChapter 5chevron_right5.3
fitness_center

Exercise 5.3

Extended Well Log Display

Level 2
Chapter 5: Data Visualization & Plotting
descriptionProblem

Extend the chapter's triple-combo log to a four-track display by adding water saturation (Sw) as a fourth track.

Use the following synthetic depth and curve data (provided in the starter):

  • depth: 7,000 to 7,500 ft, 250 points
  • gr: gamma ray
  • rt: deep resistivity (log scale)
  • phi: density-derived porosity
  • sw: water saturation in 0–1, low (~0.2) in the **hydrocarbon

sand** between 7,200 and 7,350 ft, high (~0.8) elsewhere

Build a figure with four side-by-side tracks sharing the depth axis:

  1. Track 1: gamma ray
  2. Track 2: resistivity on a log x-scale (set_xscale("log"))
  3. Track 3: porosity
  4. Track 4: water saturation Sw, with the **area between Sw and

1.0** filled in green (representing hydrocarbon-filled pore volume) using ax.fill_betweenx(depth, sw, 1.0, ...).

All tracks must:

  • Share the depth y-axis (sharey=True).
  • Display depth increasing downward (invert the y-axis once).
  • Have an x-axis label naming the curve, plus a track title.
lightbulbHints (0/5)

Stuck? Reveal hints one at a time — they progress from nudge to near-solution.

codeYour solution
main.py
visibilityReveal reference solutionexpand_more

Try solving it yourself first — the hints walk you through it. The solution below is one valid approach; yours may differ and still be correct.

import numpy as np
import matplotlib.pyplot as plt

np.random.seed(42)
depth = np.linspace(7000, 7500, 250)
in_sand = (depth >= 7200) & (depth <= 7350)

gr  = np.where(in_sand, 30, 110) + np.random.normal(0, 6, depth.size)
rt  = np.where(in_sand, 50, 2.0) * np.exp(np.random.normal(0, 0.2, depth.size))
phi = np.where(in_sand, 0.22, 0.08) + np.random.normal(0, 0.02, depth.size)
sw  = np.where(in_sand, 0.20, 0.80) + np.random.normal(0, 0.04, depth.size)
sw  = np.clip(sw, 0, 1)

fig, axes = plt.subplots(1, 4, figsize=(12, 9), sharey=True)

axes[0].plot(gr, depth, color="#2E8B57", linewidth=0.8)
axes[0].set_xlabel("GR (gAPI)")
axes[0].set_xlim(0, 150)
axes[0].set_title("Gamma Ray")

axes[1].plot(rt, depth, color="#CC4444", linewidth=0.8)
axes[1].set_xscale("log")
axes[1].set_xlabel("RT (ohm·m)")
axes[1].set_xlim(0.2, 200)
axes[1].set_title("Deep Resistivity")

axes[2].plot(phi, depth, color="#4682B4", linewidth=0.8)
axes[2].set_xlabel("Porosity (v/v)")
axes[2].set_xlim(0, 0.4)
axes[2].set_title("Porosity")

# Track 4: Sw with green hydrocarbon fill between Sw and 1.0
axes[3].plot(sw, depth, color="black", linewidth=0.8)
axes[3].fill_betweenx(depth, sw, 1.0, color="green", alpha=0.3, label="HC-filled pore")
axes[3].set_xlabel("Sw (v/v)")
axes[3].set_xlim(0, 1)
axes[3].set_title("Water Saturation")
axes[3].legend(loc="lower left", fontsize=8)

axes[0].invert_yaxis()        # all axes share y, so inverting once flips them all
axes[0].set_ylabel("Depth (ft)")

for ax in axes:
    ax.grid(True, alpha=0.2)

fig.suptitle("Four-track petrophysical log - GR / RT / φ / Sw",
             fontweight="bold", y=1.01)
plt.tight_layout()
plt.show()

lockCopying code is a Full Access feature.