Unit Conversion Example — convert_units

This example demonstrates utilities.convert_units() across four physical categories: length (km / m / cm / mm), mass (kg / g / lb / oz), angle (degrees / radians / gradians), and temperature (°C / °F / K). Conversion tables are printed to stdout and two temperature-curve plots are generated — Celsius→Fahrenheit and Celsius→Kelvin — over the range −40 °C to +100 °C.

Example Code

"""IMSL unit conversion example: convert_units across length, mass, angle, temperature.

Outputs:
- Conversion tables printed to stdout
- SVG temperature conversion curves saved to
  test_output/example_imsl_unit_conversion.svg
"""
from __future__ import annotations

from pathlib import Path
from typing import Dict

import matplotlib.pyplot as plt
import numpy as np

from utilities import convert_units


def run_demo_imsl_unit_conversion() -> Dict[str, object]:
    """Demonstrate :func:`utilities.convert_units` across multiple categories.

    Builds conversion tables for length (km/m/cm/mm), mass (kg/g/lb/oz),
    angle (deg/rad), and temperature (C/F/K).  Plots temperature conversion
    curves for Celsius→Fahrenheit and Celsius→Kelvin over the range −40 °C
    to +100 °C.

    Args:
        None

    Returns:
        Dict[str, object]: Result dict with keys ``length_table`` (list),
            ``mass_table`` (list), ``angle_table`` (list),
            ``temp_table`` (list), and ``plot_path`` (str).
    """
    # ── Length conversion table ───────────────────────────────────────────────
    length_values_km = [0.001, 0.01, 0.1, 1.0, 10.0, 100.0]
    length_units = ["km", "m", "cm", "mm"]
    length_table: list[dict] = []

    print("\nIMSL Unit Conversion Example")
    print("=" * 70)

    print("\n  Length Conversion Table")
    print(f"  {'km':>10}  {'m':>12}  {'cm':>14}  {'mm':>16}")
    print("  " + "-" * 56)
    for km in length_values_km:
        row: dict[str, float] = {"km": km}
        m_val = convert_units(km, "km", "m")
        cm_val = convert_units(km, "km", "cm")
        mm_val = convert_units(km, "km", "mm")
        row.update({"m": m_val, "cm": cm_val, "mm": mm_val})
        length_table.append(row)
        print(f"  {km:>10.4f}  {m_val:>12.2f}  {cm_val:>14.2f}  {mm_val:>16.2f}")

    # ── Mass conversion table ─────────────────────────────────────────────────
    mass_values_kg = [0.001, 0.01, 0.1, 0.5, 1.0, 5.0, 10.0]
    mass_table: list[dict] = []

    print("\n  Mass Conversion Table")
    print(f"  {'kg':>8}  {'g':>10}  {'lb':>12}  {'oz':>12}")
    print("  " + "-" * 48)
    for kg in mass_values_kg:
        g_val = convert_units(kg, "kg", "g")
        lb_val = convert_units(kg, "kg", "lb")
        oz_val = convert_units(kg, "kg", "oz")
        mass_table.append({"kg": kg, "g": g_val, "lb": lb_val, "oz": oz_val})
        print(f"  {kg:>8.4f}  {g_val:>10.3f}  {lb_val:>12.6f}  {oz_val:>12.6f}")

    # ── Angle conversion table ────────────────────────────────────────────────
    angle_values_deg = [0.0, 30.0, 45.0, 60.0, 90.0, 180.0, 270.0, 360.0]
    angle_table: list[dict] = []

    print("\n  Angle Conversion Table")
    print(f"  {'deg':>8}  {'rad':>12}  {'grad':>10}")
    print("  " + "-" * 36)
    for deg in angle_values_deg:
        rad_val = convert_units(deg, "deg", "rad")
        grad_val = convert_units(deg, "deg", "grad")
        angle_table.append({"deg": deg, "rad": rad_val, "grad": grad_val})
        print(f"  {deg:>8.1f}  {rad_val:>12.6f}  {grad_val:>10.4f}")

    # ── Temperature conversion table ──────────────────────────────────────────
    temp_values_c = [-40.0, -20.0, 0.0, 20.0, 37.0, 100.0]
    temp_table: list[dict] = []

    print("\n  Temperature Conversion Table")
    print(f"  {'°C':>8}  {'°F':>10}  {'K':>10}")
    print("  " + "-" * 34)
    for c in temp_values_c:
        f_val = convert_units(c, "C", "F")
        k_val = convert_units(c, "C", "K")
        temp_table.append({"C": c, "F": f_val, "K": k_val})
        print(f"  {c:>8.1f}  {f_val:>10.2f}  {k_val:>10.2f}")

    # ── Plot: temperature conversion curves ───────────────────────────────────
    output_dir = Path("test_output")
    output_dir.mkdir(parents=True, exist_ok=True)
    plot_path = output_dir / "example_imsl_unit_conversion.svg"

    c_range = np.linspace(-40.0, 100.0, 200)
    f_range = np.array([convert_units(c, "C", "F") for c in c_range])
    k_range = np.array([convert_units(c, "C", "K") for c in c_range])

    fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(13, 5))

    ax1.plot(c_range, f_range, color="#b45309", linewidth=2.2,
             label="°C → °F")
    ax1.axhline(32.0, color="gray", linewidth=0.8, linestyle="--",
                label="Freezing 32 °F")
    ax1.axhline(212.0, color="gray", linewidth=0.8, linestyle=":",
                label="Boiling 212 °F")
    ax1.axvline(0.0, color="#92400e", linewidth=0.8, linestyle="--", alpha=0.7)
    ax1.axvline(100.0, color="#92400e", linewidth=0.8, linestyle=":", alpha=0.7)
    ax1.scatter([-40.0], [-40.0], color="red", zorder=5,
                label="−40 °C = −40 °F")
    ax1.set_xlabel("Temperature (°C)")
    ax1.set_ylabel("Temperature (°F)")
    ax1.set_title("Celsius → Fahrenheit")
    ax1.legend(fontsize=8)
    ax1.grid(True, alpha=0.3)

    ax2.plot(c_range, k_range, color="#d97706", linewidth=2.2,
             label="°C → K")
    ax2.axhline(273.15, color="gray", linewidth=0.8, linestyle="--",
                label="Freezing 273.15 K")
    ax2.axhline(373.15, color="gray", linewidth=0.8, linestyle=":",
                label="Boiling 373.15 K")
    ax2.axvline(-273.15, color="#92400e", linewidth=0.8, linestyle="-.",
                alpha=0.6, label="Absolute zero")
    ax2.set_xlabel("Temperature (°C)")
    ax2.set_ylabel("Temperature (K)")
    ax2.set_title("Celsius → Kelvin")
    ax2.legend(fontsize=8)
    ax2.grid(True, alpha=0.3)

    fig.suptitle("IMSL Unit Conversion: convert_units — temperature curves",
                 fontweight="bold")
    fig.tight_layout()
    fig.savefig(plot_path, format="svg")
    plt.close(fig)

    print(f"\nPlot saved to: {plot_path}")
    return {
        "length_table": length_table,
        "mass_table": mass_table,
        "angle_table": angle_table,
        "temp_table": temp_table,
        "plot_path": str(plot_path),
    }


