import numpy as np, pandas as pd
import matplotlib as mpl, matplotlib.pyplot as plt
# A clean house style for report-ready figures: no chartjunk, strong titles, muted grid.
mpl.rcParams.update({"figure.dpi":110,"font.size":11,"axes.spines.top":False,"axes.spines.right":False,
"axes.grid":True,"grid.alpha":0.22,"axes.titleweight":"bold","axes.titlesize":12.5,
"axes.titlelocation":"left","axes.titlepad":10})
ROSE, INK, MUT, GR, RD = "#be123c", "#1a2138", "#64748b", "#16a34a", "#dc2626"
pd.set_option('display.max_columns', 20)
Recipe 1 · Format the numbers so they read at a glance¶
Raw floats like 535879.0 slow a reader down. Format currency, percentages, and thousands, right-align them, and round to the precision the decision needs, never more.
df = pd.DataFrame({
"Region":["North","West","East","South","Central"],
"Revenue":[535879, 489393, 422289, 379930, 327447],
"Share":[0.249, 0.227, 0.196, 0.176, 0.152],
"Growth":[0.14, 0.11, 0.09, 0.07, 0.05]})
styled = (df.style.hide(axis="index")
.format({"Revenue":"${:,.0f}", "Share":"{:.1%}", "Growth":"{:+.0%}"}))
styled
| Region | Revenue | Share | Growth |
|---|---|---|---|
| North | $535,879 | 24.9% | +14% |
| West | $489,393 | 22.7% | +11% |
| East | $422,289 | 19.6% | +9% |
| South | $379,930 | 17.6% | +7% |
| Central | $327,447 | 15.2% | +5% |
Recipe 2 · Highlight what matters, and add a total¶
Guide the eye: shade the largest value, color growth by sign, and append a summary row so the reader sees the whole and the parts together.
total = pd.DataFrame({"Region":["TOTAL"], "Revenue":[df.Revenue.sum()],
"Share":[df.Share.sum()], "Growth":[np.nan]})
full = pd.concat([df, total], ignore_index=True)
def color_growth(v): return "" if pd.isna(v) else f"color:{'#16a34a' if v>=0.1 else '#b45309'}"
styled = (full.style.hide(axis="index")
.format({"Revenue":"${:,.0f}", "Share":"{:.1%}", "Growth":lambda v: "" if pd.isna(v) else f"{v:+.0%}"})
.background_gradient(subset=["Revenue"], cmap="Reds")
.map(color_growth, subset=["Growth"])
.set_properties(subset=pd.IndexSlice[full.index[-1], :], **{"font-weight":"bold"}))
styled
| Region | Revenue | Share | Growth |
|---|---|---|---|
| North | $535,879 | 24.9% | +14% |
| West | $489,393 | 22.7% | +11% |
| East | $422,289 | 19.6% | +9% |
| South | $379,930 | 17.6% | +7% |
| Central | $327,447 | 15.2% | +5% |
| TOTAL | $2,154,938 | 100.0% |
Recipe 3 · A reusable report-table function¶
Wrap the choices into one function so every table in a report looks the same. Pass a frame and the column formats; get back a clean, styled table.
def report_table(frame, formats, highlight=None):
s = frame.style.hide(axis="index").format(formats)
if highlight: s = s.background_gradient(subset=[highlight], cmap="Reds")
return s.set_table_styles([{"selector":"th","props":[("background-color","#be123c"),("color","white"),
("font-size","11px"),("text-align","left")]}])
report_table(df, {"Revenue":"${:,.0f}","Share":"{:.1%}","Growth":"{:+.0%}"}, highlight="Revenue")
| Region | Revenue | Share | Growth |
|---|---|---|---|
| North | $535,879 | 24.9% | +14% |
| West | $489,393 | 22.7% | +11% |
| East | $422,289 | 19.6% | +9% |
| South | $379,930 | 17.6% | +7% |
| Central | $327,447 | 15.2% | +5% |
Recipe 4 · Export the finished table to Excel and to Word¶
A styled table is only useful if it lands in the deliverable. Save it to Excel with formatting intact, and drop it straight into a Word document as a real table, the bridge from notebook to report.
# to Excel (keeps the number formats)
report_table(df, {"Revenue":"${:,.0f}","Share":"{:.1%}","Growth":"{:+.0%}"}).to_excel("region_table.xlsx", index=False)
print("wrote region_table.xlsx")
# to Word: a real table a reader can select and reuse
try:
import docx
except ModuleNotFoundError: # python-docx is not preinstalled on Google Colab
import sys, subprocess; subprocess.run([sys.executable, "-m", "pip", "install", "-q", "python-docx"]); import docx
from docx import Document
disp = df.assign(Revenue=df.Revenue.map("${:,.0f}".format), Share=df.Share.map("{:.1%}".format),
Growth=df.Growth.map("{:+.0%}".format))
doc = Document(); doc.add_heading("Revenue by Region", level=1)
t = doc.add_table(rows=1, cols=len(disp.columns)); t.style = "Light Grid Accent 1"
for j, c_ in enumerate(disp.columns):
t.rows[0].cells[j].text = c_; t.rows[0].cells[j].paragraphs[0].runs[0].bold = True
for _, r in disp.iterrows():
cs = t.add_row().cells
for j, c_ in enumerate(disp.columns): cs[j].text = str(r[c_])
doc.save("region_table.docx"); print("wrote region_table.docx")
wrote region_table.xlsx wrote region_table.docx
Wrap-up¶
Format for the decision, highlight the one number that matters, summarize with a total, and standardize it in a function. Then export to the format the audience actually opens, Excel for analysts, Word for a report. The three report notebooks that follow put these tables and the charts together into finished, downloadable documents.