[{"data":1,"prerenderedAt":1615},["ShallowReactive",2],{"doc:\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fset-print-area-and-page-setup-with-openpyxl":3,"surround:\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fset-print-area-and-page-setup-with-openpyxl":1606},{"id":4,"title":5,"body":6,"dateModified":1583,"datePublished":1583,"description":1584,"extension":1585,"faq":1586,"meta":1597,"navigation":221,"path":1598,"seo":1599,"slug":1602,"stem":1603,"type":1604,"__hash__":1605},"docs\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fset-print-area-and-page-setup-with-openpyxl\u002Findex.md","Set the Print Area and Page Setup with openpyxl",{"type":7,"value":8,"toc":1566},"minimark",[9,19,152,157,182,186,193,338,345,349,352,443,450,454,485,491,554,558,561,666,697,701,760,763,767,770,836,839,843,846,1083,1090,1094,1097,1264,1271,1278,1327,1331,1334,1364,1371,1378,1382,1433,1437,1455,1459,1462,1466,1479,1499,1505,1511,1525,1529,1562],[10,11,12,13,18],"p",{},"A generated workbook that looks right on screen can print as fourteen pages of orphaned columns, and nobody discovers that until someone in the meeting tries. openpyxl exposes the whole page-setup surface — print area, orientation, scaling, repeated headers, margins, headers and footers — and setting it takes about ten lines. The same settings govern PDF export, which is where most generated reports actually end up. This guide configures a sheet for printing properly. It belongs to ",[14,15,17],"a",{"href":16},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002F","Styling Excel Cells with openpyxl",".",[20,21,29,30,29,34,29,38,29,45,29,52,29,57,29,65,29,73,29,79,29,83,29,86,29,90,29,93,29,96,29,100,29,103,29,107,29,112,29,120,29,126,29,131,29,135,29,138,29,141,29,144,29,146,29,149],"svg",{"viewBox":22,"role":23,"ariaLabelledBy":24,"xmlns":27,"style":28},"0 0 760 232","img",[25,26],"pr-t","pr-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:760px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[31,32,33],"title",{"id":25},"The same sheet printed with and without page setup",[35,36,37],"desc",{"id":26},"Without configuration the columns overflow onto separate pages with no repeated header, while fit-to-width, landscape orientation and repeated title rows produce readable pages.",[39,40],"rect",{"x":41,"y":41,"width":42,"height":43,"fill":44},"0","760","232","#ffffff",[46,47,51],"text",{"x":48,"y":49,"style":50},"196","28","font-size:12.5px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","default settings",[46,53,56],{"x":54,"y":49,"style":55},"566","font-size:12.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","configured",[58,59],"line",{"x1":60,"y1":61,"x2":60,"y2":62,"stroke":63,"style":64},"380","40","214","var(--line,#cdd5e6)","stroke-width:1px",[39,66],{"x":67,"y":68,"width":69,"height":70,"rx":71,"fill":72,"stroke":63},"44","48","90","120","6","#fee8f2",[46,74,78],{"x":75,"y":76,"style":77},"89","104","font-size:11px;fill:var(--accent-ink,#be185d);text-anchor:middle","cols A–D",[46,80,82],{"x":75,"y":81,"style":77},"124","page 1",[39,84],{"x":85,"y":68,"width":69,"height":70,"rx":71,"fill":72,"stroke":63},"144",[46,87,89],{"x":88,"y":76,"style":77},"189","cols E–F",[46,91,92],{"x":88,"y":81,"style":77},"no header",[39,94],{"x":95,"y":68,"width":69,"height":70,"rx":71,"fill":72,"stroke":63},"244",[46,97,99],{"x":98,"y":76,"style":77},"289","col G",[46,101,102],{"x":98,"y":81,"style":77},"orphaned",[46,104,106],{"x":48,"y":48,"style":105},"font-size:11.5px;fill:var(--muted,#5b6780);text-anchor:middle","three pages wide, unreadable",[39,108],{"x":109,"y":68,"width":110,"height":70,"rx":71,"fill":111,"stroke":63},"416","146","#d9f4f1",[39,113],{"x":114,"y":115,"width":116,"height":117,"rx":118,"fill":119},"424","56","130","18","3","#0b6157",[46,121,125],{"x":122,"y":123,"style":124},"489","70","font-size:10.5px;fill:#ffffff;text-anchor:middle","repeated header",[46,127,130],{"x":122,"y":128,"style":129},"112","font-size:11px;fill:var(--teal-ink,#0b6157);text-anchor:middle","all columns",[46,132,134],{"x":122,"y":133,"style":129},"134","page 1 of 2",[39,136],{"x":137,"y":68,"width":110,"height":70,"rx":71,"fill":111,"stroke":63},"572",[39,139],{"x":140,"y":115,"width":116,"height":117,"rx":118,"fill":119},"580",[46,142,125],{"x":143,"y":123,"style":124},"645",[46,145,130],{"x":143,"y":128,"style":129},[46,147,148],{"x":143,"y":133,"style":129},"page 2 of 2",[46,150,151],{"x":54,"y":48,"style":105},"one page wide, two pages long",[153,154,156],"h2",{"id":155},"prerequisites","Prerequisites",[158,159,164],"pre",{"className":160,"code":161,"language":162,"meta":163,"style":163},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install openpyxl\n","bash","",[165,166,167],"code",{"__ignoreMap":163},[168,169,171,175,179],"span",{"class":58,"line":170},1,[168,172,174],{"class":173},"sMTad","pip",[168,176,178],{"class":177},"srMev"," install",[168,180,181],{"class":177}," openpyxl\n",[153,183,185],{"id":184},"set-the-print-area","Set the print area",[10,187,188,189,192],{},"Without one, Excel prints everything it considers used — including a stray value someone left in ",[165,190,191],{},"AZ900",":",[158,194,198],{"className":195,"code":196,"language":197,"meta":163,"style":163},"language-python shiki shiki-themes github-light github-dark-high-contrast","from openpyxl import load_workbook\n\nwb = load_workbook(\"report.xlsx\")\nws = wb[\"Summary\"]\n\nlast_col = ws.cell(row=1, column=ws.max_column).column_letter\nws.print_area = f\"A1:{last_col}{ws.max_row}\"\nwb.save(\"report.xlsx\")\n","python",[165,199,200,216,223,241,258,263,295,328],{"__ignoreMap":163},[168,201,202,206,210,213],{"class":58,"line":170},[168,203,205],{"class":204},"s-kum","from",[168,207,209],{"class":208},"skGVy"," openpyxl ",[168,211,212],{"class":204},"import",[168,214,215],{"class":208}," load_workbook\n",[168,217,219],{"class":58,"line":218},2,[168,220,222],{"emptyLinePlaceholder":221},true,"\n",[168,224,226,229,232,235,238],{"class":58,"line":225},3,[168,227,228],{"class":208},"wb ",[168,230,231],{"class":204},"=",[168,233,234],{"class":208}," load_workbook(",[168,236,237],{"class":177},"\"report.xlsx\"",[168,239,240],{"class":208},")\n",[168,242,244,247,249,252,255],{"class":58,"line":243},4,[168,245,246],{"class":208},"ws ",[168,248,231],{"class":204},[168,250,251],{"class":208}," wb[",[168,253,254],{"class":177},"\"Summary\"",[168,256,257],{"class":208},"]\n",[168,259,261],{"class":58,"line":260},5,[168,262,222],{"emptyLinePlaceholder":221},[168,264,266,269,271,274,278,280,284,287,290,292],{"class":58,"line":265},6,[168,267,268],{"class":208},"last_col ",[168,270,231],{"class":204},[168,272,273],{"class":208}," ws.cell(",[168,275,277],{"class":276},"sa561","row",[168,279,231],{"class":204},[168,281,283],{"class":282},"sP0c6","1",[168,285,286],{"class":208},", ",[168,288,289],{"class":276},"column",[168,291,231],{"class":204},[168,293,294],{"class":208},"ws.max_column).column_letter\n",[168,296,298,301,303,306,309,313,316,319,322,325],{"class":58,"line":297},7,[168,299,300],{"class":208},"ws.print_area ",[168,302,231],{"class":204},[168,304,305],{"class":204}," f",[168,307,308],{"class":177},"\"A1:",[168,310,312],{"class":311},"sSjpA","{",[168,314,315],{"class":208},"last_col",[168,317,318],{"class":311},"}{",[168,320,321],{"class":208},"ws.max_row",[168,323,324],{"class":311},"}",[168,326,327],{"class":177},"\"\n",[168,329,331,334,336],{"class":58,"line":330},8,[168,332,333],{"class":208},"wb.save(",[168,335,237],{"class":177},[168,337,240],{"class":208},[10,339,340,341,344],{},"Computing the range from the data rather than hardcoding it means the setting stays correct as the report grows. For several blocks, assign a list — ",[165,342,343],{},"ws.print_area = [\"A1:F20\", \"A30:F60\"]"," — and each prints as its own page.",[153,346,348],{"id":347},"orientation-paper-and-fit-to-width","Orientation, paper and fit to width",[10,350,351],{},"The single most valuable setting is fit-to-width: it scales the sheet so no column is orphaned, while letting the rows flow over as many pages as they need.",[158,353,355],{"className":195,"code":354,"language":197,"meta":163,"style":163},"from openpyxl.worksheet.properties import PageSetupProperties\n\nws.page_setup.orientation = \"landscape\"        # 'portrait' is the default\nws.page_setup.paperSize = ws.PAPERSIZE_A4\nws.page_setup.fitToWidth = 1\nws.page_setup.fitToHeight = 0                  # 0 = as many pages as needed\nws.sheet_properties.pageSetUpPr = PageSetupProperties(fitToPage=True)\n",[165,356,357,369,373,387,400,410,423],{"__ignoreMap":163},[168,358,359,361,364,366],{"class":58,"line":170},[168,360,205],{"class":204},[168,362,363],{"class":208}," openpyxl.worksheet.properties ",[168,365,212],{"class":204},[168,367,368],{"class":208}," PageSetupProperties\n",[168,370,371],{"class":58,"line":218},[168,372,222],{"emptyLinePlaceholder":221},[168,374,375,378,380,383],{"class":58,"line":225},[168,376,377],{"class":208},"ws.page_setup.orientation ",[168,379,231],{"class":204},[168,381,382],{"class":177}," \"landscape\"",[168,384,386],{"class":385},"s-wDw","        # 'portrait' is the default\n",[168,388,389,392,394,397],{"class":58,"line":243},[168,390,391],{"class":208},"ws.page_setup.paperSize ",[168,393,231],{"class":204},[168,395,396],{"class":208}," ws.",[168,398,399],{"class":282},"PAPERSIZE_A4\n",[168,401,402,405,407],{"class":58,"line":260},[168,403,404],{"class":208},"ws.page_setup.fitToWidth ",[168,406,231],{"class":204},[168,408,409],{"class":282}," 1\n",[168,411,412,415,417,420],{"class":58,"line":265},[168,413,414],{"class":208},"ws.page_setup.fitToHeight ",[168,416,231],{"class":204},[168,418,419],{"class":282}," 0",[168,421,422],{"class":385},"                  # 0 = as many pages as needed\n",[168,424,425,428,430,433,436,438,441],{"class":58,"line":297},[168,426,427],{"class":208},"ws.sheet_properties.pageSetUpPr ",[168,429,231],{"class":204},[168,431,432],{"class":208}," PageSetupProperties(",[168,434,435],{"class":276},"fitToPage",[168,437,231],{"class":204},[168,439,440],{"class":282},"True",[168,442,240],{"class":208},[10,444,445,446,449],{},"That last line is the one everybody misses. ",[165,447,448],{},"fitToWidth"," is ignored unless the sheet's page-setup properties say the sheet is in fit-to-page mode; without it Excel keeps whatever percentage scale was set and the setting appears to do nothing.",[153,451,453],{"id":452},"repeat-the-header-row-on-every-page","Repeat the header row on every page",[158,455,457],{"className":195,"code":456,"language":197,"meta":163,"style":163},"ws.print_title_rows = \"1:1\"       # repeat row 1 at the top of every page\nws.print_title_cols = \"A:A\"       # and column A down the left\n",[165,458,459,472],{"__ignoreMap":163},[168,460,461,464,466,469],{"class":58,"line":170},[168,462,463],{"class":208},"ws.print_title_rows ",[168,465,231],{"class":204},[168,467,468],{"class":177}," \"1:1\"",[168,470,471],{"class":385},"       # repeat row 1 at the top of every page\n",[168,473,474,477,479,482],{"class":58,"line":218},[168,475,476],{"class":208},"ws.print_title_cols ",[168,478,231],{"class":204},[168,480,481],{"class":177}," \"A:A\"",[168,483,484],{"class":385},"       # and column A down the left\n",[10,486,487,488,18],{},"On a report longer than a page this is the difference between a printout somebody can read and one where page four is a grid of unlabelled numbers. If the report has a two-row header — a title and a column row — use ",[165,489,490],{},"\"1:2\"",[20,492,29,497,29,500,29,503,29,506,29,511,29,518,29,523,29,526,29,530,29,533,29,538,29,540,29,543,29,549],{"viewBox":493,"role":23,"ariaLabelledBy":494,"xmlns":27,"style":28},"0 0 760 218",[495,496],"pr2-t","pr2-d",[31,498,499],{"id":495},"The page-setup settings that matter, in order",[35,501,502],{"id":496},"Print area bounds what is printed, fit-to-page controls scaling, title rows repeat the header, and header and footer text carries the page numbering.",[39,504],{"x":41,"y":41,"width":42,"height":505,"fill":44},"218",[46,507,510],{"x":60,"y":508,"style":509},"26","font-size:13px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","Four settings, biggest effect first",[39,512],{"x":513,"y":514,"width":515,"height":514,"rx":516,"fill":517,"stroke":63},"30","46","332","9","#ebebfd",[46,519,522],{"x":48,"y":520,"style":521},"75","font-size:12px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","1. print_area — what prints at all",[39,524],{"x":513,"y":525,"width":515,"height":514,"rx":516,"fill":517,"stroke":63},"100",[46,527,529],{"x":48,"y":528,"style":521},"129","2. fitToPage + fitToWidth — no orphans",[39,531],{"x":532,"y":514,"width":515,"height":514,"rx":516,"fill":111,"stroke":63},"398",[46,534,537],{"x":535,"y":520,"style":536},"564","font-size:12px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","3. print_title_rows — headers repeat",[39,539],{"x":532,"y":525,"width":515,"height":514,"rx":516,"fill":111,"stroke":63},[46,541,542],{"x":535,"y":528,"style":536},"4. footer \"&P of &N\" — page numbers",[39,544],{"x":513,"y":545,"width":546,"height":547,"rx":516,"fill":548,"stroke":63},"156","700","42","#fdefd8",[46,550,553],{"x":60,"y":551,"style":552},"182","font-size:12px;fill:var(--gold-ink,#7a4e06);text-anchor:middle","All four also govern how the sheet converts to PDF",[153,555,557],{"id":556},"headers-footers-and-margins","Headers, footers and margins",[10,559,560],{},"Excel's header and footer strings use its own format codes, and openpyxl passes them straight through:",[158,562,564],{"className":195,"code":563,"language":197,"meta":163,"style":163},"ws.oddHeader.left.text = \"Regional sales\"\nws.oddHeader.left.size = 11\nws.oddHeader.right.text = \"&D &T\"                 # date and time\nws.oddFooter.center.text = \"Page &P of &N\"\nws.oddFooter.right.text = \"&F — &A\"               # filename — sheet name\n\nws.page_margins.left = 0.5\nws.page_margins.right = 0.5\nws.page_margins.top = 0.6\nws.page_margins.bottom = 0.6\n",[165,565,566,576,586,599,609,622,626,636,645,656],{"__ignoreMap":163},[168,567,568,571,573],{"class":58,"line":170},[168,569,570],{"class":208},"ws.oddHeader.left.text ",[168,572,231],{"class":204},[168,574,575],{"class":177}," \"Regional sales\"\n",[168,577,578,581,583],{"class":58,"line":218},[168,579,580],{"class":208},"ws.oddHeader.left.size ",[168,582,231],{"class":204},[168,584,585],{"class":282}," 11\n",[168,587,588,591,593,596],{"class":58,"line":225},[168,589,590],{"class":208},"ws.oddHeader.right.text ",[168,592,231],{"class":204},[168,594,595],{"class":177}," \"&D &T\"",[168,597,598],{"class":385},"                 # date and time\n",[168,600,601,604,606],{"class":58,"line":243},[168,602,603],{"class":208},"ws.oddFooter.center.text ",[168,605,231],{"class":204},[168,607,608],{"class":177}," \"Page &P of &N\"\n",[168,610,611,614,616,619],{"class":58,"line":260},[168,612,613],{"class":208},"ws.oddFooter.right.text ",[168,615,231],{"class":204},[168,617,618],{"class":177}," \"&F — &A\"",[168,620,621],{"class":385},"               # filename — sheet name\n",[168,623,624],{"class":58,"line":265},[168,625,222],{"emptyLinePlaceholder":221},[168,627,628,631,633],{"class":58,"line":297},[168,629,630],{"class":208},"ws.page_margins.left ",[168,632,231],{"class":204},[168,634,635],{"class":282}," 0.5\n",[168,637,638,641,643],{"class":58,"line":330},[168,639,640],{"class":208},"ws.page_margins.right ",[168,642,231],{"class":204},[168,644,635],{"class":282},[168,646,648,651,653],{"class":58,"line":647},9,[168,649,650],{"class":208},"ws.page_margins.top ",[168,652,231],{"class":204},[168,654,655],{"class":282}," 0.6\n",[168,657,659,662,664],{"class":58,"line":658},10,[168,660,661],{"class":208},"ws.page_margins.bottom ",[168,663,231],{"class":204},[168,665,655],{"class":282},[10,667,668,669,672,673,676,677,680,681,684,685,688,689,692,693,696],{},"The codes worth knowing are ",[165,670,671],{},"&P"," (page number), ",[165,674,675],{},"&N"," (total pages), ",[165,678,679],{},"&D"," (date), ",[165,682,683],{},"&T"," (time), ",[165,686,687],{},"&F"," (file name), ",[165,690,691],{},"&A"," (sheet name) and ",[165,694,695],{},"&B"," (bold). Margins are in inches regardless of the paper size.",[153,698,700],{"id":699},"centre-gridlines-and-print-quality","Centre, gridlines and print quality",[158,702,704],{"className":195,"code":703,"language":197,"meta":163,"style":163},"ws.print_options.horizontalCentered = True\nws.print_options.verticalCentered = False\nws.print_options.gridLines = False        # True prints the sheet grid\nws.print_options.headings = False         # row numbers and column letters\nws.page_setup.blackAndWhite = False\n",[165,705,706,716,726,739,751],{"__ignoreMap":163},[168,707,708,711,713],{"class":58,"line":170},[168,709,710],{"class":208},"ws.print_options.horizontalCentered ",[168,712,231],{"class":204},[168,714,715],{"class":282}," True\n",[168,717,718,721,723],{"class":58,"line":218},[168,719,720],{"class":208},"ws.print_options.verticalCentered ",[168,722,231],{"class":204},[168,724,725],{"class":282}," False\n",[168,727,728,731,733,736],{"class":58,"line":225},[168,729,730],{"class":208},"ws.print_options.gridLines ",[168,732,231],{"class":204},[168,734,735],{"class":282}," False",[168,737,738],{"class":385},"        # True prints the sheet grid\n",[168,740,741,744,746,748],{"class":58,"line":243},[168,742,743],{"class":208},"ws.print_options.headings ",[168,745,231],{"class":204},[168,747,735],{"class":282},[168,749,750],{"class":385},"         # row numbers and column letters\n",[168,752,753,756,758],{"class":58,"line":260},[168,754,755],{"class":208},"ws.page_setup.blackAndWhite ",[168,757,231],{"class":204},[168,759,725],{"class":282},[10,761,762],{},"Printing gridlines is usually wrong for a styled report — the borders you applied already convey the structure, and the grid competes with them. For an unformatted data dump, turning them on helps.",[153,764,766],{"id":765},"control-where-the-pages-break","Control where the pages break",[10,768,769],{},"Let Excel paginate unless a break belongs somewhere specific — between regions, or before a summary block:",[158,771,773],{"className":195,"code":772,"language":197,"meta":163,"style":163},"from openpyxl.worksheet.pagebreak import Break\n\nfor row in (25, 50, 75):\n    ws.row_breaks.append(Break(id=row))       # break after this row\n",[165,774,775,787,791,820],{"__ignoreMap":163},[168,776,777,779,782,784],{"class":58,"line":170},[168,778,205],{"class":204},[168,780,781],{"class":208}," openpyxl.worksheet.pagebreak ",[168,783,212],{"class":204},[168,785,786],{"class":208}," Break\n",[168,788,789],{"class":58,"line":218},[168,790,222],{"emptyLinePlaceholder":221},[168,792,793,796,799,802,805,808,810,813,815,817],{"class":58,"line":225},[168,794,795],{"class":204},"for",[168,797,798],{"class":208}," row ",[168,800,801],{"class":204},"in",[168,803,804],{"class":208}," (",[168,806,807],{"class":282},"25",[168,809,286],{"class":208},[168,811,812],{"class":282},"50",[168,814,286],{"class":208},[168,816,520],{"class":282},[168,818,819],{"class":208},"):\n",[168,821,822,825,828,830,833],{"class":58,"line":243},[168,823,824],{"class":208},"    ws.row_breaks.append(Break(",[168,826,827],{"class":276},"id",[168,829,231],{"class":204},[168,831,832],{"class":208},"row))       ",[168,834,835],{"class":385},"# break after this row\n",[10,837,838],{},"Manual breaks are worth adding when each page should be self-contained, for example one region per page in a pack that gets split up and handed out.",[153,840,842],{"id":841},"apply-it-to-every-sheet-in-the-workbook","Apply it to every sheet in the workbook",[10,844,845],{},"Page setup is per sheet, and a multi-sheet report needs it everywhere:",[158,847,849],{"className":195,"code":848,"language":197,"meta":163,"style":163},"from openpyxl.worksheet.properties import PageSetupProperties\n\ndef configure_printing(ws, landscape: bool = True) -> None:\n    last_col = ws.cell(row=1, column=max(ws.max_column, 1)).column_letter\n    ws.print_area = f\"A1:{last_col}{ws.max_row}\"\n    ws.page_setup.orientation = \"landscape\" if landscape else \"portrait\"\n    ws.page_setup.paperSize = ws.PAPERSIZE_A4\n    ws.page_setup.fitToWidth = 1\n    ws.page_setup.fitToHeight = 0\n    ws.sheet_properties.pageSetUpPr = PageSetupProperties(fitToPage=True)\n    ws.print_title_rows = \"1:1\"\n    ws.print_options.horizontalCentered = True\n    ws.oddFooter.center.text = \"&A — page &P of &N\"\n\nfor sheet in wb.worksheets:\n    configure_printing(sheet)\nwb.save(\"report.xlsx\")\n",[165,850,851,861,865,895,927,950,971,982,991,1001,1018,1029,1039,1050,1055,1068,1074],{"__ignoreMap":163},[168,852,853,855,857,859],{"class":58,"line":170},[168,854,205],{"class":204},[168,856,363],{"class":208},[168,858,212],{"class":204},[168,860,368],{"class":208},[168,862,863],{"class":58,"line":218},[168,864,222],{"emptyLinePlaceholder":221},[168,866,867,870,874,877,880,883,886,889,892],{"class":58,"line":225},[168,868,869],{"class":204},"def",[168,871,873],{"class":872},"s_Opv"," configure_printing",[168,875,876],{"class":208},"(ws, landscape: ",[168,878,879],{"class":282},"bool",[168,881,882],{"class":204}," =",[168,884,885],{"class":282}," True",[168,887,888],{"class":208},") -> ",[168,890,891],{"class":282},"None",[168,893,894],{"class":208},":\n",[168,896,897,900,902,904,906,908,910,912,914,916,919,922,924],{"class":58,"line":243},[168,898,899],{"class":208},"    last_col ",[168,901,231],{"class":204},[168,903,273],{"class":208},[168,905,277],{"class":276},[168,907,231],{"class":204},[168,909,283],{"class":282},[168,911,286],{"class":208},[168,913,289],{"class":276},[168,915,231],{"class":204},[168,917,918],{"class":282},"max",[168,920,921],{"class":208},"(ws.max_column, ",[168,923,283],{"class":282},[168,925,926],{"class":208},")).column_letter\n",[168,928,929,932,934,936,938,940,942,944,946,948],{"class":58,"line":260},[168,930,931],{"class":208},"    ws.print_area ",[168,933,231],{"class":204},[168,935,305],{"class":204},[168,937,308],{"class":177},[168,939,312],{"class":311},[168,941,315],{"class":208},[168,943,318],{"class":311},[168,945,321],{"class":208},[168,947,324],{"class":311},[168,949,327],{"class":177},[168,951,952,955,957,959,962,965,968],{"class":58,"line":265},[168,953,954],{"class":208},"    ws.page_setup.orientation ",[168,956,231],{"class":204},[168,958,382],{"class":177},[168,960,961],{"class":204}," if",[168,963,964],{"class":208}," landscape ",[168,966,967],{"class":204},"else",[168,969,970],{"class":177}," \"portrait\"\n",[168,972,973,976,978,980],{"class":58,"line":297},[168,974,975],{"class":208},"    ws.page_setup.paperSize ",[168,977,231],{"class":204},[168,979,396],{"class":208},[168,981,399],{"class":282},[168,983,984,987,989],{"class":58,"line":330},[168,985,986],{"class":208},"    ws.page_setup.fitToWidth ",[168,988,231],{"class":204},[168,990,409],{"class":282},[168,992,993,996,998],{"class":58,"line":647},[168,994,995],{"class":208},"    ws.page_setup.fitToHeight ",[168,997,231],{"class":204},[168,999,1000],{"class":282}," 0\n",[168,1002,1003,1006,1008,1010,1012,1014,1016],{"class":58,"line":658},[168,1004,1005],{"class":208},"    ws.sheet_properties.pageSetUpPr ",[168,1007,231],{"class":204},[168,1009,432],{"class":208},[168,1011,435],{"class":276},[168,1013,231],{"class":204},[168,1015,440],{"class":282},[168,1017,240],{"class":208},[168,1019,1021,1024,1026],{"class":58,"line":1020},11,[168,1022,1023],{"class":208},"    ws.print_title_rows ",[168,1025,231],{"class":204},[168,1027,1028],{"class":177}," \"1:1\"\n",[168,1030,1032,1035,1037],{"class":58,"line":1031},12,[168,1033,1034],{"class":208},"    ws.print_options.horizontalCentered ",[168,1036,231],{"class":204},[168,1038,715],{"class":282},[168,1040,1042,1045,1047],{"class":58,"line":1041},13,[168,1043,1044],{"class":208},"    ws.oddFooter.center.text ",[168,1046,231],{"class":204},[168,1048,1049],{"class":177}," \"&A — page &P of &N\"\n",[168,1051,1053],{"class":58,"line":1052},14,[168,1054,222],{"emptyLinePlaceholder":221},[168,1056,1058,1060,1063,1065],{"class":58,"line":1057},15,[168,1059,795],{"class":204},[168,1061,1062],{"class":208}," sheet ",[168,1064,801],{"class":204},[168,1066,1067],{"class":208}," wb.worksheets:\n",[168,1069,1071],{"class":58,"line":1070},16,[168,1072,1073],{"class":208},"    configure_printing(sheet)\n",[168,1075,1077,1079,1081],{"class":58,"line":1076},17,[168,1078,333],{"class":208},[168,1080,237],{"class":177},[168,1082,240],{"class":208},[10,1084,1085,1086,18],{},"Putting that in the same module as the report's style constants keeps every generated workbook consistent, in the spirit of ",[14,1087,1089],{"href":1088},"\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",[153,1091,1093],{"id":1092},"check-the-settings-landed","Check the settings landed",[10,1095,1096],{},"Page setup is invisible until somebody prints, which is the worst moment to discover it is wrong. Read the properties back after saving:",[158,1098,1100],{"className":195,"code":1099,"language":197,"meta":163,"style":163},"from openpyxl import load_workbook\n\nwb = load_workbook(\"report.xlsx\")\nfor ws in wb.worksheets:\n    setup = ws.page_setup\n    props = ws.sheet_properties.pageSetUpPr\n    print(f\"{ws.title:20s} area={ws.print_area} titles={ws.print_title_rows} \"\n          f\"orient={setup.orientation} fitW={setup.fitToWidth} \"\n          f\"fitToPage={getattr(props, 'fitToPage', None)}\")\n",[165,1101,1102,1112,1116,1128,1139,1149,1159,1206,1233],{"__ignoreMap":163},[168,1103,1104,1106,1108,1110],{"class":58,"line":170},[168,1105,205],{"class":204},[168,1107,209],{"class":208},[168,1109,212],{"class":204},[168,1111,215],{"class":208},[168,1113,1114],{"class":58,"line":218},[168,1115,222],{"emptyLinePlaceholder":221},[168,1117,1118,1120,1122,1124,1126],{"class":58,"line":225},[168,1119,228],{"class":208},[168,1121,231],{"class":204},[168,1123,234],{"class":208},[168,1125,237],{"class":177},[168,1127,240],{"class":208},[168,1129,1130,1132,1135,1137],{"class":58,"line":243},[168,1131,795],{"class":204},[168,1133,1134],{"class":208}," ws ",[168,1136,801],{"class":204},[168,1138,1067],{"class":208},[168,1140,1141,1144,1146],{"class":58,"line":260},[168,1142,1143],{"class":208},"    setup ",[168,1145,231],{"class":204},[168,1147,1148],{"class":208}," ws.page_setup\n",[168,1150,1151,1154,1156],{"class":58,"line":265},[168,1152,1153],{"class":208},"    props ",[168,1155,231],{"class":204},[168,1157,1158],{"class":208}," ws.sheet_properties.pageSetUpPr\n",[168,1160,1161,1164,1167,1170,1173,1175,1178,1181,1183,1186,1188,1191,1193,1196,1198,1201,1203],{"class":58,"line":297},[168,1162,1163],{"class":282},"    print",[168,1165,1166],{"class":208},"(",[168,1168,1169],{"class":204},"f",[168,1171,1172],{"class":177},"\"",[168,1174,312],{"class":311},[168,1176,1177],{"class":208},"ws.title",[168,1179,1180],{"class":204},":20s",[168,1182,324],{"class":311},[168,1184,1185],{"class":177}," area=",[168,1187,312],{"class":311},[168,1189,1190],{"class":208},"ws.print_area",[168,1192,324],{"class":311},[168,1194,1195],{"class":177}," titles=",[168,1197,312],{"class":311},[168,1199,1200],{"class":208},"ws.print_title_rows",[168,1202,324],{"class":311},[168,1204,1205],{"class":177}," \"\n",[168,1207,1208,1211,1214,1216,1219,1221,1224,1226,1229,1231],{"class":58,"line":330},[168,1209,1210],{"class":204},"          f",[168,1212,1213],{"class":177},"\"orient=",[168,1215,312],{"class":311},[168,1217,1218],{"class":208},"setup.orientation",[168,1220,324],{"class":311},[168,1222,1223],{"class":177}," fitW=",[168,1225,312],{"class":311},[168,1227,1228],{"class":208},"setup.fitToWidth",[168,1230,324],{"class":311},[168,1232,1205],{"class":177},[168,1234,1235,1237,1240,1242,1245,1248,1251,1253,1255,1258,1260,1262],{"class":58,"line":647},[168,1236,1210],{"class":204},[168,1238,1239],{"class":177},"\"fitToPage=",[168,1241,312],{"class":311},[168,1243,1244],{"class":282},"getattr",[168,1246,1247],{"class":208},"(props, ",[168,1249,1250],{"class":177},"'fitToPage'",[168,1252,286],{"class":208},[168,1254,891],{"class":282},[168,1256,1257],{"class":208},")",[168,1259,324],{"class":311},[168,1261,1172],{"class":177},[168,1263,240],{"class":208},[158,1265,1269],{"className":1266,"code":1268,"language":46,"meta":163},[1267],"language-text","Summary              area=A1:H42 titles=1:1 orient=landscape fitW=1 fitToPage=True\nDetail               area=None   titles=None orient=portrait  fitW=None fitToPage=None\n",[165,1270,1268],{"__ignoreMap":163},[10,1272,1273,1274,1277],{},"The second line is the failure this check exists to catch: a sheet added later that never went through the configure function. Looping over ",[165,1275,1276],{},"wb.worksheets"," at the end of the job, rather than configuring sheets as they are created, makes that impossible.",[20,1279,29,1284,29,1287,29,1290,29,1292,29,1295,29,1298,29,1300,29,1305,29,1308,29,1312,29,1314,29,1318,29,1320,29,1323],{"viewBox":1280,"role":23,"ariaLabelledBy":1281,"xmlns":27,"style":28},"0 0 760 196",[1282,1283],"pr3-t","pr3-d",[31,1285,1286],{"id":1282},"Configuring sheets as a final pass rather than at creation",[35,1288,1289],{"id":1283},"Applying page setup inside each builder leaves any later-added sheet unconfigured, while a single pass over every worksheet at the end covers all of them.",[39,1291],{"x":41,"y":41,"width":42,"height":48,"fill":44},[46,1293,1294],{"x":48,"y":49,"style":50},"configure per builder",[46,1296,1297],{"x":54,"y":49,"style":55},"configure in one final pass",[39,1299],{"x":513,"y":514,"width":515,"height":67,"rx":516,"fill":72,"stroke":63},[46,1301,1304],{"x":48,"y":1302,"style":1303},"74","font-size:12px;fill:var(--accent-ink,#be185d);text-anchor:middle","every builder must remember to call it",[39,1306],{"x":513,"y":1307,"width":515,"height":67,"rx":516,"fill":72,"stroke":63},"98",[46,1309,1311],{"x":48,"y":1310,"style":1303},"126","a new sheet ships unconfigured",[39,1313],{"x":532,"y":514,"width":515,"height":67,"rx":516,"fill":111,"stroke":63},[46,1315,1317],{"x":535,"y":1302,"style":1316},"font-size:12px;fill:var(--teal-ink,#0b6157);text-anchor:middle","one loop over wb.worksheets",[39,1319],{"x":532,"y":1307,"width":515,"height":67,"rx":516,"fill":111,"stroke":63},[46,1321,1322],{"x":535,"y":1310,"style":1316},"new sheets covered automatically",[46,1324,1326],{"x":60,"y":1325,"style":105},"176","The same argument applies to freeze panes and column widths",[153,1328,1330],{"id":1329},"scale-by-percentage-when-fitting-is-wrong","Scale by percentage when fitting is wrong",[10,1332,1333],{},"Fit-to-page is right for a wide table, but it can shrink a narrow report to an unreadable size — a five-column sheet fitted to one page wide is fine, while the same setting on a sheet with one very wide text column drags everything down with it. Use an explicit percentage scale instead:",[158,1335,1337],{"className":195,"code":1336,"language":197,"meta":163,"style":163},"ws.sheet_properties.pageSetUpPr = None       # leave fit-to-page mode\nws.page_setup.scale = 85                     # per cent of natural size\n",[165,1338,1339,1351],{"__ignoreMap":163},[168,1340,1341,1343,1345,1348],{"class":58,"line":170},[168,1342,427],{"class":208},[168,1344,231],{"class":204},[168,1346,1347],{"class":282}," None",[168,1349,1350],{"class":385},"       # leave fit-to-page mode\n",[168,1352,1353,1356,1358,1361],{"class":58,"line":218},[168,1354,1355],{"class":208},"ws.page_setup.scale ",[168,1357,231],{"class":204},[168,1359,1360],{"class":282}," 85",[168,1362,1363],{"class":385},"                     # per cent of natural size\n",[10,1365,1366,1367,1370],{},"The two are mutually exclusive: Excel honours ",[165,1368,1369],{},"scale"," only when the sheet is not in fit-to-page mode, which is why the property is cleared first. Between 80 and 90 per cent usually buys a column or two without hurting legibility; below about 70 the text stops being comfortable to read on paper.",[10,1372,1373,1374,18],{},"A practical rule for a generated report: fit to width when the sheet is a wide table of numbers, and use a fixed scale when it is a narrow document-like sheet with long text. If you cannot decide, set the width of the widest text column explicitly and wrap it — the layout then fits without any scaling at all, as covered in ",[14,1375,1377],{"href":1376},"\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",[153,1379,1381],{"id":1380},"common-pitfalls-and-gotchas","Common pitfalls and gotchas",[1383,1384,1385,1397,1407,1413,1419],"ul",{},[1386,1387,1388,1396],"li",{},[1389,1390,1391,1393,1394,18],"strong",{},[165,1392,448],{}," with no ",[165,1395,435],{}," The setting is silently ignored; set the sheet property too.",[1386,1398,1399,1402,1403,1406],{},[1389,1400,1401],{},"A stale print area."," Hardcoding ",[165,1404,1405],{},"A1:F100"," on a report that grows to 300 rows truncates it without warning.",[1386,1408,1409,1412],{},[1389,1410,1411],{},"Margins in the wrong unit."," They are inches, not centimetres or points.",[1386,1414,1415,1418],{},[1389,1416,1417],{},"Setting page options on the workbook."," They live on each worksheet.",[1386,1420,1421,1424,1425,1428,1429,1432],{},[1389,1422,1423],{},"Expecting xlsxwriter's API here."," xlsxwriter uses methods such as ",[165,1426,1427],{},"ws.set_landscape()"," and ",[165,1430,1431],{},"ws.fit_to_pages()","; the concepts match but the names do not.",[153,1434,1436],{"id":1435},"performance-and-scale-notes","Performance and scale notes",[10,1438,1439,1440,1428,1443,1445,1446,1450,1451,18],{},"Page setup costs nothing at write time — it is a handful of XML attributes — so apply it to every generated sheet rather than only the ones somebody has complained about. Where it does have a measurable effect is PDF conversion: a sheet without a print area can produce a PDF hundreds of pages long, which is slow to render and slow to email. Setting ",[165,1441,1442],{},"print_area",[165,1444,448],{}," before conversion often turns a multi-megabyte PDF into a two-page one. The conversion itself is covered in ",[14,1447,1449],{"href":1448},"\u002Fautomating-reporting-workflows\u002Fexporting-excel-reports-to-pdf\u002Fconvert-excel-file-to-pdf-with-python\u002F","Convert an Excel file to PDF with Python"," and the page furniture in ",[14,1452,1454],{"href":1453},"\u002Fautomating-reporting-workflows\u002Fexporting-excel-reports-to-pdf\u002Fadd-headers-footers-and-page-numbers-to-an-excel-pdf\u002F","Add headers, footers and page numbers to an Excel PDF",[153,1456,1458],{"id":1457},"conclusion","Conclusion",[10,1460,1461],{},"Ten lines of page setup decide whether a generated report is usable on paper or as a PDF. Set the print area from the data's real extent, turn on fit-to-page and fit-to-width so no column is orphaned, repeat the header row, and put \"page P of N\" in the footer. Apply the same function to every sheet in the workbook, and the output is consistent whether a reader prints it, exports it, or just scrolls.",[153,1463,1465],{"id":1464},"frequently-asked-questions","Frequently asked questions",[10,1467,1468,1471,1472,1475,1476,1478],{},[1389,1469,1470],{},"Why does fitToWidth do nothing?","\nScaling options only apply when sheet properties are set to use them. Set ",[165,1473,1474],{},"ws.sheet_properties.pageSetUpPr.fitToPage = True"," as well as ",[165,1477,448],{},", or Excel keeps the percentage scale instead.",[10,1480,1481,1484,1485,1488,1489,1492,1493,1495,1496,18],{},[1389,1482,1483],{},"How do I repeat the header row on every printed page?","\nSet ",[165,1486,1487],{},"ws.print_title_rows = \"1:1\"",". The equivalent for columns is ",[165,1490,1491],{},"print_title_cols",", and both accept ranges like ",[165,1494,490],{}," or ",[165,1497,1498],{},"\"A:B\"",[10,1500,1501,1504],{},[1389,1502,1503],{},"Does this affect a PDF export?","\nYes, and that is the main reason to bother. LibreOffice and Excel both honour page setup when converting to PDF, so an unconfigured sheet becomes a PDF spread across a dozen ragged pages.",[10,1506,1507,1510],{},[1389,1508,1509],{},"Can I set the print area to several ranges?","\nYes — assign a list of ranges. Excel prints each as its own page, which is useful for a summary block and a detail block on one sheet.",[10,1512,1513,1516,1517,1520,1521,1524],{},[1389,1514,1515],{},"How do I put the page number in the footer?","\nUse Excel's format codes in ",[165,1518,1519],{},"ws.oddFooter.center.text",", for example ",[165,1522,1523],{},"\"Page &P of &N\"",". The same codes work in headers.",[153,1526,1528],{"id":1527},"related","Related",[1383,1530,1531,1540,1547,1552,1557],{},[1386,1532,1533,1536,1537,1539],{},[1389,1534,1535],{},"Up:"," ",[14,1538,17],{"href":16}," — the on-screen half of presentation.",[1386,1541,1542,1546],{},[14,1543,1545],{"href":1544},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Ffreeze-header-row-in-excel-with-openpyxl\u002F","Freeze the header row in Excel with openpyxl"," — the on-screen counterpart to repeated print titles.",[1386,1548,1549,1551],{},[14,1550,1377],{"href":1376}," — widths decide how much fit-to-width has to shrink.",[1386,1553,1554,1556],{},[14,1555,1449],{"href":1448}," — where these settings pay off most.",[1386,1558,1559,1561],{},[14,1560,1454],{"href":1453}," — the same codes, in the PDF pipeline.",[1563,1564,1565],"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 .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html pre.shiki code .sP0c6, html code.shiki .sP0c6{--shiki-default:#005CC5;--shiki-dark:#91CBFF}html pre.shiki code .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}html pre.shiki code .s-wDw, html code.shiki .s-wDw{--shiki-default:#6A737D;--shiki-dark:#BDC4CC}html pre.shiki code .s_Opv, html code.shiki .s_Opv{--shiki-default:#6F42C1;--shiki-dark:#DBB7FF}",{"title":163,"searchDepth":218,"depth":218,"links":1567},[1568,1569,1570,1571,1572,1573,1574,1575,1576,1577,1578,1579,1580,1581,1582],{"id":155,"depth":218,"text":156},{"id":184,"depth":218,"text":185},{"id":347,"depth":218,"text":348},{"id":452,"depth":218,"text":453},{"id":556,"depth":218,"text":557},{"id":699,"depth":218,"text":700},{"id":765,"depth":218,"text":766},{"id":841,"depth":218,"text":842},{"id":1092,"depth":218,"text":1093},{"id":1329,"depth":218,"text":1330},{"id":1380,"depth":218,"text":1381},{"id":1435,"depth":218,"text":1436},{"id":1457,"depth":218,"text":1458},{"id":1464,"depth":218,"text":1465},{"id":1527,"depth":218,"text":1528},"2026-08-27","Make a generated workbook print properly: print area, landscape orientation, fit to width, repeated header rows, margins, headers and footers, and page breaks.","md",[1587,1589,1591,1593,1595],{"q":1470,"a":1588},"Scaling options only apply when sheet properties are set to use them. Set ws.sheet_properties.pageSetUpPr.fitToPage = True as well as fitToWidth, or Excel keeps the percentage scale instead.",{"q":1483,"a":1590},"Set ws.print_title_rows = \"1:1\". The equivalent for columns is print_title_cols, and both accept ranges like \"1:2\" or \"A:B\".",{"q":1503,"a":1592},"Yes, and that is the main reason to bother. LibreOffice and Excel both honour page setup when converting to PDF, so an unconfigured sheet becomes a PDF spread across a dozen ragged pages.",{"q":1509,"a":1594},"Yes — assign a list of ranges. Excel prints each as its own page, which is useful for a summary block and a detail block on one sheet.",{"q":1515,"a":1596},"Use Excel's format codes in ws.oddFooter.center.text, for example \"Page &P of &N\". The same codes work in headers.",{},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fset-print-area-and-page-setup-with-openpyxl",{"title":1600,"description":1601},"Excel Print Area and Page Setup in openpyxl","Configure printing from openpyxl: print_area, orientation, fitToWidth scaling, print_title_rows, margins, header\u002Ffooter codes, gridlines and manual page breaks.","set-print-area-and-page-setup-with-openpyxl","formatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fset-print-area-and-page-setup-with-openpyxl\u002Findex","how-to","q03S-SJYRY0jG84OLLoMsAmzudgooQf0rh64NT5UrZ0",[1607,1611],{"title":1608,"path":1609,"stem":1610,"children":-1},"Set Column Width and Row Height in openpyxl","\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fset-column-width-and-row-height-in-openpyxl","formatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fset-column-width-and-row-height-in-openpyxl\u002Findex",{"title":1612,"path":1613,"stem":1614,"children":-1},"Getting Started with Python Excel Automation","\u002Fgetting-started-with-python-excel-automation","getting-started-with-python-excel-automation\u002Findex",1788710154008]