[{"data":1,"prerenderedAt":1844},["ShallowReactive",2],{"doc:\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fchange-the-default-font-of-an-excel-workbook-with-python":3,"surround:\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fchange-the-default-font-of-an-excel-workbook-with-python":1810,"ancestors:\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fchange-the-default-font-of-an-excel-workbook-with-python":1819,"children:\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fchange-the-default-font-of-an-excel-workbook-with-python":1824,"related:\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fchange-the-default-font-of-an-excel-workbook-with-python":1825},{"id":4,"title":5,"body":6,"dateModified":1777,"datePublished":1777,"description":1778,"extension":1779,"faq":1780,"keyword":1789,"kind":1790,"meta":1791,"navigation":101,"path":1800,"seo":1801,"slug":1803,"stem":1804,"topics":1805,"type":1808,"__hash__":1809},"docs\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fchange-the-default-font-of-an-excel-workbook-with-python\u002Findex.md","Change the Default Font of an Excel Workbook with Python",{"type":7,"value":8,"toc":1763},"minimark",[9,24,29,61,72,76,79,274,284,288,295,471,478,634,638,644,764,771,775,778,1055,1077,1277,1281,1292,1502,1516,1607,1611,1634,1638,1641,1645,1682,1686,1698,1702,1708,1714,1720,1726,1730,1759],[10,11,12,13,17,18,23],"p",{},"Brand guidelines say Arial 10, or the company font, everywhere — and a generated report comes out in Calibri 11 except for the few cells the script styled explicitly. Styling every cell by hand is slow and misses empty cells that someone types into later. Excel keeps a workbook-wide default font in the ",[14,15,16],"em",{},"Normal"," cell style; set that, and every unstyled cell — including cells added later by a person — uses it. How to set it from Python depends on the library: XlsxWriter has an option for it, while openpyxl offers no public switch, and the obvious attempt silently does nothing. This page shows what works with each, how to keep bold and coloured cells in the same font family, and how to verify the result. It belongs to ",[19,20,22],"a",{"href":21},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002F","Styling Excel Cells with openpyxl",".",[25,26,28],"h2",{"id":27},"prerequisites","Prerequisites",[30,31,36],"pre",{"className":32,"code":33,"language":34,"meta":35,"style":35},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install xlsxwriter openpyxl pandas\n","bash","",[37,38,39],"code",{"__ignoreMap":35},[40,41,44,48,52,55,58],"span",{"class":42,"line":43},"line",1,[40,45,47],{"class":46},"sMTad","pip",[40,49,51],{"class":50},"srMev"," install",[40,53,54],{"class":50}," xlsxwriter",[40,56,57],{"class":50}," openpyxl",[40,59,60],{"class":50}," pandas\n",[10,62,63,64,67,68,71],{},"LibreOffice (",[37,65,66],{},"soffice",") and ",[37,69,70],{},"pdffonts"," (from Poppler) are used in Step 5 to check which fonts a rendered file really uses; they are optional.",[25,73,75],{"id":74},"step-1-xlsxwriter-default_format_properties","Step 1 — XlsxWriter: default_format_properties",[10,77,78],{},"XlsxWriter sets the default font when the workbook is created:",[30,80,84],{"className":81,"code":82,"language":83,"meta":35,"style":35},"language-python shiki shiki-themes github-light github-dark-high-contrast","import xlsxwriter\n\nbook = xlsxwriter.Workbook(\"branded.xlsx\", {\n    \"default_format_properties\": {\"font_name\": \"Arial\", \"font_size\": 10},\n})\nsheet = book.add_worksheet(\"Summary\")\nheading = book.add_format({\"bold\": True, \"font_color\": \"#4338CA\"})\nsheet.write(\"A1\", \"Quarterly summary\", heading)\nsheet.write_row(\"A3\", [\"Region\", \"Revenue\"])\nsheet.write_row(\"A4\", [\"North\", 1200])\nbook.close()\n","python",[37,85,86,96,103,121,154,160,177,208,225,248,268],{"__ignoreMap":35},[40,87,88,92],{"class":42,"line":43},[40,89,91],{"class":90},"s-kum","import",[40,93,95],{"class":94},"skGVy"," xlsxwriter\n",[40,97,99],{"class":42,"line":98},2,[40,100,102],{"emptyLinePlaceholder":101},true,"\n",[40,104,106,109,112,115,118],{"class":42,"line":105},3,[40,107,108],{"class":94},"book ",[40,110,111],{"class":90},"=",[40,113,114],{"class":94}," xlsxwriter.Workbook(",[40,116,117],{"class":50},"\"branded.xlsx\"",[40,119,120],{"class":94},", {\n",[40,122,124,127,130,133,136,139,142,145,147,151],{"class":42,"line":123},4,[40,125,126],{"class":50},"    \"default_format_properties\"",[40,128,129],{"class":94},": {",[40,131,132],{"class":50},"\"font_name\"",[40,134,135],{"class":94},": ",[40,137,138],{"class":50},"\"Arial\"",[40,140,141],{"class":94},", ",[40,143,144],{"class":50},"\"font_size\"",[40,146,135],{"class":94},[40,148,150],{"class":149},"sP0c6","10",[40,152,153],{"class":94},"},\n",[40,155,157],{"class":42,"line":156},5,[40,158,159],{"class":94},"})\n",[40,161,163,166,168,171,174],{"class":42,"line":162},6,[40,164,165],{"class":94},"sheet ",[40,167,111],{"class":90},[40,169,170],{"class":94}," book.add_worksheet(",[40,172,173],{"class":50},"\"Summary\"",[40,175,176],{"class":94},")\n",[40,178,180,183,185,188,191,193,196,198,201,203,206],{"class":42,"line":179},7,[40,181,182],{"class":94},"heading ",[40,184,111],{"class":90},[40,186,187],{"class":94}," book.add_format({",[40,189,190],{"class":50},"\"bold\"",[40,192,135],{"class":94},[40,194,195],{"class":149},"True",[40,197,141],{"class":94},[40,199,200],{"class":50},"\"font_color\"",[40,202,135],{"class":94},[40,204,205],{"class":50},"\"#4338CA\"",[40,207,159],{"class":94},[40,209,211,214,217,219,222],{"class":42,"line":210},8,[40,212,213],{"class":94},"sheet.write(",[40,215,216],{"class":50},"\"A1\"",[40,218,141],{"class":94},[40,220,221],{"class":50},"\"Quarterly summary\"",[40,223,224],{"class":94},", heading)\n",[40,226,228,231,234,237,240,242,245],{"class":42,"line":227},9,[40,229,230],{"class":94},"sheet.write_row(",[40,232,233],{"class":50},"\"A3\"",[40,235,236],{"class":94},", [",[40,238,239],{"class":50},"\"Region\"",[40,241,141],{"class":94},[40,243,244],{"class":50},"\"Revenue\"",[40,246,247],{"class":94},"])\n",[40,249,251,253,256,258,261,263,266],{"class":42,"line":250},10,[40,252,230],{"class":94},[40,254,255],{"class":50},"\"A4\"",[40,257,236],{"class":94},[40,259,260],{"class":50},"\"North\"",[40,262,141],{"class":94},[40,264,265],{"class":149},"1200",[40,267,247],{"class":94},[40,269,271],{"class":42,"line":270},11,[40,272,273],{"class":94},"book.close()\n",[10,275,276,279,280,283],{},[37,277,278],{},"default_format_properties"," replaces Calibri 11 in the workbook's base style, so every cell written without a format, every empty cell and every format created with ",[37,281,282],{},"add_format"," starts from Arial 10. The heading format only adds bold and a colour; the font name is inherited. This is the simplest and most complete way to change the default, and it works for the whole file in one line.",[25,285,287],{"id":286},"step-2-the-same-through-pandas","Step 2 — The same through pandas",[10,289,290,291,294],{},"pandas uses XlsxWriter by default when it is installed, and passes writer options through ",[37,292,293],{},"engine_kwargs",":",[30,296,298],{"className":81,"code":297,"language":83,"meta":35,"style":35},"import pandas as pd\n\ndf = pd.DataFrame({\"Region\": [\"North\", \"South\", \"East\"], \"Revenue\": [1200, 950, 1430]})\nwith pd.ExcelWriter(\"branded_pandas.xlsx\", engine=\"xlsxwriter\",\n                    engine_kwargs={\"options\": {\"default_format_properties\": {\"font_name\": \"Arial\", \"font_size\": 10}}}) as xw:\n    df.to_excel(xw, index=False, sheet_name=\"Data\")\nprint(\"written with Arial 10 as the default\")\n",[37,299,300,313,317,366,391,433,458],{"__ignoreMap":35},[40,301,302,304,307,310],{"class":42,"line":43},[40,303,91],{"class":90},[40,305,306],{"class":94}," pandas ",[40,308,309],{"class":90},"as",[40,311,312],{"class":94}," pd\n",[40,314,315],{"class":42,"line":98},[40,316,102],{"emptyLinePlaceholder":101},[40,318,319,322,324,327,329,332,334,336,339,341,344,347,349,351,353,355,358,360,363],{"class":42,"line":105},[40,320,321],{"class":94},"df ",[40,323,111],{"class":90},[40,325,326],{"class":94}," pd.DataFrame({",[40,328,239],{"class":50},[40,330,331],{"class":94},": [",[40,333,260],{"class":50},[40,335,141],{"class":94},[40,337,338],{"class":50},"\"South\"",[40,340,141],{"class":94},[40,342,343],{"class":50},"\"East\"",[40,345,346],{"class":94},"], ",[40,348,244],{"class":50},[40,350,331],{"class":94},[40,352,265],{"class":149},[40,354,141],{"class":94},[40,356,357],{"class":149},"950",[40,359,141],{"class":94},[40,361,362],{"class":149},"1430",[40,364,365],{"class":94},"]})\n",[40,367,368,371,374,377,379,383,385,388],{"class":42,"line":123},[40,369,370],{"class":90},"with",[40,372,373],{"class":94}," pd.ExcelWriter(",[40,375,376],{"class":50},"\"branded_pandas.xlsx\"",[40,378,141],{"class":94},[40,380,382],{"class":381},"sa561","engine",[40,384,111],{"class":90},[40,386,387],{"class":50},"\"xlsxwriter\"",[40,389,390],{"class":94},",\n",[40,392,393,396,398,401,404,406,409,411,413,415,417,419,421,423,425,428,430],{"class":42,"line":156},[40,394,395],{"class":381},"                    engine_kwargs",[40,397,111],{"class":90},[40,399,400],{"class":94},"{",[40,402,403],{"class":50},"\"options\"",[40,405,129],{"class":94},[40,407,408],{"class":50},"\"default_format_properties\"",[40,410,129],{"class":94},[40,412,132],{"class":50},[40,414,135],{"class":94},[40,416,138],{"class":50},[40,418,141],{"class":94},[40,420,144],{"class":50},[40,422,135],{"class":94},[40,424,150],{"class":149},[40,426,427],{"class":94},"}}}) ",[40,429,309],{"class":90},[40,431,432],{"class":94}," xw:\n",[40,434,435,438,441,443,446,448,451,453,456],{"class":42,"line":162},[40,436,437],{"class":94},"    df.to_excel(xw, ",[40,439,440],{"class":381},"index",[40,442,111],{"class":90},[40,444,445],{"class":149},"False",[40,447,141],{"class":94},[40,449,450],{"class":381},"sheet_name",[40,452,111],{"class":90},[40,454,455],{"class":50},"\"Data\"",[40,457,176],{"class":94},[40,459,460,463,466,469],{"class":42,"line":179},[40,461,462],{"class":149},"print",[40,464,465],{"class":94},"(",[40,467,468],{"class":50},"\"written with Arial 10 as the default\"",[40,470,176],{"class":94},[10,472,473,474,477],{},"The data cells and pandas' own bold header both use Arial 10 — the header format pandas creates inherits the default name and size and only adds bold and a border. Column widths that pandas or ",[37,475,476],{},"autofit()"," compute later are based on the characters, so a smaller default font leaves columns slightly wider than needed; adjust widths after changing the font if the layout is tight.",[479,480,488,489,488,493,488,497,488,505,488,515,488,526,488,533,488,539,488,545,488,551,488,555,488,560,488,564,488,569,488,573,488,580,488,584,488,590,488,595,488,599,488,603,488,610,488,613,488,618,488,621,488,626,488,629],"svg",{"viewBox":481,"role":482,"ariaLabelledBy":483,"xmlns":486,"style":487},"4 0 752 233","img",[484,485],"df-libs-t","df-libs-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:752px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[490,491,492],"title",{"id":484},"Changing the default font with XlsxWriter and openpyxl",[494,495,496],"desc",{"id":485},"XlsxWriter has a workbook option, default_format_properties, that changes the base style for all cells and formats. openpyxl has no public option; editing the Normal named style does not change existing cells, so the reliable route is a template whose default font is already set.",[498,499],"rect",{"x":500,"y":501,"width":502,"height":503,"fill":504},"4","0","752","233","#ffffff",[498,506],{"x":507,"y":508,"width":509,"height":510,"rx":511,"fill":512,"stroke":513,"style":514},"20.0","16.0","351.0","201.0","14","#d9f4f1","var(--teal,#0f9488)","stroke-width:2px",[516,517,519],"g",{"transform":518},"translate(182.5,29.0) scale(1.083)",[520,521],"path",{"d":522,"fill":523,"stroke":524,"style":525},"M5 12.5l4.5 4.5L19 7","none","var(--teal-ink,#0b6157)","stroke-width:1.66px;stroke-linecap:round;stroke-linejoin:round",[527,528,532],"text",{"x":529,"y":530,"style":531},"195.5","78.0","font-size:14px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","XlsxWriter",[42,534],{"x1":535,"y1":536,"x2":537,"y2":536,"stroke":513,"style":538},"36.0","91.0","355.0","stroke-width:1px",[527,540,544],{"x":541,"y":542,"style":543},"60.0","111.0","font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:start","default_format_properties option",[516,546,548],{"transform":547},"translate(38.5,99.5) scale(0.625)",[520,549],{"d":522,"fill":523,"stroke":513,"style":550},"stroke-width:2.88px;stroke-linecap:round;stroke-linejoin:round",[527,552,554],{"x":541,"y":553,"style":543},"137.0","new formats inherit the font",[516,556,558],{"transform":557},"translate(38.5,125.5) scale(0.625)",[520,559],{"d":522,"fill":523,"stroke":513,"style":550},[527,561,563],{"x":541,"y":562,"style":543},"163.0","works through pandas engine_kwargs",[516,565,567],{"transform":566},"translate(38.5,151.5) scale(0.625)",[520,568],{"d":522,"fill":523,"stroke":513,"style":550},[527,570,572],{"x":541,"y":571,"style":543},"189.0","new files only",[516,574,576],{"transform":575},"translate(38.5,177.5) scale(0.625)",[520,577],{"d":578,"fill":523,"stroke":579,"style":550},"M12 3.5l9.5 17h-19z M12 10v5 M12 17.8v.4","var(--gold,#b4740a)",[498,581],{"x":582,"y":508,"width":509,"height":510,"rx":511,"fill":583,"stroke":579,"style":514},"389.0","#fdefd8",[516,585,587],{"transform":586},"translate(551.5,29.0) scale(1.083)",[520,588],{"d":578,"fill":523,"stroke":589,"style":525},"var(--gold-ink,#7a4e06)",[527,591,594],{"x":592,"y":530,"style":593},"564.5","font-size:14px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","openpyxl",[42,596],{"x1":597,"y1":536,"x2":598,"y2":536,"stroke":579,"style":538},"405.0","724.0",[527,600,602],{"x":601,"y":542,"style":543},"429.0","no public default-font option",[516,604,606],{"transform":605},"translate(407.5,99.5) scale(0.625)",[520,607],{"d":608,"fill":523,"stroke":609,"style":550},"M6 6l12 12 M18 6L6 18","var(--accent,#f43f8f)",[527,611,612],{"x":601,"y":553,"style":543},"editing Normal style has no effect",[516,614,616],{"transform":615},"translate(407.5,125.5) scale(0.625)",[520,617],{"d":608,"fill":523,"stroke":609,"style":550},[527,619,620],{"x":601,"y":562,"style":543},"inherits the default from a template",[516,622,624],{"transform":623},"translate(407.5,151.5) scale(0.625)",[520,625],{"d":522,"fill":523,"stroke":513,"style":550},[527,627,628],{"x":601,"y":571,"style":543},"set name explicitly on new Font objects",[516,630,632],{"transform":631},"translate(407.5,177.5) scale(0.625)",[520,633],{"d":578,"fill":523,"stroke":579,"style":550},[25,635,637],{"id":636},"step-3-why-changing-the-normal-style-in-openpyxl-does-not-work","Step 3 — Why changing the Normal style in openpyxl does not work",[10,639,640,641,643],{},"openpyxl does expose the workbook's named styles, and changing the font of ",[37,642,16],{}," looks like it should work:",[30,645,647],{"className":81,"code":646,"language":83,"meta":35,"style":35},"from openpyxl import Workbook\nfrom openpyxl.styles import Font\n\nwb = Workbook()\nws = wb.active\nwb._named_styles[\"Normal\"].font = Font(name=\"Arial\", size=10)\nws[\"A1\"] = \"still Calibri?\"\nprint(ws[\"A1\"].font.name, ws[\"A1\"].font.sz)\n",[37,648,649,662,674,678,688,698,732,747],{"__ignoreMap":35},[40,650,651,654,657,659],{"class":42,"line":43},[40,652,653],{"class":90},"from",[40,655,656],{"class":94}," openpyxl ",[40,658,91],{"class":90},[40,660,661],{"class":94}," Workbook\n",[40,663,664,666,669,671],{"class":42,"line":98},[40,665,653],{"class":90},[40,667,668],{"class":94}," openpyxl.styles ",[40,670,91],{"class":90},[40,672,673],{"class":94}," Font\n",[40,675,676],{"class":42,"line":105},[40,677,102],{"emptyLinePlaceholder":101},[40,679,680,683,685],{"class":42,"line":123},[40,681,682],{"class":94},"wb ",[40,684,111],{"class":90},[40,686,687],{"class":94}," Workbook()\n",[40,689,690,693,695],{"class":42,"line":156},[40,691,692],{"class":94},"ws ",[40,694,111],{"class":90},[40,696,697],{"class":94}," wb.active\n",[40,699,700,703,706,709,711,714,717,719,721,723,726,728,730],{"class":42,"line":162},[40,701,702],{"class":94},"wb._named_styles[",[40,704,705],{"class":50},"\"Normal\"",[40,707,708],{"class":94},"].font ",[40,710,111],{"class":90},[40,712,713],{"class":94}," Font(",[40,715,716],{"class":381},"name",[40,718,111],{"class":90},[40,720,138],{"class":50},[40,722,141],{"class":94},[40,724,725],{"class":381},"size",[40,727,111],{"class":90},[40,729,150],{"class":149},[40,731,176],{"class":94},[40,733,734,737,739,742,744],{"class":42,"line":179},[40,735,736],{"class":94},"ws[",[40,738,216],{"class":50},[40,740,741],{"class":94},"] ",[40,743,111],{"class":90},[40,745,746],{"class":50}," \"still Calibri?\"\n",[40,748,749,751,754,756,759,761],{"class":42,"line":210},[40,750,462],{"class":149},[40,752,753],{"class":94},"(ws[",[40,755,216],{"class":50},[40,757,758],{"class":94},"].font.name, ws[",[40,760,216],{"class":50},[40,762,763],{"class":94},"].font.sz)\n",[10,765,766,767,770],{},"The cell still reports Calibri 11. Cells do not look up the Normal style when they are written; they point at the workbook's ",[14,768,769],{},"first font entry",", which openpyxl creates as Calibri 11 and does not change when the named style is edited. The attribute used here is private (the leading underscore says so) and editing it is a dead end either way. openpyxl simply has no supported switch for the base font of a new workbook.",[25,772,774],{"id":773},"step-4-openpyxl-start-from-a-template-with-the-right-default","Step 4 — openpyxl: start from a template with the right default",[10,776,777],{},"The reliable openpyxl route is to start from a workbook whose default font is already right — created once by XlsxWriter, or saved from Excel after changing the Normal style — and let openpyxl inherit it:",[30,779,781],{"className":81,"code":780,"language":83,"meta":35,"style":35},"from openpyxl import load_workbook\nfrom copy import copy\n\ntemplate = xlsxwriter.Workbook(\"arial_template.xlsx\", {\"default_format_properties\": {\"font_name\": \"Arial\", \"font_size\": 10}})\ntemplate.add_worksheet(\"Report\")\ntemplate.close()\n\nwb = load_workbook(\"arial_template.xlsx\")\nws = wb[\"Report\"]\nws[\"A1\"] = \"Inherited default\"\nbase = ws[\"A1\"].font\nws[\"A2\"] = \"Bold, same family\"\nws[\"A2\"].font = Font(name=base.name, sz=base.sz, b=True)\nws[\"A3\"] = \"Bold, family lost\"\nws[\"A3\"].font = Font(b=True)\nwb.save(\"report_from_template.xlsx\")\nfor coord in (\"A1\", \"A2\", \"A3\"):\n    print(coord, ws[coord].font.name, ws[coord].font.sz, ws[coord].font.b)\n",[37,782,783,794,806,810,846,856,861,865,878,892,905,920,935,972,986,1007,1018,1046],{"__ignoreMap":35},[40,784,785,787,789,791],{"class":42,"line":43},[40,786,653],{"class":90},[40,788,656],{"class":94},[40,790,91],{"class":90},[40,792,793],{"class":94}," load_workbook\n",[40,795,796,798,801,803],{"class":42,"line":98},[40,797,653],{"class":90},[40,799,800],{"class":94}," copy ",[40,802,91],{"class":90},[40,804,805],{"class":94}," copy\n",[40,807,808],{"class":42,"line":105},[40,809,102],{"emptyLinePlaceholder":101},[40,811,812,815,817,819,822,825,827,829,831,833,835,837,839,841,843],{"class":42,"line":123},[40,813,814],{"class":94},"template ",[40,816,111],{"class":90},[40,818,114],{"class":94},[40,820,821],{"class":50},"\"arial_template.xlsx\"",[40,823,824],{"class":94},", {",[40,826,408],{"class":50},[40,828,129],{"class":94},[40,830,132],{"class":50},[40,832,135],{"class":94},[40,834,138],{"class":50},[40,836,141],{"class":94},[40,838,144],{"class":50},[40,840,135],{"class":94},[40,842,150],{"class":149},[40,844,845],{"class":94},"}})\n",[40,847,848,851,854],{"class":42,"line":156},[40,849,850],{"class":94},"template.add_worksheet(",[40,852,853],{"class":50},"\"Report\"",[40,855,176],{"class":94},[40,857,858],{"class":42,"line":162},[40,859,860],{"class":94},"template.close()\n",[40,862,863],{"class":42,"line":179},[40,864,102],{"emptyLinePlaceholder":101},[40,866,867,869,871,874,876],{"class":42,"line":210},[40,868,682],{"class":94},[40,870,111],{"class":90},[40,872,873],{"class":94}," load_workbook(",[40,875,821],{"class":50},[40,877,176],{"class":94},[40,879,880,882,884,887,889],{"class":42,"line":227},[40,881,692],{"class":94},[40,883,111],{"class":90},[40,885,886],{"class":94}," wb[",[40,888,853],{"class":50},[40,890,891],{"class":94},"]\n",[40,893,894,896,898,900,902],{"class":42,"line":250},[40,895,736],{"class":94},[40,897,216],{"class":50},[40,899,741],{"class":94},[40,901,111],{"class":90},[40,903,904],{"class":50}," \"Inherited default\"\n",[40,906,907,910,912,915,917],{"class":42,"line":270},[40,908,909],{"class":94},"base ",[40,911,111],{"class":90},[40,913,914],{"class":94}," ws[",[40,916,216],{"class":50},[40,918,919],{"class":94},"].font\n",[40,921,923,925,928,930,932],{"class":42,"line":922},12,[40,924,736],{"class":94},[40,926,927],{"class":50},"\"A2\"",[40,929,741],{"class":94},[40,931,111],{"class":90},[40,933,934],{"class":50}," \"Bold, same family\"\n",[40,936,938,940,942,944,946,948,950,952,955,958,960,963,966,968,970],{"class":42,"line":937},13,[40,939,736],{"class":94},[40,941,927],{"class":50},[40,943,708],{"class":94},[40,945,111],{"class":90},[40,947,713],{"class":94},[40,949,716],{"class":381},[40,951,111],{"class":90},[40,953,954],{"class":94},"base.name, ",[40,956,957],{"class":381},"sz",[40,959,111],{"class":90},[40,961,962],{"class":94},"base.sz, ",[40,964,965],{"class":381},"b",[40,967,111],{"class":90},[40,969,195],{"class":149},[40,971,176],{"class":94},[40,973,975,977,979,981,983],{"class":42,"line":974},14,[40,976,736],{"class":94},[40,978,233],{"class":50},[40,980,741],{"class":94},[40,982,111],{"class":90},[40,984,985],{"class":50}," \"Bold, family lost\"\n",[40,987,989,991,993,995,997,999,1001,1003,1005],{"class":42,"line":988},15,[40,990,736],{"class":94},[40,992,233],{"class":50},[40,994,708],{"class":94},[40,996,111],{"class":90},[40,998,713],{"class":94},[40,1000,965],{"class":381},[40,1002,111],{"class":90},[40,1004,195],{"class":149},[40,1006,176],{"class":94},[40,1008,1010,1013,1016],{"class":42,"line":1009},16,[40,1011,1012],{"class":94},"wb.save(",[40,1014,1015],{"class":50},"\"report_from_template.xlsx\"",[40,1017,176],{"class":94},[40,1019,1021,1024,1027,1030,1033,1035,1037,1039,1041,1043],{"class":42,"line":1020},17,[40,1022,1023],{"class":90},"for",[40,1025,1026],{"class":94}," coord ",[40,1028,1029],{"class":90},"in",[40,1031,1032],{"class":94}," (",[40,1034,216],{"class":50},[40,1036,141],{"class":94},[40,1038,927],{"class":50},[40,1040,141],{"class":94},[40,1042,233],{"class":50},[40,1044,1045],{"class":94},"):\n",[40,1047,1049,1052],{"class":42,"line":1048},18,[40,1050,1051],{"class":149},"    print",[40,1053,1054],{"class":94},"(coord, ws[coord].font.name, ws[coord].font.sz, ws[coord].font.b)\n",[10,1056,1057,1058,1061,1062,1065,1066,1069,1070,1072,1073,23],{},"Cells written into the loaded template report Arial 10 without any styling, because the template's first font entry is Arial 10. The two bold cells show the second trap: ",[37,1059,1060],{},"Font(b=True)"," creates a font with ",[14,1063,1064],{},"no name and no size",", which Excel and LibreOffice fill in from their own fallbacks — not from your default — so the cell renders in a different family. Build new fonts from the base font's name and size, or copy it with changes (",[37,1067,1068],{},"copy(base)"," and then set ",[37,1071,965],{},"), so emphasised cells stay in the house font. Template workflows are covered in ",[19,1074,1076],{"href":1075},"\u002Fautomating-reporting-workflows\u002Fgenerating-excel-reports-from-templates\u002Ffill-excel-template-with-python-openpyxl\u002F","Fill an Excel Template with Python and openpyxl",[479,1078,488,1084,488,1087,488,1090,488,1095,488,1102,488,1106,488,1112,488,1116,488,1120,488,1124,488,1128,488,1132,488,1136,488,1140,488,1144,488,1148,488,1153,488,1158,488,1162,488,1164,488,1167,488,1169,488,1172,488,1174,488,1177,488,1179,488,1182,488,1185,488,1189,488,1191,488,1195,488,1197,488,1200,488,1202,488,1206,488,1208,488,1210,488,1212,488,1215,488,1218,488,1222,488,1224,488,1227,488,1229,488,1232,488,1234,488,1236,488,1238,488,1240,488,1242,488,1245,488,1248,488,1251,488,1253,488,1256,488,1258,488,1261,488,1265,488,1269,488,1271,488,1273,488,1275],{"viewBox":1079,"role":482,"ariaLabelledBy":1080,"xmlns":486,"style":1083},"171 0 417 168",[1081,1082],"df-cells-t","df-cells-d","width:100%;max-width:417px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[490,1085,1086],{"id":1081},"What each cell inherits in the template-based workbook",[494,1088,1089],{"id":1082},"A1 with no styling inherits Arial 10 from the template. A2, bold with the base font's name and size, stays Arial. A3, created with Font(b=True) alone, has no font name and renders in the application's fallback font.",[498,1091],{"x":1092,"y":501,"width":1093,"height":1094,"fill":504},"171","417","168",[498,1096],{"x":1097,"y":508,"width":1098,"height":1099,"rx":501,"fill":1100,"stroke":1101,"style":538},"187.8","32.0","24.0","#e7ebef","var(--line,#cdd5e6)",[498,1103],{"x":1104,"y":508,"width":1105,"height":1099,"rx":501,"fill":1100,"stroke":1101,"style":538},"219.8","44.7",[527,1107,1111],{"x":1108,"y":1109,"style":1110},"242.2","33.0","font-size:11px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","A",[498,1113],{"x":1114,"y":508,"width":1115,"height":1099,"rx":501,"fill":1100,"stroke":1101,"style":538},"264.5","119.6",[527,1117,1119],{"x":1118,"y":1109,"style":1110},"324.3","B",[498,1121],{"x":1122,"y":508,"width":1123,"height":1099,"rx":501,"fill":1100,"stroke":1101,"style":538},"384.1","80.7",[527,1125,1127],{"x":1126,"y":1109,"style":1110},"424.5","C",[498,1129],{"x":1130,"y":508,"width":1131,"height":1099,"rx":501,"fill":1100,"stroke":1101,"style":538},"464.8","59.4",[527,1133,1135],{"x":1134,"y":1109,"style":1110},"494.5","D",[498,1137],{"x":1138,"y":508,"width":1139,"height":1099,"rx":501,"fill":1100,"stroke":1101,"style":538},"524.2","48.0",[527,1141,1143],{"x":1142,"y":1109,"style":1110},"548.2","E",[498,1145],{"x":1097,"y":1146,"width":1098,"height":1147,"rx":501,"fill":1100,"stroke":1101,"style":538},"40.0","28.0",[527,1149,1152],{"x":1150,"y":1151,"style":1110},"203.8","59.0","1",[498,1154],{"x":1104,"y":1146,"width":1105,"height":1147,"rx":501,"fill":1155,"stroke":1156,"style":1157},"#f0f4ff","var(--brand,#5b5cf0)","stroke-width:1.5px",[527,1159,1161],{"x":1108,"y":1151,"style":1160},"font-size:10.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Cell",[498,1163],{"x":1114,"y":1146,"width":1115,"height":1147,"rx":501,"fill":1155,"stroke":1156,"style":1157},[527,1165,1166],{"x":1118,"y":1151,"style":1160},"Text",[498,1168],{"x":1122,"y":1146,"width":1123,"height":1147,"rx":501,"fill":1155,"stroke":1156,"style":1157},[527,1170,1171],{"x":1126,"y":1151,"style":1160},"Font name",[498,1173],{"x":1130,"y":1146,"width":1131,"height":1147,"rx":501,"fill":1155,"stroke":1156,"style":1157},[527,1175,1176],{"x":1134,"y":1151,"style":1160},"Size",[498,1178],{"x":1138,"y":1146,"width":1139,"height":1147,"rx":501,"fill":1155,"stroke":1156,"style":1157},[527,1180,1181],{"x":1142,"y":1151,"style":1160},"Bold",[498,1183],{"x":1097,"y":1184,"width":1098,"height":1147,"rx":501,"fill":1100,"stroke":1101,"style":538},"68.0",[527,1186,1188],{"x":1150,"y":1187,"style":1110},"87.0","2",[498,1190],{"x":1104,"y":1184,"width":1105,"height":1147,"rx":501,"fill":504,"stroke":1101,"style":538},[527,1192,1194],{"x":1108,"y":1187,"style":1193},"font-size:10.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","A1",[498,1196],{"x":1114,"y":1184,"width":1115,"height":1147,"rx":501,"fill":504,"stroke":1101,"style":538},[527,1198,1199],{"x":1118,"y":1187,"style":1193},"Inherited default",[498,1201],{"x":1122,"y":1184,"width":1123,"height":1147,"rx":501,"fill":512,"stroke":513,"style":1157},[527,1203,1205],{"x":1126,"y":1187,"style":1204},"font-size:10.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Arial",[498,1207],{"x":1130,"y":1184,"width":1131,"height":1147,"rx":501,"fill":504,"stroke":1101,"style":538},[527,1209,150],{"x":1134,"y":1187,"style":1193},[498,1211],{"x":1138,"y":1184,"width":1139,"height":1147,"rx":501,"fill":504,"stroke":1101,"style":538},[527,1213,1214],{"x":1142,"y":1187,"style":1193},"no",[498,1216],{"x":1097,"y":1217,"width":1098,"height":1147,"rx":501,"fill":1100,"stroke":1101,"style":538},"96.0",[527,1219,1221],{"x":1150,"y":1220,"style":1110},"115.0","3",[498,1223],{"x":1104,"y":1217,"width":1105,"height":1147,"rx":501,"fill":504,"stroke":1101,"style":538},[527,1225,1226],{"x":1108,"y":1220,"style":1193},"A2",[498,1228],{"x":1114,"y":1217,"width":1115,"height":1147,"rx":501,"fill":504,"stroke":1101,"style":538},[527,1230,1231],{"x":1118,"y":1220,"style":1193},"Bold, same family",[498,1233],{"x":1122,"y":1217,"width":1123,"height":1147,"rx":501,"fill":512,"stroke":513,"style":1157},[527,1235,1205],{"x":1126,"y":1220,"style":1204},[498,1237],{"x":1130,"y":1217,"width":1131,"height":1147,"rx":501,"fill":504,"stroke":1101,"style":538},[527,1239,150],{"x":1134,"y":1220,"style":1193},[498,1241],{"x":1138,"y":1217,"width":1139,"height":1147,"rx":501,"fill":504,"stroke":1101,"style":538},[527,1243,1244],{"x":1142,"y":1220,"style":1193},"yes",[498,1246],{"x":1097,"y":1247,"width":1098,"height":1147,"rx":501,"fill":1100,"stroke":1101,"style":538},"124.0",[527,1249,500],{"x":1150,"y":1250,"style":1110},"143.0",[498,1252],{"x":1104,"y":1247,"width":1105,"height":1147,"rx":501,"fill":504,"stroke":1101,"style":538},[527,1254,1255],{"x":1108,"y":1250,"style":1193},"A3",[498,1257],{"x":1114,"y":1247,"width":1115,"height":1147,"rx":501,"fill":504,"stroke":1101,"style":538},[527,1259,1260],{"x":1118,"y":1250,"style":1193},"Bold, family lost",[498,1262],{"x":1122,"y":1247,"width":1123,"height":1147,"rx":501,"fill":1263,"stroke":1264,"style":1157},"#fce9e9","var(--danger,#dc2626)",[527,1266,1268],{"x":1126,"y":1250,"style":1267},"font-size:10.5px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","(none)",[498,1270],{"x":1130,"y":1247,"width":1131,"height":1147,"rx":501,"fill":1263,"stroke":1264,"style":1157},[527,1272,1268],{"x":1134,"y":1250,"style":1267},[498,1274],{"x":1138,"y":1247,"width":1139,"height":1147,"rx":501,"fill":504,"stroke":1101,"style":538},[527,1276,1244],{"x":1142,"y":1250,"style":1193},[25,1278,1280],{"id":1279},"step-5-check-the-fonts-that-actually-render","Step 5 — Check the fonts that actually render",[10,1282,1283,1284,1287,1288,1291],{},"What a cell ",[14,1285,1286],{},"says"," its font is and what a reader ",[14,1289,1290],{},"sees"," can differ — fonts missing on the reader's machine are substituted. Rendering to PDF and listing the embedded fonts shows the truth:",[30,1293,1295],{"className":81,"code":1294,"language":83,"meta":35,"style":35},"import subprocess\n\nfor name in (\"branded.xlsx\", \"report_from_template.xlsx\"):\n    subprocess.run([\"soffice\", \"--headless\", \"--convert-to\", \"pdf\", name], check=True, capture_output=True)\n    fonts = subprocess.run([\"pdffonts\", name.replace(\".xlsx\", \".pdf\")], capture_output=True, text=True).stdout\n    used = sorted({line.split()[0].split(\"+\")[-1] for line in fonts.splitlines()[2:] if line.strip()})\n    print(f\"{name:28} {used}\")\n",[37,1296,1297,1304,1308,1327,1371,1415,1467],{"__ignoreMap":35},[40,1298,1299,1301],{"class":42,"line":43},[40,1300,91],{"class":90},[40,1302,1303],{"class":94}," subprocess\n",[40,1305,1306],{"class":42,"line":98},[40,1307,102],{"emptyLinePlaceholder":101},[40,1309,1310,1312,1315,1317,1319,1321,1323,1325],{"class":42,"line":105},[40,1311,1023],{"class":90},[40,1313,1314],{"class":94}," name ",[40,1316,1029],{"class":90},[40,1318,1032],{"class":94},[40,1320,117],{"class":50},[40,1322,141],{"class":94},[40,1324,1015],{"class":50},[40,1326,1045],{"class":94},[40,1328,1329,1332,1335,1337,1340,1342,1345,1347,1350,1353,1356,1358,1360,1362,1365,1367,1369],{"class":42,"line":123},[40,1330,1331],{"class":94},"    subprocess.run([",[40,1333,1334],{"class":50},"\"soffice\"",[40,1336,141],{"class":94},[40,1338,1339],{"class":50},"\"--headless\"",[40,1341,141],{"class":94},[40,1343,1344],{"class":50},"\"--convert-to\"",[40,1346,141],{"class":94},[40,1348,1349],{"class":50},"\"pdf\"",[40,1351,1352],{"class":94},", name], ",[40,1354,1355],{"class":381},"check",[40,1357,111],{"class":90},[40,1359,195],{"class":149},[40,1361,141],{"class":94},[40,1363,1364],{"class":381},"capture_output",[40,1366,111],{"class":90},[40,1368,195],{"class":149},[40,1370,176],{"class":94},[40,1372,1373,1376,1378,1381,1384,1387,1390,1392,1395,1398,1400,1402,1404,1406,1408,1410,1412],{"class":42,"line":156},[40,1374,1375],{"class":94},"    fonts ",[40,1377,111],{"class":90},[40,1379,1380],{"class":94}," subprocess.run([",[40,1382,1383],{"class":50},"\"pdffonts\"",[40,1385,1386],{"class":94},", name.replace(",[40,1388,1389],{"class":50},"\".xlsx\"",[40,1391,141],{"class":94},[40,1393,1394],{"class":50},"\".pdf\"",[40,1396,1397],{"class":94},")], ",[40,1399,1364],{"class":381},[40,1401,111],{"class":90},[40,1403,195],{"class":149},[40,1405,141],{"class":94},[40,1407,527],{"class":381},[40,1409,111],{"class":90},[40,1411,195],{"class":149},[40,1413,1414],{"class":94},").stdout\n",[40,1416,1417,1420,1422,1425,1428,1430,1433,1436,1439,1442,1444,1446,1448,1451,1453,1456,1458,1461,1464],{"class":42,"line":162},[40,1418,1419],{"class":94},"    used ",[40,1421,111],{"class":90},[40,1423,1424],{"class":149}," sorted",[40,1426,1427],{"class":94},"({line.split()[",[40,1429,501],{"class":149},[40,1431,1432],{"class":94},"].split(",[40,1434,1435],{"class":50},"\"+\"",[40,1437,1438],{"class":94},")[",[40,1440,1441],{"class":90},"-",[40,1443,1152],{"class":149},[40,1445,741],{"class":94},[40,1447,1023],{"class":90},[40,1449,1450],{"class":94}," line ",[40,1452,1029],{"class":90},[40,1454,1455],{"class":94}," fonts.splitlines()[",[40,1457,1188],{"class":149},[40,1459,1460],{"class":94},":] ",[40,1462,1463],{"class":90},"if",[40,1465,1466],{"class":94}," line.strip()})\n",[40,1468,1469,1471,1473,1476,1479,1482,1484,1487,1490,1493,1496,1498,1500],{"class":42,"line":179},[40,1470,1051],{"class":149},[40,1472,465],{"class":94},[40,1474,1475],{"class":90},"f",[40,1477,1478],{"class":50},"\"",[40,1480,400],{"class":1481},"sSjpA",[40,1483,716],{"class":94},[40,1485,1486],{"class":90},":28",[40,1488,1489],{"class":1481},"}",[40,1491,1492],{"class":1481}," {",[40,1494,1495],{"class":94},"used",[40,1497,1489],{"class":1481},[40,1499,1478],{"class":50},[40,1501,176],{"class":94},[10,1503,1504,1505,1508,1509,1512,1513,1515],{},"On this Linux machine, Arial is not installed, so LibreOffice substitutes ",[14,1506,1507],{},"Liberation Sans",", a metric-compatible replacement — text takes exactly the same width, and the file still says Arial, so it renders in real Arial for Windows and Mac readers. The template-based report shows a second family as well: ",[14,1510,1511],{},"Caladea",", a serif font, appears for the cell created with ",[37,1514,1060],{}," — with no name of its own, the cell fell back to LibreOffice's default for the file, which is the problem Step 4 warned about, now visible in the output. In Excel the same cell would fall back to the application default, again not your house font. Checking the font list in a test catches that kind of slip before a branded report goes out.",[479,1517,488,1522,488,1525,488,1528,488,1531,488,1536,488,1544,488,1550,488,1555,488,1560,488,1565,488,1568,488,1575,488,1580,488,1583,488,1587,488,1590,488,1593,488,1599,488,1604],{"viewBox":1518,"role":482,"ariaLabelledBy":1519,"xmlns":486,"style":487},"4 0 752 125",[1520,1521],"df-check-t","df-check-d",[490,1523,1524],{"id":1520},"From the font a cell names to the font a reader sees",[494,1526,1527],{"id":1521},"A cell names a font such as Arial. When the file is opened, the application looks for that font; if it is missing, it substitutes a metric-compatible one such as Liberation Sans. A cell without a font name gets the application's own fallback, which may be a different family.",[498,1529],{"x":500,"y":501,"width":502,"height":1530,"fill":504},"125",[498,1532],{"x":507,"y":508,"width":1533,"height":1534,"rx":1535,"fill":1100,"stroke":1101,"style":514},"216.0","93.0","12",[516,1537,1539],{"transform":1538},"translate(116.0,29.0) scale(1.000)",[520,1540],{"d":1541,"fill":523,"stroke":1542,"style":1543},"M4 4h16v16H4z M4 9h16 M4 14h16 M10 4v16","var(--text,#172033)","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[527,1545,1549],{"x":1546,"y":1547,"style":1548},"128.0","75.5","font-size:13.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Cell font name",[527,1551,1554],{"x":1546,"y":1552,"style":1553},"95.0","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","Arial (or none)",[42,1556],{"x1":1557,"y1":1558,"x2":1559,"y2":1558,"stroke":1156,"style":514},"241.0","62.5","263.0",[1561,1562],"polygon",{"points":1563,"fill":1564},"267.0,62.5 258.0,67.5 258.0,57.5","#5b5cf0",[498,1566],{"x":1567,"y":508,"width":1533,"height":1534,"rx":1535,"fill":1155,"stroke":1156,"style":514},"272.0",[516,1569,1571],{"transform":1570},"translate(368.0,29.0) scale(1.000)",[520,1572],{"d":1573,"fill":523,"stroke":1574,"style":1543},"M11 4a7 7 0 1 0 .01 0z M16 16l5 5","var(--brand-strong,#4338ca)",[527,1576,1579],{"x":1577,"y":1547,"style":1578},"380.0","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Font installed?",[527,1581,1582],{"x":1577,"y":1552,"style":1553},"on the reader's machine",[42,1584],{"x1":1585,"y1":1558,"x2":1586,"y2":1558,"stroke":1156,"style":514},"493.0","515.0",[1561,1588],{"points":1589,"fill":1564},"519.0,62.5 510.0,67.5 510.0,57.5",[498,1591],{"x":1592,"y":508,"width":1533,"height":1534,"rx":1535,"fill":512,"stroke":513,"style":514},"524.0",[516,1594,1596],{"transform":1595},"translate(620.0,29.0) scale(1.000)",[520,1597],{"d":1598,"fill":523,"stroke":524,"style":1543},"M2 12s4-7 10-7 10 7 10 7-4 7-10 7S2 12 2 12z M12 9a3 3 0 1 0 .01 0z",[527,1600,1603],{"x":1601,"y":1547,"style":1602},"632.0","font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Rendered font",[527,1605,1606],{"x":1601,"y":1552,"style":1553},"Arial · Liberation Sans · fallback",[25,1608,1610],{"id":1609},"step-6-fonts-for-charts-comments-and-headers","Step 6 — Fonts for charts, comments and headers",[10,1612,1613,1614,1617,1618,1621,1622,1625,1626,1629,1630,23],{},"The default font covers cells. Other parts of a workbook have their own settings: chart text in XlsxWriter is set per chart (",[37,1615,1616],{},"chart.set_title({\"name_font\": {\"name\": \"Arial\"}})"," and the axis ",[37,1619,1620],{},"num_font"," and ",[37,1623,1624],{},"name_font"," options), page headers and footers take a font code such as ",[37,1627,1628],{},"&\"Arial,Bold\"",", and cell comments use Excel's own comment font. If brand rules cover the whole document, set those explicitly too. Number formats and column widths are independent of the font name, but a different font size changes how many characters fit in a column; see ",[19,1631,1633],{"href":1632},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fset-column-width-and-row-height-in-openpyxl\u002F","Set Column Width and Row Height in openpyxl",[25,1635,1637],{"id":1636},"performance-notes","Performance notes",[10,1639,1640],{},"Changing the default font costs nothing at write time: it is one entry in the styles part. It even saves work compared with styling every cell, because each explicitly styled cell needs a style record, while unstyled cells share the default. The template approach adds one small file read per run. The PDF font check takes a couple of seconds for the LibreOffice conversion, so keep it in tests rather than in every production run.",[25,1642,1644],{"id":1643},"common-pitfalls","Common pitfalls",[1646,1647,1648,1656,1664,1670,1676],"ul",{},[1649,1650,1651,1655],"li",{},[1652,1653,1654],"strong",{},"Editing openpyxl's Normal style."," It does not change the font cells use; start from a template instead.",[1649,1657,1658,1663],{},[1652,1659,1660,1662],{},[37,1661,1060],{}," without a name."," The cell falls back to the application's font; pass the base name and size.",[1649,1665,1666,1669],{},[1652,1667,1668],{},"Styling only the cells you write."," Empty cells and later additions keep Calibri; change the default instead.",[1649,1671,1672,1675],{},[1652,1673,1674],{},"Assuming the reader has the font."," Unusual fonts are substituted; prefer widely installed fonts or embed a check.",[1649,1677,1678,1681],{},[1652,1679,1680],{},"Forgetting charts and headers."," They do not follow the cell default.",[25,1683,1685],{"id":1684},"conclusion","Conclusion",[10,1687,1688,1689,1691,1692,1694,1695,1697],{},"With XlsxWriter, set ",[37,1690,278],{}," when creating the workbook — directly or through pandas' ",[37,1693,293],{}," — and every cell and format inherits the font. openpyxl has no public option and ignores edits to the Normal style for cell fonts, so start from a template whose default font is already right, and create emphasised fonts from the base name and size rather than ",[37,1696,1060],{}," alone. Render a PDF and list its fonts to confirm what readers will see.",[25,1699,1701],{"id":1700},"frequently-asked-questions","Frequently asked questions",[10,1703,1704,1707],{},[1652,1705,1706],{},"How do I change the default font in an Excel file created with Python?","\nWith XlsxWriter, pass {\"default_format_properties\": {\"font_name\": \"Arial\", \"font_size\": 10}} as the Workbook options. Every cell and every format created afterwards uses that font unless it sets its own.",[10,1709,1710,1713],{},[1652,1711,1712],{},"How do I set the default font when writing Excel with pandas?","\nUse the xlsxwriter engine and pass engine_kwargs={\"options\": {\"default_format_properties\": {\"font_name\": \"Arial\", \"font_size\": 10}}} to pd.ExcelWriter. pandas' header format inherits the font too.",[10,1715,1716,1719],{},[1652,1717,1718],{},"Why doesn't changing the Normal style font in openpyxl work?","\nCells reference the workbook's first font entry directly, and openpyxl does not update it when the Normal named style changes. Start from a template workbook whose default font is already set instead.",[10,1721,1722,1725],{},[1652,1723,1724],{},"Why does my bold cell use a different font after changing the default?","\nIt was styled with Font(b=True), which creates a font without a name or size, so the application substitutes its own fallback. Create the bold font with the default's name and size.",[25,1727,1729],{"id":1728},"related","Related",[1646,1731,1732,1738,1745,1752],{},[1649,1733,1734,1735,1737],{},"Up one level: ",[19,1736,22],{"href":21}," — fonts, fills and alignment.",[1649,1739,1740,1744],{},[19,1741,1743],{"href":1742},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fapply-a-reusable-style-theme-across-an-excel-report\u002F","Apply a Reusable Style Theme Across an Excel Report"," — consistent styles beyond the font.",[1649,1746,1747,1751],{},[19,1748,1750],{"href":1749},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fwrite-a-formatted-excel-report-with-xlsxwriter\u002F","Write a Formatted Excel Report with XlsxWriter"," — formats built on the default.",[1649,1753,1754,1758],{},[19,1755,1757],{"href":1756},"\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Fsave-a-workbook-as-an-excel-template-with-python\u002F","Save a Workbook as an Excel Template with Python"," — keeping the default in a template.",[1760,1761,1762],"style",{},"html pre.shiki code .sMTad, html code.shiki .sMTad{--shiki-default:#6F42C1;--shiki-dark:#FFB757}html pre.shiki code .srMev, html code.shiki .srMev{--shiki-default:#032F62;--shiki-dark:#ADDCFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s-kum, html code.shiki .s-kum{--shiki-default:#D73A49;--shiki-dark:#FF9492}html pre.shiki code .skGVy, html code.shiki .skGVy{--shiki-default:#24292E;--shiki-dark:#F0F3F6}html pre.shiki code .sP0c6, html code.shiki .sP0c6{--shiki-default:#005CC5;--shiki-dark:#91CBFF}html pre.shiki code .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html pre.shiki code .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}",{"title":35,"searchDepth":98,"depth":98,"links":1764},[1765,1766,1767,1768,1769,1770,1771,1772,1773,1774,1775,1776],{"id":27,"depth":98,"text":28},{"id":74,"depth":98,"text":75},{"id":286,"depth":98,"text":287},{"id":636,"depth":98,"text":637},{"id":773,"depth":98,"text":774},{"id":1279,"depth":98,"text":1280},{"id":1609,"depth":98,"text":1610},{"id":1636,"depth":98,"text":1637},{"id":1643,"depth":98,"text":1644},{"id":1684,"depth":98,"text":1685},{"id":1700,"depth":98,"text":1701},{"id":1728,"depth":98,"text":1729},"2026-10-02","Make a generated workbook use your house font everywhere — not just in the cells you styled: set XlsxWriter's default_format_properties (also through pandas), understand why changing the Normal style in openpyxl does nothing to existing cells, use a template so openpyxl inherits the right default, keep bold and coloured cells in the same family, and verify the fonts that actually render.","md",[1781,1783,1785,1787],{"q":1706,"a":1782},"With XlsxWriter, pass {\"default_format_properties\": {\"font_name\": \"Arial\", \"font_size\": 10}} as the Workbook options. Every cell and every format created afterwards uses that font unless it sets its own.",{"q":1712,"a":1784},"Use the xlsxwriter engine and pass engine_kwargs={\"options\": {\"default_format_properties\": {\"font_name\": \"Arial\", \"font_size\": 10}}} to pd.ExcelWriter. pandas' header format inherits the font too.",{"q":1718,"a":1786},"Cells reference the workbook's first font entry directly, and openpyxl does not update it when the Normal named style changes. Start from a template workbook whose default font is already set instead.",{"q":1724,"a":1788},"It was styled with Font(b=True), which creates a font without a name or size, so the application substitutes its own fallback. Create the bold font with the default's name and size.","change the default font of an excel workbook with python",null,{"breadcrumb":1792},[1793,1796,1799],{"name":1794,"item":1795},"Home","\u002F",{"name":1797,"item":1798},"Formatting and Charting Excel Reports with Python","\u002Fformatting-and-charting-excel-reports-with-python\u002F",{"name":22,"item":21},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fchange-the-default-font-of-an-excel-workbook-with-python",{"title":5,"description":1802},"Set a workbook-wide default font from Python: XlsxWriter default_format_properties and pandas engine_kwargs, why openpyxl Normal-style edits do not apply, the template approach, Font(bold=True) losing the font name, and checking rendered fonts with pdffonts.","change-the-default-font-of-an-excel-workbook-with-python","formatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fchange-the-default-font-of-an-excel-workbook-with-python\u002Findex",[1806,594,1807],"cell-styling","xlsxwriter","how-to","qljAr-ZfRHcKBWjYAJN1adW3jb1ZCcM3a6k_0z_V-A4",[1811,1815],{"title":1812,"path":1813,"stem":1814,"children":-1},"Build a Calendar Sheet in Excel with Python","\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fbuild-a-calendar-sheet-in-excel-with-python","formatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fbuild-a-calendar-sheet-in-excel-with-python\u002Findex",{"title":1816,"path":1817,"stem":1818,"children":-1},"Freeze the Header Row in Excel with openpyxl","\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Ffreeze-header-row-in-excel-with-openpyxl","formatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Ffreeze-header-row-in-excel-with-openpyxl\u002Findex",[1820,1822],{"path":1821,"title":1797},"\u002Fformatting-and-charting-excel-reports-with-python",{"path":1823,"title":22},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl",[],[1826,1829,1832,1835,1838,1841],{"path":1827,"title":1828,"kind":1808},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fwrite-rich-text-in-a-cell-with-xlsxwriter","Write Rich Text with Mixed Formats in One Cell with xlsxwriter",{"path":1830,"title":1831,"kind":1808},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fcopy-cell-styles-with-openpyxl","Copy Cell Styles from One Cell to Another with openpyxl",{"path":1833,"title":1834,"kind":1808},"\u002Fgetting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas\u002Fauto-fit-column-widths-when-writing-with-pandas","Auto-Fit Column Widths When Writing with pandas",{"path":1836,"title":1837,"kind":1808},"\u002Fgetting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas\u002Fexport-a-styled-pandas-dataframe-to-excel","Export a Styled pandas DataFrame to Excel",{"path":1839,"title":1840,"kind":1808},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fgenerate-a-staff-rota-in-excel-with-python","Generate a Staff Rota in Excel with Python",{"path":1842,"title":1843,"kind":1808},"\u002Fautomating-reporting-workflows\u002Fbuilding-multi-sheet-excel-dashboards\u002Fadd-a-table-of-contents-sheet-with-hyperlinks-in-excel","Add a Table of Contents Sheet with Hyperlinks in Excel",1790972117263]