[{"data":1,"prerenderedAt":2533},["ShallowReactive",2],{"doc:\u002Fgetting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas\u002Fexport-a-styled-pandas-dataframe-to-excel":3,"surround:\u002Fgetting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas\u002Fexport-a-styled-pandas-dataframe-to-excel":2498,"ancestors:\u002Fgetting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas\u002Fexport-a-styled-pandas-dataframe-to-excel":2507,"children:\u002Fgetting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas\u002Fexport-a-styled-pandas-dataframe-to-excel":2512,"related:\u002Fgetting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas\u002Fexport-a-styled-pandas-dataframe-to-excel":2513},{"id":4,"title":5,"body":6,"dateModified":2463,"datePublished":2463,"description":2464,"extension":2465,"faq":2466,"keyword":2475,"kind":2476,"meta":2477,"navigation":225,"path":2486,"seo":2487,"slug":2490,"stem":2491,"topics":2492,"type":2496,"__hash__":2497},"docs\u002Fgetting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas\u002Fexport-a-styled-pandas-dataframe-to-excel\u002Findex.md","Export a Styled pandas DataFrame to Excel",{"type":7,"value":8,"toc":2448},"minimark",[9,35,148,153,186,197,365,369,382,582,596,600,603,747,750,826,830,849,1011,1019,1023,1032,1197,1207,1411,1415,1429,1577,1591,1595,1609,1826,1832,1836,1839,2209,2219,2223,2334,2338,2348,2354,2358,2373,2377,2384,2390,2396,2402,2406,2444],[10,11,12,16,17,20,21,24,25,28,29,34],"p",{},[13,14,15],"code",{},"df.to_excel()"," writes values and nothing else: no colours, no bold headers, no highlighted outliers. Most\npeople then reach for openpyxl and loop over cells. There is a shorter path for many reports. pandas'\n",[13,18,19],{},"Styler"," — the object behind ",[13,22,23],{},"df.style"," that notebooks use to render coloured tables — has its own\n",[13,26,27],{},"to_excel"," method, and it converts a useful subset of CSS into real Excel formatting. This guide, part of\n",[30,31,33],"a",{"href":32},"\u002Fgetting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas\u002F","Writing DataFrames to Excel with Pandas",",\nshows what carries over, what quietly does not, and how to fill the gaps.",[36,37,45,46,45,50,45,54,45,61,45,70,45,77,45,82,45,89,45,94,45,98,45,102,45,106,45,110,45,113,45,116,45,120,45,123,45,127,45,130,45,135,45,139,45,142],"svg",{"viewBox":38,"role":39,"ariaLabelledBy":40,"xmlns":43,"style":44},"0 0 760 136","img",[41,42],"sty-path-t","sty-path-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  ",[47,48,49],"title",{"id":41},"From DataFrame to formatted workbook through Styler",[51,52,53],"desc",{"id":42},"A DataFrame gets a Styler through df.style, style methods attach CSS to cells, and Styler.to_excel converts supported CSS properties into Excel fills, fonts, borders and number formats in the written workbook.",[55,56],"rect",{"x":57,"y":57,"width":58,"height":59,"fill":60},"0","760","136","#ffffff",[55,62],{"x":63,"y":63,"width":64,"height":65,"rx":66,"fill":67,"stroke":68,"style":69},"20","150","66","12","#e7ebef","var(--line,#cdd5e6)","stroke-width:2px",[71,72,76],"text",{"x":73,"y":74,"style":75},"95","50","font-size:14px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","DataFrame",[71,78,81],{"x":73,"y":79,"style":80},"72","font-size:11.5px;font-weight:400;fill:var(--muted,#5b6780);text-anchor:middle","values",[83,84],"line",{"x1":85,"y1":86,"x2":87,"y2":86,"stroke":88,"style":69},"175","53","204","var(--brand,#5b5cf0)",[90,91],"polygon",{"points":92,"fill":93},"207,53 198,48 198,58","#5b5cf0",[55,95],{"x":96,"y":63,"width":64,"height":65,"rx":66,"fill":97,"stroke":88,"style":69},"210","#f0f4ff",[71,99,23],{"x":100,"y":74,"style":101},"285","font-size:14px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle",[71,103,105],{"x":100,"y":79,"style":104},"font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","a Styler",[83,107],{"x1":108,"y1":86,"x2":109,"y2":86,"stroke":88,"style":69},"365","394",[90,111],{"points":112,"fill":93},"397,53 388,48 388,58",[55,114],{"x":115,"y":63,"width":64,"height":65,"rx":66,"fill":97,"stroke":88,"style":69},"400",[71,117,119],{"x":118,"y":74,"style":101},"475","style methods",[71,121,122],{"x":118,"y":79,"style":104},"CSS per cell",[83,124],{"x1":125,"y1":86,"x2":126,"y2":86,"stroke":88,"style":69},"555","584",[90,128],{"points":129,"fill":93},"587,53 578,48 578,58",[55,131],{"x":132,"y":63,"width":64,"height":65,"rx":66,"fill":133,"stroke":134,"style":69},"590","#d9f4f1","var(--teal,#0f9488)",[71,136,27],{"x":137,"y":74,"style":138},"665","font-size:14px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle",[71,140,141],{"x":137,"y":79,"style":104},"CSS → Excel styles",[71,143,147],{"x":144,"y":145,"style":146},"380","120","font-size:12.5px;font-weight:400;fill:var(--muted,#5b6780);text-anchor:middle","only CSS reaches Excel; display formatting does not",[149,150,152],"h2",{"id":151},"prerequisites","Prerequisites",[154,155,160],"pre",{"className":156,"code":157,"language":158,"meta":159,"style":159},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install pandas openpyxl jinja2 matplotlib\n","bash","",[13,161,162],{"__ignoreMap":159},[163,164,166,170,174,177,180,183],"span",{"class":83,"line":165},1,[163,167,169],{"class":168},"sMTad","pip",[163,171,173],{"class":172},"srMev"," install",[163,175,176],{"class":172}," pandas",[163,178,179],{"class":172}," openpyxl",[163,181,182],{"class":172}," jinja2",[163,184,185],{"class":172}," matplotlib\n",[10,187,188,189,192,193,196],{},"Styler needs ",[13,190,191],{},"jinja2"," installed, and ",[13,194,195],{},"background_gradient"," needs matplotlib for its colour maps. The examples use this small frame:",[154,198,202],{"className":199,"code":200,"language":201,"meta":159,"style":159},"language-python shiki shiki-themes github-light github-dark-high-contrast","import pandas as pd\n\nsales = pd.DataFrame({\n    \"Region\": [\"North\", \"South\", \"East\", \"West\"],\n    \"Revenue\": [120500.0, 98200.5, 143900.25, 87150.0],\n    \"Growth\": [0.12, -0.034, 0.081, -0.12],\n    \"Deals\": [14, 11, 17, 9],\n})\n","python",[13,203,204,220,227,239,270,299,331,359],{"__ignoreMap":159},[163,205,206,210,214,217],{"class":83,"line":165},[163,207,209],{"class":208},"s-kum","import",[163,211,213],{"class":212},"skGVy"," pandas ",[163,215,216],{"class":208},"as",[163,218,219],{"class":212}," pd\n",[163,221,223],{"class":83,"line":222},2,[163,224,226],{"emptyLinePlaceholder":225},true,"\n",[163,228,230,233,236],{"class":83,"line":229},3,[163,231,232],{"class":212},"sales ",[163,234,235],{"class":208},"=",[163,237,238],{"class":212}," pd.DataFrame({\n",[163,240,242,245,248,251,254,257,259,262,264,267],{"class":83,"line":241},4,[163,243,244],{"class":172},"    \"Region\"",[163,246,247],{"class":212},": [",[163,249,250],{"class":172},"\"North\"",[163,252,253],{"class":212},", ",[163,255,256],{"class":172},"\"South\"",[163,258,253],{"class":212},[163,260,261],{"class":172},"\"East\"",[163,263,253],{"class":212},[163,265,266],{"class":172},"\"West\"",[163,268,269],{"class":212},"],\n",[163,271,273,276,278,282,284,287,289,292,294,297],{"class":83,"line":272},5,[163,274,275],{"class":172},"    \"Revenue\"",[163,277,247],{"class":212},[163,279,281],{"class":280},"sP0c6","120500.0",[163,283,253],{"class":212},[163,285,286],{"class":280},"98200.5",[163,288,253],{"class":212},[163,290,291],{"class":280},"143900.25",[163,293,253],{"class":212},[163,295,296],{"class":280},"87150.0",[163,298,269],{"class":212},[163,300,302,305,307,310,312,315,318,320,323,325,327,329],{"class":83,"line":301},6,[163,303,304],{"class":172},"    \"Growth\"",[163,306,247],{"class":212},[163,308,309],{"class":280},"0.12",[163,311,253],{"class":212},[163,313,314],{"class":208},"-",[163,316,317],{"class":280},"0.034",[163,319,253],{"class":212},[163,321,322],{"class":280},"0.081",[163,324,253],{"class":212},[163,326,314],{"class":208},[163,328,309],{"class":280},[163,330,269],{"class":212},[163,332,334,337,339,342,344,347,349,352,354,357],{"class":83,"line":333},7,[163,335,336],{"class":172},"    \"Deals\"",[163,338,247],{"class":212},[163,340,341],{"class":280},"14",[163,343,253],{"class":212},[163,345,346],{"class":280},"11",[163,348,253],{"class":212},[163,350,351],{"class":280},"17",[163,353,253],{"class":212},[163,355,356],{"class":280},"9",[163,358,269],{"class":212},[163,360,362],{"class":83,"line":361},8,[163,363,364],{"class":212},"})\n",[149,366,368],{"id":367},"step-1-write-a-styled-frame","Step 1 — Write a styled frame",[10,370,371,372,374,375,377,378,381],{},"Chain style methods on ",[13,373,23],{}," and call ",[13,376,27],{}," on the result exactly as you would on the DataFrame. The styling methods take a ",[13,379,380],{},"subset"," of\ncolumns, and functions return CSS strings per cell.",[154,383,385],{"className":199,"code":384,"language":201,"meta":159,"style":159},"def negative_red(value: float) -> str:\n    return \"color: #be185d; font-weight: bold\" if value \u003C 0 else \"\"\n\nstyled = (\n    sales.style\n         .map(negative_red, subset=[\"Growth\"])\n         .set_properties(subset=[\"Region\"], **{\"font-weight\": \"bold\"})\n         .highlight_max(subset=[\"Revenue\"], color=\"#C6EFCE\")\n)\nstyled.to_excel(\"styled.xlsx\", sheet_name=\"Sales\", index=False, engine=\"openpyxl\")\n",[13,386,387,411,437,441,451,456,475,509,536,541],{"__ignoreMap":159},[163,388,389,392,396,399,402,405,408],{"class":83,"line":165},[163,390,391],{"class":208},"def",[163,393,395],{"class":394},"s_Opv"," negative_red",[163,397,398],{"class":212},"(value: ",[163,400,401],{"class":280},"float",[163,403,404],{"class":212},") -> ",[163,406,407],{"class":280},"str",[163,409,410],{"class":212},":\n",[163,412,413,416,419,422,425,428,431,434],{"class":83,"line":222},[163,414,415],{"class":208},"    return",[163,417,418],{"class":172}," \"color: #be185d; font-weight: bold\"",[163,420,421],{"class":208}," if",[163,423,424],{"class":212}," value ",[163,426,427],{"class":208},"\u003C",[163,429,430],{"class":280}," 0",[163,432,433],{"class":208}," else",[163,435,436],{"class":172}," \"\"\n",[163,438,439],{"class":83,"line":229},[163,440,226],{"emptyLinePlaceholder":225},[163,442,443,446,448],{"class":83,"line":241},[163,444,445],{"class":212},"styled ",[163,447,235],{"class":208},[163,449,450],{"class":212}," (\n",[163,452,453],{"class":83,"line":272},[163,454,455],{"class":212},"    sales.style\n",[163,457,458,461,464,466,469,472],{"class":83,"line":301},[163,459,460],{"class":212},"         .map(negative_red, ",[163,462,380],{"class":463},"sa561",[163,465,235],{"class":208},[163,467,468],{"class":212},"[",[163,470,471],{"class":172},"\"Growth\"",[163,473,474],{"class":212},"])\n",[163,476,477,480,482,484,486,489,492,495,498,501,504,507],{"class":83,"line":333},[163,478,479],{"class":212},"         .set_properties(",[163,481,380],{"class":463},[163,483,235],{"class":208},[163,485,468],{"class":212},[163,487,488],{"class":172},"\"Region\"",[163,490,491],{"class":212},"], ",[163,493,494],{"class":208},"**",[163,496,497],{"class":212},"{",[163,499,500],{"class":172},"\"font-weight\"",[163,502,503],{"class":212},": ",[163,505,506],{"class":172},"\"bold\"",[163,508,364],{"class":212},[163,510,511,514,516,518,520,523,525,528,530,533],{"class":83,"line":361},[163,512,513],{"class":212},"         .highlight_max(",[163,515,380],{"class":463},[163,517,235],{"class":208},[163,519,468],{"class":212},[163,521,522],{"class":172},"\"Revenue\"",[163,524,491],{"class":212},[163,526,527],{"class":463},"color",[163,529,235],{"class":208},[163,531,532],{"class":172},"\"#C6EFCE\"",[163,534,535],{"class":212},")\n",[163,537,539],{"class":83,"line":538},9,[163,540,535],{"class":212},[163,542,544,547,550,552,555,557,560,562,565,567,570,572,575,577,580],{"class":83,"line":543},10,[163,545,546],{"class":212},"styled.to_excel(",[163,548,549],{"class":172},"\"styled.xlsx\"",[163,551,253],{"class":212},[163,553,554],{"class":463},"sheet_name",[163,556,235],{"class":208},[163,558,559],{"class":172},"\"Sales\"",[163,561,253],{"class":212},[163,563,564],{"class":463},"index",[163,566,235],{"class":208},[163,568,569],{"class":280},"False",[163,571,253],{"class":212},[163,573,574],{"class":463},"engine",[163,576,235],{"class":208},[163,578,579],{"class":172},"\"openpyxl\"",[163,581,535],{"class":212},[10,583,584,587,588,591,592,595],{},[13,585,586],{},"map"," (called ",[13,589,590],{},"applymap"," in older pandas releases) applies a function to each cell; ",[13,593,594],{},"apply"," passes whole columns or rows, which suits rules that compare values\nwith each other. Open the file and the negative growth figures are red and bold, the region names bold, and the best revenue cell green — all without touching\nopenpyxl directly.",[149,597,599],{"id":598},"step-2-know-which-css-becomes-excel-formatting","Step 2 — Know which CSS becomes Excel formatting",[10,601,602],{},"The conversion recognises a specific set of CSS properties and maps them onto Excel's style model. Anything else is ignored without a warning, which is the source of\nmost \"my styling disappeared\" surprises.",[154,604,606],{"className":199,"code":605,"language":201,"meta":159,"style":159},"from openpyxl import load_workbook\n\nsheet = load_workbook(\"styled.xlsx\")[\"Sales\"]\nfor ref in (\"A2\", \"B4\", \"C3\"):\n    cell = sheet[ref]\n    print(ref, cell.value, \"bold\" if cell.font.b else \"\", cell.fill.fgColor.rgb,\n          cell.font.color.rgb if cell.font.color is not None and cell.font.color.type == \"rgb\" else \"\")\n",[13,607,608,621,625,645,675,685,709],{"__ignoreMap":159},[163,609,610,613,616,618],{"class":83,"line":165},[163,611,612],{"class":208},"from",[163,614,615],{"class":212}," openpyxl ",[163,617,209],{"class":208},[163,619,620],{"class":212}," load_workbook\n",[163,622,623],{"class":83,"line":222},[163,624,226],{"emptyLinePlaceholder":225},[163,626,627,630,632,635,637,640,642],{"class":83,"line":229},[163,628,629],{"class":212},"sheet ",[163,631,235],{"class":208},[163,633,634],{"class":212}," load_workbook(",[163,636,549],{"class":172},[163,638,639],{"class":212},")[",[163,641,559],{"class":172},[163,643,644],{"class":212},"]\n",[163,646,647,650,653,656,659,662,664,667,669,672],{"class":83,"line":241},[163,648,649],{"class":208},"for",[163,651,652],{"class":212}," ref ",[163,654,655],{"class":208},"in",[163,657,658],{"class":212}," (",[163,660,661],{"class":172},"\"A2\"",[163,663,253],{"class":212},[163,665,666],{"class":172},"\"B4\"",[163,668,253],{"class":212},[163,670,671],{"class":172},"\"C3\"",[163,673,674],{"class":212},"):\n",[163,676,677,680,682],{"class":83,"line":272},[163,678,679],{"class":212},"    cell ",[163,681,235],{"class":208},[163,683,684],{"class":212}," sheet[ref]\n",[163,686,687,690,693,695,697,700,703,706],{"class":83,"line":301},[163,688,689],{"class":280},"    print",[163,691,692],{"class":212},"(ref, cell.value, ",[163,694,506],{"class":172},[163,696,421],{"class":208},[163,698,699],{"class":212}," cell.font.b ",[163,701,702],{"class":208},"else",[163,704,705],{"class":172}," \"\"",[163,707,708],{"class":212},", cell.fill.fgColor.rgb,\n",[163,710,711,714,717,720,723,726,729,732,735,738,741,743,745],{"class":83,"line":333},[163,712,713],{"class":212},"          cell.font.color.rgb ",[163,715,716],{"class":208},"if",[163,718,719],{"class":212}," cell.font.color ",[163,721,722],{"class":208},"is",[163,724,725],{"class":208}," not",[163,727,728],{"class":280}," None",[163,730,731],{"class":208}," and",[163,733,734],{"class":212}," cell.font.color.type ",[163,736,737],{"class":208},"==",[163,739,740],{"class":172}," \"rgb\"",[163,742,433],{"class":208},[163,744,705],{"class":172},[163,746,535],{"class":212},[10,748,749],{},"Background colour, font colour, weight and style, borders, text alignment and wrapping all survive. Layout properties with no Excel equivalent — padding, width, hover\neffects — do not. And one very commonly used Styler feature does not carry over at all, which is the subject of the next step.",[36,751,45,756,45,759,45,762,45,765,45,768,45,774,45,780,45,784,45,788,45,792,45,796,45,801,45,806,45,810,45,813,45,816,45,819,45,822],{"viewBox":752,"role":39,"ariaLabelledBy":753,"xmlns":43,"style":44},"0 0 760 214",[754,755],"sty-support-t","sty-support-d",[47,757,758],{"id":754},"What survives Styler.to_excel",[51,760,761],{"id":755},"Background colour, font colour, bold and italic, borders, alignment and the number-format property are written to Excel. Styler.format display strings, padding, widths, captions and table-level CSS are not.",[55,763],{"x":57,"y":57,"width":58,"height":764,"fill":60},"214",[55,766],{"x":63,"y":63,"width":767,"height":64,"rx":341,"fill":133,"stroke":134,"style":69},"350",[71,769,773],{"x":770,"y":771,"style":772},"195","46","font-size:13px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","written to Excel",[83,775],{"x1":776,"y1":777,"x2":778,"y2":777,"stroke":134,"style":779},"36","56","354","stroke-width:1px",[71,781,783],{"x":770,"y":782,"style":104},"78","background-color",[71,785,787],{"x":770,"y":786,"style":104},"101","color, font-weight, font-style",[71,789,791],{"x":770,"y":790,"style":104},"124","border, text-align, white-space",[71,793,795],{"x":770,"y":794,"style":104},"147","number-format (custom CSS)",[55,797],{"x":798,"y":63,"width":767,"height":64,"rx":341,"fill":799,"stroke":800,"style":69},"390","#fee8f2","var(--accent,#f43f8f)",[71,802,805],{"x":803,"y":771,"style":804},"565","font-size:13px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","ignored in Excel",[83,807],{"x1":808,"y1":777,"x2":809,"y2":777,"stroke":800,"style":779},"406","724",[71,811,812],{"x":803,"y":782,"style":104},"Styler.format() strings",[71,814,815],{"x":803,"y":786,"style":104},"padding, width, height",[71,817,818],{"x":803,"y":790,"style":104},"captions, tooltips",[71,820,821],{"x":803,"y":794,"style":104},"table-level styles",[71,823,825],{"x":144,"y":824,"style":146},"200","if it is not a per-cell CSS property Excel understands, it is dropped",[149,827,829],{"id":828},"step-3-use-number-format-not-format","Step 3 — Use number-format, not format()",[10,831,832,835,836,840,841,844,845,848],{},[13,833,834],{},"Styler.format()"," changes how values are ",[837,838,839],"em",{},"displayed as text"," in HTML. It does not set an Excel number format, so a column formatted as ",[13,842,843],{},"{:,.2f}"," in a notebook is written\nto Excel as a raw float with the General format. The Excel equivalent is a pseudo-CSS property, ",[13,846,847],{},"number-format",", whose value is an Excel format code.",[154,850,852],{"className":199,"code":851,"language":201,"meta":159,"style":159},"formatted = (\n    sales.style\n         .set_properties(subset=[\"Revenue\"], **{\"number-format\": \"#,##0.00\"})\n         .set_properties(subset=[\"Growth\"], **{\"number-format\": \"0.0%\"})\n         .map(negative_red, subset=[\"Growth\"])\n)\nformatted.to_excel(\"formatted.xlsx\", sheet_name=\"Sales\", index=False)\n\ncheck = load_workbook(\"formatted.xlsx\")[\"Sales\"]\nprint(check[\"B2\"].number_format, check[\"C2\"].number_format)   # #,##0.00 0.0%\n",[13,853,854,863,867,895,922,936,940,966,970,987],{"__ignoreMap":159},[163,855,856,859,861],{"class":83,"line":165},[163,857,858],{"class":212},"formatted ",[163,860,235],{"class":208},[163,862,450],{"class":212},[163,864,865],{"class":83,"line":222},[163,866,455],{"class":212},[163,868,869,871,873,875,877,879,881,883,885,888,890,893],{"class":83,"line":229},[163,870,479],{"class":212},[163,872,380],{"class":463},[163,874,235],{"class":208},[163,876,468],{"class":212},[163,878,522],{"class":172},[163,880,491],{"class":212},[163,882,494],{"class":208},[163,884,497],{"class":212},[163,886,887],{"class":172},"\"number-format\"",[163,889,503],{"class":212},[163,891,892],{"class":172},"\"#,##0.00\"",[163,894,364],{"class":212},[163,896,897,899,901,903,905,907,909,911,913,915,917,920],{"class":83,"line":241},[163,898,479],{"class":212},[163,900,380],{"class":463},[163,902,235],{"class":208},[163,904,468],{"class":212},[163,906,471],{"class":172},[163,908,491],{"class":212},[163,910,494],{"class":208},[163,912,497],{"class":212},[163,914,887],{"class":172},[163,916,503],{"class":212},[163,918,919],{"class":172},"\"0.0%\"",[163,921,364],{"class":212},[163,923,924,926,928,930,932,934],{"class":83,"line":272},[163,925,460],{"class":212},[163,927,380],{"class":463},[163,929,235],{"class":208},[163,931,468],{"class":212},[163,933,471],{"class":172},[163,935,474],{"class":212},[163,937,938],{"class":83,"line":301},[163,939,535],{"class":212},[163,941,942,945,948,950,952,954,956,958,960,962,964],{"class":83,"line":333},[163,943,944],{"class":212},"formatted.to_excel(",[163,946,947],{"class":172},"\"formatted.xlsx\"",[163,949,253],{"class":212},[163,951,554],{"class":463},[163,953,235],{"class":208},[163,955,559],{"class":172},[163,957,253],{"class":212},[163,959,564],{"class":463},[163,961,235],{"class":208},[163,963,569],{"class":280},[163,965,535],{"class":212},[163,967,968],{"class":83,"line":361},[163,969,226],{"emptyLinePlaceholder":225},[163,971,972,975,977,979,981,983,985],{"class":83,"line":538},[163,973,974],{"class":212},"check ",[163,976,235],{"class":208},[163,978,634],{"class":212},[163,980,947],{"class":172},[163,982,639],{"class":212},[163,984,559],{"class":172},[163,986,644],{"class":212},[163,988,989,992,995,998,1001,1004,1007],{"class":83,"line":543},[163,990,991],{"class":280},"print",[163,993,994],{"class":212},"(check[",[163,996,997],{"class":172},"\"B2\"",[163,999,1000],{"class":212},"].number_format, check[",[163,1002,1003],{"class":172},"\"C2\"",[163,1005,1006],{"class":212},"].number_format)   ",[163,1008,1010],{"class":1009},"s-wDw","# #,##0.00 0.0%\n",[10,1012,1013,1014,1018],{},"Keeping the values numeric and applying a format code is always the better outcome: the numbers still sum, sort and chart in Excel. Formatting values into strings before\nwriting produces cells that look right and behave like text. The format codes themselves are the same ones used everywhere else on this site, collected in\n",[30,1015,1017],{"href":1016},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fapplying-number-and-date-formats-in-excel\u002Fwrite-custom-number-format-codes-in-excel-with-python\u002F","Write Custom Number Format Codes in Excel with Python",".",[149,1020,1022],{"id":1021},"step-4-gradients-and-conditional-highlights","Step 4 — Gradients and conditional highlights",[10,1024,1025,1027,1028,1031],{},[13,1026,195],{}," and ",[13,1029,1030],{},"highlight_between"," compute a colour for every cell from its value, then write those as fixed fills. The result looks like conditional formatting,\nbut it is a snapshot: the colours were decided in Python and do not change if someone edits a number in Excel.",[154,1033,1035],{"className":199,"code":1034,"language":201,"meta":159,"style":159},"heat = (\n    sales.style\n         .background_gradient(subset=[\"Revenue\"], cmap=\"Greens\")\n         .highlight_between(subset=[\"Growth\"], left=-1, right=0, color=\"#FFC7CE\")\n         .set_properties(subset=[\"Revenue\"], **{\"number-format\": \"#,##0\"})\n)\nheat.to_excel(\"heat.xlsx\", sheet_name=\"Sales\", index=False)\nprint(load_workbook(\"heat.xlsx\")[\"Sales\"][\"B4\"].fill.fgColor.rgb)\n",[13,1036,1037,1046,1050,1075,1119,1146,1150,1176],{"__ignoreMap":159},[163,1038,1039,1042,1044],{"class":83,"line":165},[163,1040,1041],{"class":212},"heat ",[163,1043,235],{"class":208},[163,1045,450],{"class":212},[163,1047,1048],{"class":83,"line":222},[163,1049,455],{"class":212},[163,1051,1052,1055,1057,1059,1061,1063,1065,1068,1070,1073],{"class":83,"line":229},[163,1053,1054],{"class":212},"         .background_gradient(",[163,1056,380],{"class":463},[163,1058,235],{"class":208},[163,1060,468],{"class":212},[163,1062,522],{"class":172},[163,1064,491],{"class":212},[163,1066,1067],{"class":463},"cmap",[163,1069,235],{"class":208},[163,1071,1072],{"class":172},"\"Greens\"",[163,1074,535],{"class":212},[163,1076,1077,1080,1082,1084,1086,1088,1090,1093,1096,1099,1101,1104,1106,1108,1110,1112,1114,1117],{"class":83,"line":241},[163,1078,1079],{"class":212},"         .highlight_between(",[163,1081,380],{"class":463},[163,1083,235],{"class":208},[163,1085,468],{"class":212},[163,1087,471],{"class":172},[163,1089,491],{"class":212},[163,1091,1092],{"class":463},"left",[163,1094,1095],{"class":208},"=-",[163,1097,1098],{"class":280},"1",[163,1100,253],{"class":212},[163,1102,1103],{"class":463},"right",[163,1105,235],{"class":208},[163,1107,57],{"class":280},[163,1109,253],{"class":212},[163,1111,527],{"class":463},[163,1113,235],{"class":208},[163,1115,1116],{"class":172},"\"#FFC7CE\"",[163,1118,535],{"class":212},[163,1120,1121,1123,1125,1127,1129,1131,1133,1135,1137,1139,1141,1144],{"class":83,"line":272},[163,1122,479],{"class":212},[163,1124,380],{"class":463},[163,1126,235],{"class":208},[163,1128,468],{"class":212},[163,1130,522],{"class":172},[163,1132,491],{"class":212},[163,1134,494],{"class":208},[163,1136,497],{"class":212},[163,1138,887],{"class":172},[163,1140,503],{"class":212},[163,1142,1143],{"class":172},"\"#,##0\"",[163,1145,364],{"class":212},[163,1147,1148],{"class":83,"line":301},[163,1149,535],{"class":212},[163,1151,1152,1155,1158,1160,1162,1164,1166,1168,1170,1172,1174],{"class":83,"line":333},[163,1153,1154],{"class":212},"heat.to_excel(",[163,1156,1157],{"class":172},"\"heat.xlsx\"",[163,1159,253],{"class":212},[163,1161,554],{"class":463},[163,1163,235],{"class":208},[163,1165,559],{"class":172},[163,1167,253],{"class":212},[163,1169,564],{"class":463},[163,1171,235],{"class":208},[163,1173,569],{"class":280},[163,1175,535],{"class":212},[163,1177,1178,1180,1183,1185,1187,1189,1192,1194],{"class":83,"line":361},[163,1179,991],{"class":280},[163,1181,1182],{"class":212},"(load_workbook(",[163,1184,1157],{"class":172},[163,1186,639],{"class":212},[163,1188,559],{"class":172},[163,1190,1191],{"class":212},"][",[163,1193,666],{"class":172},[163,1195,1196],{"class":212},"].fill.fgColor.rgb)\n",[10,1198,1199,1200,1202,1203,1018],{},"When more than one method styles the same cell, the later CSS wins for each property. ",[13,1201,195],{}," also sets a contrasting text colour automatically on dark fills,\nwhich is usually what you want. If the workbook will be edited after it is sent, use real conditional formatting instead, so the colours follow the data — see\n",[30,1204,1206],{"href":1205},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fapply-conditional-formatting-with-xlsxwriter\u002F","Apply Conditional Formatting with xlsxwriter",[36,1208,45,1214,45,1217,45,1220,45,1224,45,1227,45,1230,45,1236,45,1239,45,1243,45,1246,45,1250,45,1254,45,1258,45,1260,45,1264,45,1266,45,1269,45,1271,45,1274,45,1276,45,1279,45,1281,45,1284,45,1286,45,1289,45,1291,45,1294,45,1296,45,1299,45,1301,45,1304,45,1306,45,1308,45,1311,45,1315,45,1317,45,1320,45,1322,45,1325,45,1327,45,1331,45,1333,45,1335,45,1341,45,1346,45,1349,45,1353,45,1355,45,1358,45,1360,45,1364,45,1366,45,1369,45,1371,45,1373,45,1376,45,1380,45,1383,45,1387,45,1389,45,1392,45,1394,45,1397,45,1399,45,1402,45,1404,45,1406],{"viewBox":1209,"role":39,"ariaLabelledBy":1210,"xmlns":43,"style":1213},"0 0 566 254",[1211,1212],"sty-result-t","sty-result-d","width:100%;max-width:566px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[47,1215,1216],{"id":1211},"The written sheet with Styler colours and formats",[51,1218,1219],{"id":1212},"Region names are bold, the highest revenue is highlighted green, negative growth values are pink, and revenue and growth carry Excel number formats rather than text.",[55,1221],{"x":57,"y":57,"width":1222,"height":1223,"fill":60},"566","254",[55,1225],{"x":63,"y":63,"width":776,"height":1226,"rx":57,"fill":67,"stroke":68,"style":779},"30",[55,1228],{"x":777,"y":63,"width":1229,"height":1226,"rx":57,"fill":67,"stroke":68,"style":779},"80",[71,1231,1235],{"x":1232,"y":1233,"style":1234},"96","40","font-size:11.5px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","A",[55,1237],{"x":59,"y":63,"width":1238,"height":1226,"rx":57,"fill":67,"stroke":68,"style":779},"100",[71,1240,1242],{"x":1241,"y":1233,"style":1234},"186","B",[55,1244],{"x":1245,"y":63,"width":1229,"height":1226,"rx":57,"fill":67,"stroke":68,"style":779},"236",[71,1247,1249],{"x":1248,"y":1233,"style":1234},"276","C",[55,1251],{"x":1252,"y":63,"width":1253,"height":1226,"rx":57,"fill":67,"stroke":68,"style":779},"316","60",[71,1255,1257],{"x":1256,"y":1233,"style":1234},"346","D",[55,1259],{"x":63,"y":74,"width":776,"height":1226,"rx":57,"fill":67,"stroke":68,"style":779},[71,1261,1098],{"x":1262,"y":1263,"style":1234},"38","70",[55,1265],{"x":777,"y":74,"width":1229,"height":1226,"rx":57,"fill":67,"stroke":68,"style":779},[71,1267,1268],{"x":1232,"y":1263,"style":80},"Region",[55,1270],{"x":59,"y":74,"width":1238,"height":1226,"rx":57,"fill":67,"stroke":68,"style":779},[71,1272,1273],{"x":1241,"y":1263,"style":80},"Revenue",[55,1275],{"x":1245,"y":74,"width":1229,"height":1226,"rx":57,"fill":67,"stroke":68,"style":779},[71,1277,1278],{"x":1248,"y":1263,"style":80},"Growth",[55,1280],{"x":1252,"y":74,"width":1253,"height":1226,"rx":57,"fill":67,"stroke":68,"style":779},[71,1282,1283],{"x":1256,"y":1263,"style":80},"Deals",[55,1285],{"x":63,"y":1229,"width":776,"height":1226,"rx":57,"fill":67,"stroke":68,"style":779},[71,1287,1288],{"x":1262,"y":1238,"style":1234},"2",[55,1290],{"x":777,"y":1229,"width":1229,"height":1226,"rx":57,"fill":60,"stroke":68,"style":779},[71,1292,1293],{"x":1232,"y":1238,"style":104},"North",[55,1295],{"x":59,"y":1229,"width":1238,"height":1226,"rx":57,"fill":60,"stroke":68,"style":779},[71,1297,1298],{"x":1241,"y":1238,"style":104},"120,500",[55,1300],{"x":1245,"y":1229,"width":1229,"height":1226,"rx":57,"fill":60,"stroke":68,"style":779},[71,1302,1303],{"x":1248,"y":1238,"style":104},"12.0%",[55,1305],{"x":1252,"y":1229,"width":1253,"height":1226,"rx":57,"fill":60,"stroke":68,"style":779},[71,1307,341],{"x":1256,"y":1238,"style":104},[55,1309],{"x":63,"y":1310,"width":776,"height":1226,"rx":57,"fill":67,"stroke":68,"style":779},"110",[71,1312,1314],{"x":1262,"y":1313,"style":1234},"130","3",[55,1316],{"x":777,"y":1310,"width":1229,"height":1226,"rx":57,"fill":60,"stroke":68,"style":779},[71,1318,1319],{"x":1232,"y":1313,"style":104},"South",[55,1321],{"x":59,"y":1310,"width":1238,"height":1226,"rx":57,"fill":60,"stroke":68,"style":779},[71,1323,1324],{"x":1241,"y":1313,"style":104},"98,201",[55,1326],{"x":1245,"y":1310,"width":1229,"height":1226,"rx":57,"fill":799,"stroke":800,"style":779},[71,1328,1330],{"x":1248,"y":1313,"style":1329},"font-size:11.5px;font-weight:600;fill:var(--accent-ink,#be185d);text-anchor:middle","-3.4%",[55,1332],{"x":1252,"y":1310,"width":1253,"height":1226,"rx":57,"fill":60,"stroke":68,"style":779},[71,1334,346],{"x":1256,"y":1313,"style":104},[55,1336],{"x":1337,"y":1338,"width":64,"height":1339,"rx":1340,"fill":799,"stroke":800,"style":779},"396","112","26","8",[71,1342,1345],{"x":1343,"y":1344,"style":1329},"471","129","negative: pink fill",[55,1347],{"x":63,"y":1348,"width":776,"height":1226,"rx":57,"fill":67,"stroke":68,"style":779},"140",[71,1350,1352],{"x":1262,"y":1351,"style":1234},"160","4",[55,1354],{"x":777,"y":1348,"width":1229,"height":1226,"rx":57,"fill":60,"stroke":68,"style":779},[71,1356,1357],{"x":1232,"y":1351,"style":104},"East",[55,1359],{"x":59,"y":1348,"width":1238,"height":1226,"rx":57,"fill":133,"stroke":134,"style":779},[71,1361,1363],{"x":1241,"y":1351,"style":1362},"font-size:11.5px;font-weight:600;fill:var(--teal-ink,#0b6157);text-anchor:middle","143,900",[55,1365],{"x":1245,"y":1348,"width":1229,"height":1226,"rx":57,"fill":60,"stroke":68,"style":779},[71,1367,1368],{"x":1248,"y":1351,"style":104},"8.1%",[55,1370],{"x":1252,"y":1348,"width":1253,"height":1226,"rx":57,"fill":60,"stroke":68,"style":779},[71,1372,351],{"x":1256,"y":1351,"style":104},[55,1374],{"x":1337,"y":1375,"width":64,"height":1339,"rx":1340,"fill":133,"stroke":134,"style":779},"142",[71,1377,1379],{"x":1343,"y":1378,"style":1362},"159","highest: green",[55,1381],{"x":63,"y":1382,"width":776,"height":1226,"rx":57,"fill":67,"stroke":68,"style":779},"170",[71,1384,1386],{"x":1262,"y":1385,"style":1234},"190","5",[55,1388],{"x":777,"y":1382,"width":1229,"height":1226,"rx":57,"fill":60,"stroke":68,"style":779},[71,1390,1391],{"x":1232,"y":1385,"style":104},"West",[55,1393],{"x":59,"y":1382,"width":1238,"height":1226,"rx":57,"fill":60,"stroke":68,"style":779},[71,1395,1396],{"x":1241,"y":1385,"style":104},"87,150",[55,1398],{"x":1245,"y":1382,"width":1229,"height":1226,"rx":57,"fill":799,"stroke":800,"style":779},[71,1400,1401],{"x":1248,"y":1385,"style":1329},"-12.0%",[55,1403],{"x":1252,"y":1382,"width":1253,"height":1226,"rx":57,"fill":60,"stroke":68,"style":779},[71,1405,356],{"x":1256,"y":1385,"style":104},[71,1407,1410],{"x":1408,"y":1409,"style":146},"283","232","fills are fixed at write time; values stay numeric",[149,1412,1414],{"id":1413},"step-5-style-headers-and-the-index","Step 5 — Style headers and the index",[10,1416,1417,1418,1421,1422,1424,1425,1428],{},"Styler styles ",[837,1419,1420],{},"data"," cells by default. The header row written by ",[13,1423,27],{}," gets pandas' own bold, bordered header style, which you can change with ",[13,1426,1427],{},"apply_index"," on the\ncolumn labels. It takes a function that receives the labels and returns CSS for each.",[154,1430,1432],{"className":199,"code":1431,"language":201,"meta":159,"style":159},"def header_style(labels: pd.Index) -> list[str]:\n    return [\"background-color: #4338ca; color: #ffffff; font-weight: bold\" for _ in labels]\n\nreport = (\n    sales.style\n         .apply_index(header_style, axis=\"columns\")\n         .set_properties(subset=[\"Revenue\"], **{\"number-format\": \"#,##0\"})\n)\nreport.to_excel(\"headers.xlsx\", sheet_name=\"Sales\", index=False)\nprint(load_workbook(\"headers.xlsx\")[\"Sales\"][\"A1\"].fill.fgColor.rgb)\n",[13,1433,1434,1449,1470,1474,1483,1487,1502,1528,1532,1558],{"__ignoreMap":159},[163,1435,1436,1438,1441,1444,1446],{"class":83,"line":165},[163,1437,391],{"class":208},[163,1439,1440],{"class":394}," header_style",[163,1442,1443],{"class":212},"(labels: pd.Index) -> list[",[163,1445,407],{"class":280},[163,1447,1448],{"class":212},"]:\n",[163,1450,1451,1453,1456,1459,1462,1465,1467],{"class":83,"line":222},[163,1452,415],{"class":208},[163,1454,1455],{"class":212}," [",[163,1457,1458],{"class":172},"\"background-color: #4338ca; color: #ffffff; font-weight: bold\"",[163,1460,1461],{"class":208}," for",[163,1463,1464],{"class":212}," _ ",[163,1466,655],{"class":208},[163,1468,1469],{"class":212}," labels]\n",[163,1471,1472],{"class":83,"line":229},[163,1473,226],{"emptyLinePlaceholder":225},[163,1475,1476,1479,1481],{"class":83,"line":241},[163,1477,1478],{"class":212},"report ",[163,1480,235],{"class":208},[163,1482,450],{"class":212},[163,1484,1485],{"class":83,"line":272},[163,1486,455],{"class":212},[163,1488,1489,1492,1495,1497,1500],{"class":83,"line":301},[163,1490,1491],{"class":212},"         .apply_index(header_style, ",[163,1493,1494],{"class":463},"axis",[163,1496,235],{"class":208},[163,1498,1499],{"class":172},"\"columns\"",[163,1501,535],{"class":212},[163,1503,1504,1506,1508,1510,1512,1514,1516,1518,1520,1522,1524,1526],{"class":83,"line":333},[163,1505,479],{"class":212},[163,1507,380],{"class":463},[163,1509,235],{"class":208},[163,1511,468],{"class":212},[163,1513,522],{"class":172},[163,1515,491],{"class":212},[163,1517,494],{"class":208},[163,1519,497],{"class":212},[163,1521,887],{"class":172},[163,1523,503],{"class":212},[163,1525,1143],{"class":172},[163,1527,364],{"class":212},[163,1529,1530],{"class":83,"line":361},[163,1531,535],{"class":212},[163,1533,1534,1537,1540,1542,1544,1546,1548,1550,1552,1554,1556],{"class":83,"line":538},[163,1535,1536],{"class":212},"report.to_excel(",[163,1538,1539],{"class":172},"\"headers.xlsx\"",[163,1541,253],{"class":212},[163,1543,554],{"class":463},[163,1545,235],{"class":208},[163,1547,559],{"class":172},[163,1549,253],{"class":212},[163,1551,564],{"class":463},[163,1553,235],{"class":208},[163,1555,569],{"class":280},[163,1557,535],{"class":212},[163,1559,1560,1562,1564,1566,1568,1570,1572,1575],{"class":83,"line":543},[163,1561,991],{"class":280},[163,1563,1182],{"class":212},[163,1565,1539],{"class":172},[163,1567,639],{"class":212},[163,1569,559],{"class":172},[163,1571,1191],{"class":212},[163,1573,1574],{"class":172},"\"A1\"",[163,1576,1196],{"class":212},[10,1578,1579,1580,253,1583,1586,1587,1018],{},"With ",[13,1581,1582],{},"index=True",[13,1584,1585],{},"apply_index(axis=\"index\")"," styles the row labels the same way. Column widths are not something Styler controls; set them afterwards with openpyxl, or\nuse the approach in ",[30,1588,1590],{"href":1589},"\u002Fgetting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas\u002Fauto-fit-column-widths-when-writing-with-pandas\u002F","Auto-Fit Column Widths When Writing with pandas",[149,1592,1594],{"id":1593},"step-6-write-several-styled-frames-into-one-workbook","Step 6 — Write several styled frames into one workbook",[10,1596,1597,1600,1601,1604,1605,1608],{},[13,1598,1599],{},"Styler.to_excel"," accepts an ",[13,1602,1603],{},"ExcelWriter"," just like ",[13,1606,1607],{},"DataFrame.to_excel",", so a multi-sheet report can mix styled and plain sheets, and post-processing — freezing panes,\nsetting widths — can happen on the same writer before it closes.",[154,1610,1612],{"className":199,"code":1611,"language":201,"meta":159,"style":159},"summary = sales.groupby(sales[\"Growth\"] >= 0).agg(Regions=(\"Region\", \"count\"), Revenue=(\"Revenue\", \"sum\"))\nsummary.index = [\"Shrinking\", \"Growing\"]\n\nwith pd.ExcelWriter(\"report.xlsx\", engine=\"openpyxl\") as writer:\n    heat.to_excel(writer, sheet_name=\"Detail\", index=False)\n    summary.style.set_properties(**{\"number-format\": \"#,##0\"}).to_excel(writer, sheet_name=\"Summary\")\n    detail = writer.sheets[\"Detail\"]\n    detail.freeze_panes = \"A2\"\n    detail.column_dimensions[\"B\"].width = 14\n\nprint(load_workbook(\"report.xlsx\").sheetnames)\n",[13,1613,1614,1671,1690,1694,1721,1743,1770,1784,1794,1810,1814],{"__ignoreMap":159},[163,1615,1616,1619,1621,1624,1626,1629,1632,1634,1637,1640,1642,1645,1647,1649,1652,1655,1657,1659,1661,1663,1665,1668],{"class":83,"line":165},[163,1617,1618],{"class":212},"summary ",[163,1620,235],{"class":208},[163,1622,1623],{"class":212}," sales.groupby(sales[",[163,1625,471],{"class":172},[163,1627,1628],{"class":212},"] ",[163,1630,1631],{"class":208},">=",[163,1633,430],{"class":280},[163,1635,1636],{"class":212},").agg(",[163,1638,1639],{"class":463},"Regions",[163,1641,235],{"class":208},[163,1643,1644],{"class":212},"(",[163,1646,488],{"class":172},[163,1648,253],{"class":212},[163,1650,1651],{"class":172},"\"count\"",[163,1653,1654],{"class":212},"), ",[163,1656,1273],{"class":463},[163,1658,235],{"class":208},[163,1660,1644],{"class":212},[163,1662,522],{"class":172},[163,1664,253],{"class":212},[163,1666,1667],{"class":172},"\"sum\"",[163,1669,1670],{"class":212},"))\n",[163,1672,1673,1676,1678,1680,1683,1685,1688],{"class":83,"line":222},[163,1674,1675],{"class":212},"summary.index ",[163,1677,235],{"class":208},[163,1679,1455],{"class":212},[163,1681,1682],{"class":172},"\"Shrinking\"",[163,1684,253],{"class":212},[163,1686,1687],{"class":172},"\"Growing\"",[163,1689,644],{"class":212},[163,1691,1692],{"class":83,"line":229},[163,1693,226],{"emptyLinePlaceholder":225},[163,1695,1696,1699,1702,1705,1707,1709,1711,1713,1716,1718],{"class":83,"line":241},[163,1697,1698],{"class":208},"with",[163,1700,1701],{"class":212}," pd.ExcelWriter(",[163,1703,1704],{"class":172},"\"report.xlsx\"",[163,1706,253],{"class":212},[163,1708,574],{"class":463},[163,1710,235],{"class":208},[163,1712,579],{"class":172},[163,1714,1715],{"class":212},") ",[163,1717,216],{"class":208},[163,1719,1720],{"class":212}," writer:\n",[163,1722,1723,1726,1728,1730,1733,1735,1737,1739,1741],{"class":83,"line":272},[163,1724,1725],{"class":212},"    heat.to_excel(writer, ",[163,1727,554],{"class":463},[163,1729,235],{"class":208},[163,1731,1732],{"class":172},"\"Detail\"",[163,1734,253],{"class":212},[163,1736,564],{"class":463},[163,1738,235],{"class":208},[163,1740,569],{"class":280},[163,1742,535],{"class":212},[163,1744,1745,1748,1750,1752,1754,1756,1758,1761,1763,1765,1768],{"class":83,"line":301},[163,1746,1747],{"class":212},"    summary.style.set_properties(",[163,1749,494],{"class":208},[163,1751,497],{"class":212},[163,1753,887],{"class":172},[163,1755,503],{"class":212},[163,1757,1143],{"class":172},[163,1759,1760],{"class":212},"}).to_excel(writer, ",[163,1762,554],{"class":463},[163,1764,235],{"class":208},[163,1766,1767],{"class":172},"\"Summary\"",[163,1769,535],{"class":212},[163,1771,1772,1775,1777,1780,1782],{"class":83,"line":333},[163,1773,1774],{"class":212},"    detail ",[163,1776,235],{"class":208},[163,1778,1779],{"class":212}," writer.sheets[",[163,1781,1732],{"class":172},[163,1783,644],{"class":212},[163,1785,1786,1789,1791],{"class":83,"line":361},[163,1787,1788],{"class":212},"    detail.freeze_panes ",[163,1790,235],{"class":208},[163,1792,1793],{"class":172}," \"A2\"\n",[163,1795,1796,1799,1802,1805,1807],{"class":83,"line":538},[163,1797,1798],{"class":212},"    detail.column_dimensions[",[163,1800,1801],{"class":172},"\"B\"",[163,1803,1804],{"class":212},"].width ",[163,1806,235],{"class":208},[163,1808,1809],{"class":280}," 14\n",[163,1811,1812],{"class":83,"line":543},[163,1813,226],{"emptyLinePlaceholder":225},[163,1815,1817,1819,1821,1823],{"class":83,"line":1816},11,[163,1818,991],{"class":280},[163,1820,1182],{"class":212},[163,1822,1704],{"class":172},[163,1824,1825],{"class":212},").sheetnames)\n",[10,1827,1828,1831],{},[13,1829,1830],{},"writer.sheets"," exposes the underlying openpyxl worksheets while the writer is open, which is the hook for anything Styler cannot express.",[149,1833,1835],{"id":1834},"step-7-borders-alignment-and-a-reusable-table-style","Step 7 — Borders, alignment and a reusable table style",[10,1837,1838],{},"A report looks finished when numbers are right-aligned, text wraps where it should and rows are separated by a light rule. Those are all CSS properties the\nconverter understands, so they can live in one function that every export in a project applies. Keeping the palette and rules in one place is the Styler\nversion of a house style.",[154,1840,1842],{"className":199,"code":1841,"language":201,"meta":159,"style":159},"BASE = {\n    \"border-bottom\": \"1px solid #cdd5e6\",\n    \"font-family\": \"Calibri\",\n}\nNUMERIC = {**BASE, \"text-align\": \"right\"}\nTEXT = {**BASE, \"text-align\": \"left\", \"white-space\": \"normal\"}\n\ndef house_style(frame: pd.DataFrame, formats: dict[str, str]):\n    numeric_cols = list(frame.select_dtypes(\"number\").columns)\n    text_cols = [c for c in frame.columns if c not in numeric_cols]\n    styler = (\n        frame.style\n             .set_properties(subset=numeric_cols, **NUMERIC)\n             .set_properties(subset=text_cols, **TEXT)\n             .apply_index(header_style, axis=\"columns\")\n    )\n    for column, code in formats.items():\n        styler = styler.set_properties(subset=[column], **{\"number-format\": code})\n    return styler\n\nhouse_style(sales, {\"Revenue\": \"#,##0\", \"Growth\": \"0.0%\"}).to_excel(\"house.xlsx\", index=False)\ncell = load_workbook(\"house.xlsx\").active[\"B2\"]\nprint(cell.alignment.horizontal, cell.border.bottom.style, cell.number_format)\n",[13,1843,1844,1855,1868,1880,1885,1911,1945,1949,1968,1987,2020,2029,2035,2054,2072,2086,2092,2106,2133,2141,2146,2182,2201],{"__ignoreMap":159},[163,1845,1846,1849,1852],{"class":83,"line":165},[163,1847,1848],{"class":280},"BASE",[163,1850,1851],{"class":208}," =",[163,1853,1854],{"class":212}," {\n",[163,1856,1857,1860,1862,1865],{"class":83,"line":222},[163,1858,1859],{"class":172},"    \"border-bottom\"",[163,1861,503],{"class":212},[163,1863,1864],{"class":172},"\"1px solid #cdd5e6\"",[163,1866,1867],{"class":212},",\n",[163,1869,1870,1873,1875,1878],{"class":83,"line":229},[163,1871,1872],{"class":172},"    \"font-family\"",[163,1874,503],{"class":212},[163,1876,1877],{"class":172},"\"Calibri\"",[163,1879,1867],{"class":212},[163,1881,1882],{"class":83,"line":241},[163,1883,1884],{"class":212},"}\n",[163,1886,1887,1890,1892,1895,1897,1899,1901,1904,1906,1909],{"class":83,"line":272},[163,1888,1889],{"class":280},"NUMERIC",[163,1891,1851],{"class":208},[163,1893,1894],{"class":212}," {",[163,1896,494],{"class":208},[163,1898,1848],{"class":280},[163,1900,253],{"class":212},[163,1902,1903],{"class":172},"\"text-align\"",[163,1905,503],{"class":212},[163,1907,1908],{"class":172},"\"right\"",[163,1910,1884],{"class":212},[163,1912,1913,1916,1918,1920,1922,1924,1926,1928,1930,1933,1935,1938,1940,1943],{"class":83,"line":301},[163,1914,1915],{"class":280},"TEXT",[163,1917,1851],{"class":208},[163,1919,1894],{"class":212},[163,1921,494],{"class":208},[163,1923,1848],{"class":280},[163,1925,253],{"class":212},[163,1927,1903],{"class":172},[163,1929,503],{"class":212},[163,1931,1932],{"class":172},"\"left\"",[163,1934,253],{"class":212},[163,1936,1937],{"class":172},"\"white-space\"",[163,1939,503],{"class":212},[163,1941,1942],{"class":172},"\"normal\"",[163,1944,1884],{"class":212},[163,1946,1947],{"class":83,"line":333},[163,1948,226],{"emptyLinePlaceholder":225},[163,1950,1951,1953,1956,1959,1961,1963,1965],{"class":83,"line":361},[163,1952,391],{"class":208},[163,1954,1955],{"class":394}," house_style",[163,1957,1958],{"class":212},"(frame: pd.DataFrame, formats: dict[",[163,1960,407],{"class":280},[163,1962,253],{"class":212},[163,1964,407],{"class":280},[163,1966,1967],{"class":212},"]):\n",[163,1969,1970,1973,1975,1978,1981,1984],{"class":83,"line":538},[163,1971,1972],{"class":212},"    numeric_cols ",[163,1974,235],{"class":208},[163,1976,1977],{"class":280}," list",[163,1979,1980],{"class":212},"(frame.select_dtypes(",[163,1982,1983],{"class":172},"\"number\"",[163,1985,1986],{"class":212},").columns)\n",[163,1988,1989,1992,1994,1997,1999,2002,2004,2007,2009,2011,2014,2017],{"class":83,"line":543},[163,1990,1991],{"class":212},"    text_cols ",[163,1993,235],{"class":208},[163,1995,1996],{"class":212}," [c ",[163,1998,649],{"class":208},[163,2000,2001],{"class":212}," c ",[163,2003,655],{"class":208},[163,2005,2006],{"class":212}," frame.columns ",[163,2008,716],{"class":208},[163,2010,2001],{"class":212},[163,2012,2013],{"class":208},"not",[163,2015,2016],{"class":208}," in",[163,2018,2019],{"class":212}," numeric_cols]\n",[163,2021,2022,2025,2027],{"class":83,"line":1816},[163,2023,2024],{"class":212},"    styler ",[163,2026,235],{"class":208},[163,2028,450],{"class":212},[163,2030,2032],{"class":83,"line":2031},12,[163,2033,2034],{"class":212},"        frame.style\n",[163,2036,2038,2041,2043,2045,2048,2050,2052],{"class":83,"line":2037},13,[163,2039,2040],{"class":212},"             .set_properties(",[163,2042,380],{"class":463},[163,2044,235],{"class":208},[163,2046,2047],{"class":212},"numeric_cols, ",[163,2049,494],{"class":208},[163,2051,1889],{"class":280},[163,2053,535],{"class":212},[163,2055,2057,2059,2061,2063,2066,2068,2070],{"class":83,"line":2056},14,[163,2058,2040],{"class":212},[163,2060,380],{"class":463},[163,2062,235],{"class":208},[163,2064,2065],{"class":212},"text_cols, ",[163,2067,494],{"class":208},[163,2069,1915],{"class":280},[163,2071,535],{"class":212},[163,2073,2075,2078,2080,2082,2084],{"class":83,"line":2074},15,[163,2076,2077],{"class":212},"             .apply_index(header_style, ",[163,2079,1494],{"class":463},[163,2081,235],{"class":208},[163,2083,1499],{"class":172},[163,2085,535],{"class":212},[163,2087,2089],{"class":83,"line":2088},16,[163,2090,2091],{"class":212},"    )\n",[163,2093,2095,2098,2101,2103],{"class":83,"line":2094},17,[163,2096,2097],{"class":208},"    for",[163,2099,2100],{"class":212}," column, code ",[163,2102,655],{"class":208},[163,2104,2105],{"class":212}," formats.items():\n",[163,2107,2109,2112,2114,2117,2119,2121,2124,2126,2128,2130],{"class":83,"line":2108},18,[163,2110,2111],{"class":212},"        styler ",[163,2113,235],{"class":208},[163,2115,2116],{"class":212}," styler.set_properties(",[163,2118,380],{"class":463},[163,2120,235],{"class":208},[163,2122,2123],{"class":212},"[column], ",[163,2125,494],{"class":208},[163,2127,497],{"class":212},[163,2129,887],{"class":172},[163,2131,2132],{"class":212},": code})\n",[163,2134,2136,2138],{"class":83,"line":2135},19,[163,2137,415],{"class":208},[163,2139,2140],{"class":212}," styler\n",[163,2142,2144],{"class":83,"line":2143},20,[163,2145,226],{"emptyLinePlaceholder":225},[163,2147,2149,2152,2154,2156,2158,2160,2162,2164,2166,2169,2172,2174,2176,2178,2180],{"class":83,"line":2148},21,[163,2150,2151],{"class":212},"house_style(sales, {",[163,2153,522],{"class":172},[163,2155,503],{"class":212},[163,2157,1143],{"class":172},[163,2159,253],{"class":212},[163,2161,471],{"class":172},[163,2163,503],{"class":212},[163,2165,919],{"class":172},[163,2167,2168],{"class":212},"}).to_excel(",[163,2170,2171],{"class":172},"\"house.xlsx\"",[163,2173,253],{"class":212},[163,2175,564],{"class":463},[163,2177,235],{"class":208},[163,2179,569],{"class":280},[163,2181,535],{"class":212},[163,2183,2185,2188,2190,2192,2194,2197,2199],{"class":83,"line":2184},22,[163,2186,2187],{"class":212},"cell ",[163,2189,235],{"class":208},[163,2191,634],{"class":212},[163,2193,2171],{"class":172},[163,2195,2196],{"class":212},").active[",[163,2198,997],{"class":172},[163,2200,644],{"class":212},[163,2202,2204,2206],{"class":83,"line":2203},23,[163,2205,991],{"class":280},[163,2207,2208],{"class":212},"(cell.alignment.horizontal, cell.border.bottom.style, cell.number_format)\n",[10,2210,2211,2212,2215,2216,2218],{},"Each ",[13,2213,2214],{},"set_properties"," call adds to the CSS already attached to those cells, so the number formats layered on at the end combine with the alignment and borders\nrather than replacing them. A one-pixel CSS border becomes Excel's thin border style, which is the lightest rule Excel draws. When a style guide calls for more —\nbanded rows, a totals row with a double top border — build it the same way with ",[13,2217,594],{}," and a function that returns CSS per row position.",[149,2220,2222],{"id":2221},"common-pitfalls","Common pitfalls",[2224,2225,2226,2242],"table",{},[2227,2228,2229],"thead",{},[2230,2231,2232,2236,2239],"tr",{},[2233,2234,2235],"th",{},"Symptom",[2233,2237,2238],{},"Cause",[2233,2240,2241],{},"Fix",[2243,2244,2245,2262,2277,2288,2299,2320],"tbody",{},[2230,2246,2247,2251,2256],{},[2248,2249,2250],"td",{},"Numbers unformatted in Excel",[2248,2252,2253,2254],{},"Used ",[13,2255,834],{},[2248,2257,2258,2259,2261],{},"Use the ",[13,2260,847],{}," CSS property",[2230,2263,2264,2269,2272],{},[2248,2265,2266],{},[13,2267,2268],{},"ImportError: jinja2",[2248,2270,2271],{},"Styler dependency missing",[2248,2273,2274],{},[13,2275,2276],{},"pip install jinja2",[2230,2278,2279,2282,2285],{},[2248,2280,2281],{},"Gradient colours do not update after edits",[2248,2283,2284],{},"Fills are computed once in Python",[2248,2286,2287],{},"Use Excel conditional formatting instead",[2230,2289,2290,2293,2296],{},[2248,2291,2292],{},"Some styling silently missing",[2248,2294,2295],{},"CSS property with no Excel mapping",[2248,2297,2298],{},"Stick to colours, fonts, borders, alignment",[2230,2300,2301,2309,2315],{},[2248,2302,2303,2305,2306],{},[13,2304,590],{}," warns or raises ",[13,2307,2308],{},"AttributeError",[2248,2310,2311,2312,2314],{},"Renamed to ",[13,2313,586],{}," in pandas 2.1, later removed",[2248,2316,2317,2318],{},"Use ",[13,2319,586],{},[2230,2321,2322,2325,2328],{},[2248,2323,2324],{},"Colour names not recognised",[2248,2326,2327],{},"Unusual CSS colour keyword",[2248,2329,2330,2331],{},"Use hex codes like ",[13,2332,2333],{},"#C6EFCE",[149,2335,2337],{"id":2336},"performance-and-scale-notes","Performance and scale notes",[10,2339,2340,2341,2343,2344,1018],{},"Styler builds CSS for every cell and the Excel writer converts each distinct style, so styled exports are noticeably slower than plain ",[13,2342,27],{}," — fine for summary tables of\nhundreds or a few thousand rows, sluggish for hundreds of thousands. For large sheets, write plain values and apply formatting per column with xlsxwriter formats, or add\nconditional formatting rules that cover whole ranges in a single definition. Both are covered in\n",[30,2345,2347],{"href":2346},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002F","Building Excel Reports with XlsxWriter",[10,2349,2350,2351,2353],{},"A practical split that works well: style the summary sheets of a report with Styler, where the tables are small and the styling is detailed, and write the\ndetail sheets with plain ",[13,2352,27],{}," plus a handful of column formats. Readers look closely at the summary, and the detail sheet is mostly filtered and searched,\nso the detailed styling budget is spent where it is seen.",[149,2355,2357],{"id":2356},"conclusion","Conclusion",[10,2359,2360,2363,2364,2366,2367,2369,2370,2372],{},[13,2361,2362],{},"df.style.….to_excel()"," is the quickest way to get colours, bold text and highlights into a pandas export. Colours, fonts, borders and alignment translate into real Excel\nstyles; ",[13,2365,834],{}," does not, so set Excel number formats with the ",[13,2368,847],{}," property and keep values numeric. Treat gradients and highlights as fixed snapshots,\nstyle headers with ",[13,2371,1427],{},", and hand off to openpyxl through the writer for widths and panes. When the table is large or the colours must follow future edits, switch to\nxlsxwriter formats and conditional formatting.",[149,2374,2376],{"id":2375},"frequently-asked-questions","Frequently asked questions",[10,2378,2379,2383],{},[2380,2381,2382],"strong",{},"Why does my Styler format not show in Excel?","\nStyler.format only changes the text shown in HTML output. Excel needs a number format code, which you set with set_properties and the number-format CSS property.",[10,2385,2386,2389],{},[2380,2387,2388],{},"Does Styler.to_excel work with the xlsxwriter engine?","\nYes. Both openpyxl and xlsxwriter engines convert the supported CSS into Excel formats, so choose the engine for its other features.",[10,2391,2392,2395],{},[2380,2393,2394],{},"Can Styler create real conditional formatting rules?","\nNo. Every colour is computed in Python and written as a fixed fill. Use xlsxwriter's conditional_format or openpyxl's conditional formatting rules for colours that react to edits.",[10,2397,2398,2401],{},[2380,2399,2400],{},"Can I set column widths with Styler?","\nNo. Width is not converted to Excel. Set column widths through the ExcelWriter's sheets after writing, with openpyxl column_dimensions or xlsxwriter set_column.",[149,2403,2405],{"id":2404},"related","Related",[2407,2408,2409,2416,2423,2430,2437],"ul",{},[2410,2411,2412,2413,2415],"li",{},"Up one level: ",[30,2414,33],{"href":32}," — every option for getting frames into workbooks.",[2410,2417,2418,2422],{},[30,2419,2421],{"href":2420},"\u002Fautomating-reporting-workflows\u002Fbuilding-multi-sheet-excel-dashboards\u002Fwrite-multiple-dataframes-to-one-excel-file\u002F","Write Multiple DataFrames to One Excel File"," — multi-sheet writers in depth.",[2410,2424,2425,2429],{},[30,2426,2428],{"href":2427},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002F","Styling Excel Cells with openpyxl"," — full control over every style property.",[2410,2431,2432,2436],{},[30,2433,2435],{"href":2434},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fhighlight-cells-above-a-threshold-with-openpyxl\u002F","Highlight Cells Above a Threshold with openpyxl"," — colours that follow the data.",[2410,2438,2439,2443],{},[30,2440,2442],{"href":2441},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fapplying-number-and-date-formats-in-excel\u002Fformat-numbers-as-percentages-in-excel-with-python\u002F","Format Numbers as Percentages in Excel with Python"," — number formats for ratios.",[2445,2446,2447],"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 .s_Opv, html code.shiki .s_Opv{--shiki-default:#6F42C1;--shiki-dark:#DBB7FF}html pre.shiki code .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html pre.shiki code .s-wDw, html code.shiki .s-wDw{--shiki-default:#6A737D;--shiki-dark:#BDC4CC}",{"title":159,"searchDepth":222,"depth":222,"links":2449},[2450,2451,2452,2453,2454,2455,2456,2457,2458,2459,2460,2461,2462],{"id":151,"depth":222,"text":152},{"id":367,"depth":222,"text":368},{"id":598,"depth":222,"text":599},{"id":828,"depth":222,"text":829},{"id":1021,"depth":222,"text":1022},{"id":1413,"depth":222,"text":1414},{"id":1593,"depth":222,"text":1594},{"id":1834,"depth":222,"text":1835},{"id":2221,"depth":222,"text":2222},{"id":2336,"depth":222,"text":2337},{"id":2356,"depth":222,"text":2357},{"id":2375,"depth":222,"text":2376},{"id":2404,"depth":222,"text":2405},"2026-09-17","Use pandas Styler to colour, bold and highlight a DataFrame, then write it to Excel with the styles intact — and learn which Styler features survive the trip, including why format() does not and what to use instead.","md",[2467,2469,2471,2473],{"q":2382,"a":2468},"Styler.format only changes the text shown in HTML output. Excel needs a number format code, which you set with set_properties and the number-format CSS property.",{"q":2388,"a":2470},"Yes. Both openpyxl and xlsxwriter engines convert the supported CSS into Excel formats, so choose the engine for its other features.",{"q":2394,"a":2472},"No. Every colour is computed in Python and written as a fixed fill. Use xlsxwriter's conditional_format or openpyxl's conditional formatting rules for colours that react to edits.",{"q":2400,"a":2474},"No. Width is not converted to Excel. Set column widths through the ExcelWriter's sheets after writing, with openpyxl column_dimensions or xlsxwriter set_column.","export a styled pandas dataframe to excel",null,{"breadcrumb":2478},[2479,2482,2485],{"name":2480,"item":2481},"Home","\u002F",{"name":2483,"item":2484},"Getting Started with Python Excel Automation","\u002Fgetting-started-with-python-excel-automation\u002F",{"name":33,"item":32},"\u002Fgetting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas\u002Fexport-a-styled-pandas-dataframe-to-excel",{"title":2488,"description":2489},"Export a Styled pandas DataFrame to Excel with Styler.to_excel","Write pandas Styler output to Excel: background colours, fonts, highlight_max, gradients, the number-format CSS property, engine differences, and when to switch to openpyxl or xlsxwriter.","export-a-styled-pandas-dataframe-to-excel","getting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas\u002Fexport-a-styled-pandas-dataframe-to-excel\u002Findex",[2493,2494,2495],"cell-styling","writing-excel","pandas","how-to","Gfs6KRbZaUN7kNINGtCwbNVN8IWp-WQS50e5S1N2KrU",[2499,2503],{"title":2500,"path":2501,"stem":2502,"children":-1},"Control How NaN, None and Infinity Appear in Excel Output","\u002Fgetting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas\u002Fcontrol-how-nan-and-infinity-appear-in-excel-output","getting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas\u002Fcontrol-how-nan-and-infinity-appear-in-excel-output\u002Findex",{"title":2504,"path":2505,"stem":2506,"children":-1},"How pandas Data Types Are Written to Excel Cells","\u002Fgetting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas\u002Fhow-pandas-data-types-are-written-to-excel-cells","getting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas\u002Fhow-pandas-data-types-are-written-to-excel-cells\u002Findex",[2508,2510],{"path":2509,"title":2483},"\u002Fgetting-started-with-python-excel-automation",{"path":2511,"title":33},"\u002Fgetting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas",[],[2514,2518,2521,2524,2527,2530],{"path":2515,"title":2516,"kind":2517},"\u002Fformatting-and-charting-excel-reports-with-python","Formatting and Charting Excel Reports with Python","overview",{"path":2519,"title":2520,"kind":2496},"\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":2522,"title":2428,"kind":2523},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl","guide",{"path":2525,"title":2526,"kind":2496},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fadd-alternating-row-colors-with-openpyxl","Add Alternating Row Colors with openpyxl",{"path":2528,"title":2529,"kind":2496},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fadd-borders-to-a-range-with-openpyxl","Add Borders to a Range with openpyxl",{"path":2531,"title":2532,"kind":2496},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fadd-hyperlinks-to-excel-cells-with-python","Add Hyperlinks to Excel Cells with Python",1790972076444]