Formatting Utilities¶
Functions for formatting axis tick labels, rotating labels, and displaying numeric values in common formats.
Overview¶
The formatting module provides utilities for presenting numeric data in readable, publication-quality formats. These functions handle common formatting needs like percentages, thousands separators, currency, and scientific notation.
Key Features¶
Automatic formatting: Convert raw numbers to human-readable formats
Locale support: Format numbers according to regional conventions
Scientific notation: SI prefixes and engineering notation
Financial formats: Currency, millions, billions with appropriate suffixes
Label rotation: Rotate tick labels for better readability
API Reference¶
Numeric Formatting¶
- dartwork_mpl.format_axis_percent(ax: Axes, axis: Literal['x', 'y', 'both'] = 'y', decimals: int = 0) None[source]¶
Format axis tick labels as percentages.
- Parameters:
ax (Axes) – Matplotlib axes
axis (Literal["x", "y", "both"]) – Which axis to format
decimals (int) – Number of decimal places
Examples
>>> format_axis_percent(ax) # Format y-axis as percentages >>> format_axis_percent(ax, axis="both", decimals=1)
- dartwork_mpl.format_axis_thousands(ax: Axes, axis: Literal['x', 'y', 'both'] = 'y', sep: str = ',') None[source]¶
Format axis tick labels with thousands separator.
- Parameters:
ax (Axes) – Matplotlib axes
axis (Literal["x", "y", "both"]) – Which axis to format
sep (str) – Thousands separator (default: comma)
Examples
>>> format_axis_thousands(ax) # Format y-axis with commas
- dartwork_mpl.format_axis_millions(ax: Axes, axis: Literal['x', 'y', 'both'] = 'y', suffix: str = 'M', decimals: int = 1) None[source]¶
Format axis tick labels in millions.
- Parameters:
ax (Axes) – Matplotlib axes
axis (Literal["x", "y", "both"]) – Which axis to format
suffix (str) – Suffix to add (default: “M”)
decimals (int) – Number of decimal places
Examples
>>> format_axis_millions(ax) # Show as 1.5M instead of 1500000
- dartwork_mpl.format_axis_billions(ax: Axes, axis: Literal['x', 'y', 'both'] = 'y', suffix: str = 'B', decimals: int = 1) None[source]¶
Format axis tick labels in billions.
- Parameters:
ax (Axes) – Matplotlib axes
axis (Literal["x", "y", "both"]) – Which axis to format
suffix (str) – Suffix to add (default: “B”)
decimals (int) – Number of decimal places
Examples
>>> format_axis_billions(ax) # Show as 1.5B instead of 1500000000
- dartwork_mpl.format_axis_currency(ax: Axes, axis: Literal['x', 'y', 'both'] = 'y', symbol: str = '$', position: Literal['prefix', 'suffix'] = 'prefix', decimals: int = 0) None[source]¶
Format axis tick labels as currency.
- Parameters:
ax (Axes) – Matplotlib axes
axis (Literal["x", "y", "both"]) – Which axis to format
symbol (str) – Currency symbol
position (Literal["prefix", "suffix"], optional) – Position of currency symbol
decimals (int) – Number of decimal places
Examples
>>> format_axis_currency(ax) # Format as $1,000 >>> format_axis_currency(ax, symbol="€", position="suffix") # Format as 1,000€
- dartwork_mpl.format_axis_si(ax: Axes, axis: Literal['x', 'y', 'both'] = 'y', decimals: int = 1) None[source]¶
Format axis tick labels with SI prefixes (k, M, G, etc.).
- Parameters:
ax (Axes) – Matplotlib axes
axis (Literal["x", "y", "both"]) – Which axis to format
decimals (int) – Number of decimal places
Examples
>>> format_axis_si(ax) # Show as 1.5k, 2.3M, etc.
Label Management¶
- dartwork_mpl.rotate_tick_labels(ax: Axes, axis: Literal['x', 'y', 'both'] = 'x', rotation: float = 45, ha: str | None = None) None[source]¶
Rotate tick labels for better readability.
- Parameters:
ax (Axes) – Matplotlib axes
axis (Literal["x", "y", "both"]) – Which axis to rotate
rotation (float) – Rotation angle in degrees
ha (str | None) – Horizontal alignment. If None, automatically set based on rotation
Examples
>>> rotate_tick_labels(ax) # Rotate x-axis labels 45 degrees >>> rotate_tick_labels(ax, rotation=90, axis="both")
Examples¶
Percentage Formatting¶
import dartwork_mpl as dm
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
# Data as fractions (0 to 1)
x = np.arange(5)
y = np.array([0.15, 0.32, 0.45, 0.28, 0.52])
ax.bar(x, y)
# Format y-axis as percentages
dm.format_axis_percent(ax, axis='y') # Shows: 15%, 32%, 45%, etc.
# With custom decimal places
dm.format_axis_percent(ax, axis='y', decimals=1) # Shows: 15.0%, 32.0%, etc.
Financial Data Formatting¶
# Thousands separator
fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(12, 4))
# Revenue in thousands
revenue = np.array([125000, 248000, 392000, 516000, 687000])
ax1.plot(revenue)
dm.format_axis_thousands(ax1, axis='y') # Shows: 125,000, 248,000, etc.
ax1.set_title('Revenue ($)')
# Market cap in millions
market_cap = np.array([1.2e6, 2.5e6, 4.8e6, 8.3e6])
ax2.bar(range(len(market_cap)), market_cap)
dm.format_axis_millions(ax2, axis='y') # Shows: 1.2M, 2.5M, etc.
ax2.set_title('Market Cap')
# GDP in billions
gdp = np.array([1.8e9, 2.1e9, 2.4e9, 2.7e9])
ax3.plot(gdp)
dm.format_axis_billions(ax3, axis='y', suffix='B') # Shows: 1.8B, 2.1B, etc.
ax3.set_title('GDP')
Currency Formatting¶
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4))
prices = np.array([19.99, 34.50, 78.25, 124.00, 259.99])
# US Dollars
ax1.bar(range(len(prices)), prices)
dm.format_axis_currency(ax1, axis='y', symbol='$', position='prefix')
ax1.set_title('Product Prices (USD)')
# Euros (suffix style)
ax2.bar(range(len(prices)), prices * 0.85) # Convert to EUR
dm.format_axis_currency(ax2, axis='y', symbol='€', position='suffix')
ax2.set_title('Product Prices (EUR)')
Scientific Notation with SI Prefixes¶
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4))
# Frequency data
freq = np.logspace(3, 9, 50) # 1kHz to 1GHz
response = -20 * np.log10(freq / 1e6)
ax1.semilogx(freq, response)
dm.format_axis_si(ax1, axis='x') # Shows: 1k, 10k, 100k, 1M, 10M, 100M, 1G
ax1.set_xlabel('Frequency (Hz)')
ax1.set_ylabel('Response (dB)')
# Power measurements
power = np.array([1e-9, 1e-6, 1e-3, 1, 1e3]) # nW to kW
ax2.bar(range(len(power)), power)
ax2.set_yscale('log')
dm.format_axis_si(ax2, axis='y') # Shows: 1n, 1μ, 1m, 1, 1k
ax2.set_ylabel('Power (W)')
Rotating Labels¶
fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(12, 4))
# Long category names
categories = ['Category A with Long Name',
'Category B with Even Longer Name',
'Category C Short',
'Category D Medium Length',
'Category E Final']
values = np.random.randn(len(categories))
# Default rotation (45 degrees)
ax1.bar(range(len(categories)), values)
ax1.set_xticks(range(len(categories)))
ax1.set_xticklabels(categories)
dm.rotate_tick_labels(ax1, axis='x')
ax1.set_title('45° Rotation (Default)')
# Vertical rotation
ax2.bar(range(len(categories)), values)
ax2.set_xticks(range(len(categories)))
ax2.set_xticklabels(categories)
dm.rotate_tick_labels(ax2, axis='x', rotation=90, ha='right')
ax2.set_title('90° Rotation')
# Angled with custom alignment
ax3.bar(range(len(categories)), values)
ax3.set_xticks(range(len(categories)))
ax3.set_xticklabels(categories)
dm.rotate_tick_labels(ax3, axis='x', rotation=30, ha='right')
ax3.set_title('30° Rotation')
dm.simple_layout(fig)
Complete Example: Financial Dashboard¶
import dartwork_mpl as dm
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
# Create sample financial data
quarters = ['Q1 2023', 'Q2 2023', 'Q3 2023', 'Q4 2023', 'Q1 2024']
revenue = np.array([1.2e6, 1.5e6, 1.8e6, 2.1e6, 2.4e6])
profit_margin = np.array([0.12, 0.15, 0.18, 0.14, 0.16])
stock_price = np.array([45.20, 52.30, 61.50, 58.40, 67.80])
market_cap = revenue * 50 # Simplified calculation
# Create dashboard
fig = plt.figure(figsize=(12, 8))
gs = fig.add_gridspec(2, 2, hspace=0.3, wspace=0.3)
# Revenue (top-left)
ax1 = fig.add_subplot(gs[0, 0])
ax1.bar(quarters, revenue, color='oc.green5')
dm.format_axis_millions(ax1, axis='y', suffix='M')
ax1.set_title('Quarterly Revenue')
ax1.set_ylabel('Revenue ($)')
dm.rotate_tick_labels(ax1, axis='x', rotation=45)
# Profit Margin (top-right)
ax2 = fig.add_subplot(gs[0, 1])
ax2.plot(quarters, profit_margin, 'o-', color='oc.blue5', lw=2)
dm.format_axis_percent(ax2, axis='y')
ax2.set_title('Profit Margin')
ax2.set_ylabel('Margin')
ax2.set_ylim(0, 0.25)
dm.rotate_tick_labels(ax2, axis='x', rotation=45)
# Stock Price (bottom-left)
ax3 = fig.add_subplot(gs[1, 0])
ax3.plot(quarters, stock_price, 's-', color='oc.purple5', lw=2)
dm.format_axis_currency(ax3, axis='y', symbol='$')
ax3.set_title('Stock Price')
ax3.set_ylabel('Price per Share')
dm.rotate_tick_labels(ax3, axis='x', rotation=45)
# Market Cap (bottom-right)
ax4 = fig.add_subplot(gs[1, 1])
ax4.bar(quarters, market_cap, color='oc.orange5')
dm.format_axis_billions(ax4, axis='y', suffix='B')
ax4.set_title('Market Capitalization')
ax4.set_ylabel('Market Cap ($)')
dm.rotate_tick_labels(ax4, axis='x', rotation=45)
# Style all axes
for ax in [ax1, ax2, ax3, ax4]:
dm.minimal_axes(ax)
dm.add_grid(ax, axis='y', alpha=0.2)
dm.simple_layout(fig)
plt.show()
Custom Number Formats¶
For formats not covered by the built-in functions, you can create custom formatters:
from matplotlib.ticker import FuncFormatter
# Custom formatter for displaying as fractions
def format_as_fraction(x, pos):
from fractions import Fraction
return str(Fraction(x).limit_denominator(10))
ax.yaxis.set_major_formatter(FuncFormatter(format_as_fraction))
# Custom formatter for log scale with superscript
def format_log_scale(x, pos):
exponent = int(np.log10(x))
return f'$10^{{{exponent}}}$'
ax.xaxis.set_major_formatter(FuncFormatter(format_log_scale))
International Number Formats¶
# European style (comma as decimal separator)
def format_european(x, pos):
return f'{x:.2f}'.replace('.', ',')
# Indian numbering system (lakhs and crores)
def format_indian(x, pos):
if x >= 1e7:
return f'{x/1e7:.1f}Cr' # Crores
elif x >= 1e5:
return f'{x/1e5:.1f}L' # Lakhs
else:
return f'{x:.0f}'
Best Practices¶
Choose appropriate units: Use millions/billions for large numbers to avoid too many digits
Decimal places: Use 0-1 decimals for general audiences, 2-3 for technical/financial
Consistency: Use the same format across related charts
Label rotation: Use 45° for moderate-length labels, 90° for very long labels
SI prefixes: Prefer for scientific/engineering contexts
Currency: Place symbol according to local convention (prefix for USD, suffix for EUR)
Common Patterns¶
Financial Reports¶
# Standard financial formatting
dm.format_axis_millions(ax_revenue, axis='y', suffix='M')
dm.format_axis_percent(ax_growth, axis='y', decimals=1)
dm.format_axis_currency(ax_price, axis='y', symbol='$')
Scientific Papers¶
# Scientific notation with SI units
dm.format_axis_si(ax_frequency, axis='x') # Hz
dm.format_axis_si(ax_power, axis='y') # W
dm.format_axis_percent(ax_efficiency, axis='y', decimals=2)
Web Analytics¶
# User metrics
dm.format_axis_thousands(ax_users, axis='y', sep=',')
dm.format_axis_percent(ax_conversion, axis='y', decimals=1)
dm.format_axis_millions(ax_pageviews, axis='y', suffix='M')
Integration with Themes¶
Formatting utilities work seamlessly with dartwork-mpl themes:
# Apply theme first
dm.style.use('scientific')
fig, ax = dm.subplots()
# Plot data
ax.plot(data)
# Format based on data type
if data_type == 'financial':
dm.format_axis_currency(ax, axis='y', symbol='$')
elif data_type == 'percentage':
dm.format_axis_percent(ax, axis='y')
elif data_type == 'scientific':
dm.format_axis_si(ax, axis='y')
See Also¶
Agent Helper Utilities - AI helper utilities including formatting
Quick Start - Getting started guide