if __name__ == "__main__":
    run_demo_imsl_unit_conversion()

Plot Output

Two-panel temperature conversion curves: °C vs °F and °C vs K

Left: Celsius-to-Fahrenheit curve with freezing/boiling reference lines and the −40 °C = −40 °F crossover point highlighted. Right: Celsius-to-Kelvin curve with absolute-zero marker.

Console Output

IMSL Unit Conversion Example
======================================================================

  Length Conversion Table
          km             m              cm                mm
  --------------------------------------------------------
      0.0010          1.00          100.00           1000.00
      0.0100         10.00         1000.00          10000.00
      0.1000        100.00        10000.00         100000.00
      1.0000       1000.00       100000.00        1000000.00
     10.0000      10000.00      1000000.00       10000000.00
    100.0000     100000.00     10000000.00      100000000.00

  Mass Conversion Table
        kg           g            lb            oz
  ------------------------------------------------
    0.0010       1.000      0.002205      0.035274
    0.0100      10.000      0.022046      0.352740
    0.1000     100.000      0.220462      3.527396
    0.5000     500.000      1.102311     17.636981
    1.0000    1000.000      2.204623     35.273962
    5.0000    5000.000     11.023113    176.369810
   10.0000   10000.000     22.046226    352.739619

  Angle Conversion Table
       deg           rad        grad
  ------------------------------------
       0.0      0.000000      0.0000
      30.0      0.523599     33.3333
      45.0      0.785398     50.0000
      60.0      1.047198     66.6667
      90.0      1.570796    100.0000
     180.0      3.141593    200.0000
     270.0      4.712389    300.0000
     360.0      6.283185    400.0000

  Temperature Conversion Table
        ┬░C          ┬░F           K
  ----------------------------------
     -40.0      -40.00      233.15
     -20.0       -4.00      253.15
       0.0       32.00      273.15
      20.0       68.00      293.15
      37.0       98.60      310.15
     100.0      212.00      373.15

Plot saved to: test_output\example_imsl_unit_conversion.svg