[{"data":1,"prerenderedAt":2485},["ShallowReactive",2],{"doc:\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Fconvert-an-excel-sheet-to-an-html-table":3,"surround:\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Fconvert-an-excel-sheet-to-an-html-table":2450,"ancestors:\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Fconvert-an-excel-sheet-to-an-html-table":2458,"children:\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Fconvert-an-excel-sheet-to-an-html-table":2463,"related:\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Fconvert-an-excel-sheet-to-an-html-table":2464},{"id":4,"title":5,"body":6,"dateModified":2416,"datePublished":2416,"description":2417,"extension":2418,"faq":2419,"keyword":2428,"kind":2429,"meta":2430,"navigation":240,"path":2439,"seo":2440,"slug":2443,"stem":2444,"topics":2445,"type":2448,"__hash__":2449},"docs\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Fconvert-an-excel-sheet-to-an-html-table\u002Findex.md","Convert an Excel Sheet to an HTML Table with Python",{"type":7,"value":8,"toc":2402},"minimark",[9,24,171,176,206,212,431,435,448,504,527,531,538,714,733,916,920,931,1164,1174,1178,1188,1296,1299,1303,1312,1469,1476,1480,1487,1859,1869,1995,1999,2002,2215,2230,2234,2320,2324,2333,2337,2343,2349,2359,2365,2369,2398],[10,11,12,13,17,18,23],"p",{},"A worksheet is often the data behind something that is read in a browser or an inbox: a status table on an intranet page, a summary in the body of a report email, a static page generated every night. pandas converts a DataFrame to an HTML ",[14,15,16],"code",{},"\u003Ctable>"," in one call, and a few options decide whether the result looks like a finished table or a raw dump. This guide, part of ",[19,20,22],"a",{"href":21},"\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002F","Handling Excel File Formats and Conversions",", covers the plain conversion, number formatting, conditional highlights with Styler, accessibility, and putting several sheets on one page.",[25,26,34,35,34,39,34,43,34,51,34,61,34,72,34,79,34,84,34,91,34,96,34,100,34,107,34,112,34,115,34,119,34,122,34,125,34,131,34,135,34,138,34,142,34,145,34,150,34,157,34,162,34,165],"svg",{"viewBox":27,"role":28,"ariaLabelledBy":29,"xmlns":32,"style":33},"4 0 752 151","img",[30,31],"html-flow-t","html-flow-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:752px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[36,37,38],"title",{"id":30},"From worksheet to HTML table",[40,41,42],"desc",{"id":31},"A worksheet is read into a DataFrame with read_excel, values are formatted as display strings, the table is rendered with to_html or Styler.to_html with CSS classes, and the HTML is saved as a page or placed in an email body.",[44,45],"rect",{"x":46,"y":47,"width":48,"height":49,"fill":50},"4","0","752","151","#ffffff",[44,52],{"x":53,"y":54,"width":55,"height":56,"rx":57,"fill":58,"stroke":59,"style":60},"20.0","16.0","153.0","93.0","12","#e7ebef","var(--line,#cdd5e6)","stroke-width:2px",[62,63,65],"g",{"transform":64},"translate(84.5,29.0) scale(1.000)",[66,67],"path",{"d":68,"fill":69,"stroke":70,"style":71},"M4 4h16v16H4z M4 9h16 M4 14h16 M10 4v16","none","var(--text,#172033)","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[73,74,78],"text",{"x":75,"y":76,"style":77},"96.5","75.5","font-size:13.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Worksheet",[73,80,83],{"x":75,"y":81,"style":82},"95.0","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","read_excel",[85,86],"line",{"x1":87,"y1":88,"x2":89,"y2":88,"stroke":90,"style":60},"178.0","62.5","200.0","var(--brand,#5b5cf0)",[92,93],"polygon",{"points":94,"fill":95},"204.0,62.5 195.0,67.5 195.0,57.5","#5b5cf0",[44,97],{"x":98,"y":54,"width":55,"height":56,"rx":57,"fill":99,"stroke":90,"style":60},"209.0","#f0f4ff",[62,101,103],{"transform":102},"translate(273.5,29.0) scale(1.000)",[66,104],{"d":105,"fill":69,"stroke":106,"style":71},"M5 9h14 M4 15h14 M10 4l-2 16 M16 4l-2 16","var(--brand-strong,#4338ca)",[73,108,111],{"x":109,"y":76,"style":110},"285.5","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Format values",[73,113,114],{"x":109,"y":81,"style":82},"numbers, dates",[85,116],{"x1":117,"y1":88,"x2":118,"y2":88,"stroke":90,"style":60},"367.0","389.0",[92,120],{"points":121,"fill":95},"393.0,62.5 384.0,67.5 384.0,57.5",[44,123],{"x":124,"y":54,"width":55,"height":56,"rx":57,"fill":99,"stroke":90,"style":60},"398.0",[62,126,128],{"transform":127},"translate(462.5,29.0) scale(1.000)",[66,129],{"d":130,"fill":69,"stroke":106,"style":71},"M9 8l-4 4 4 4 M15 8l4 4-4 4",[73,132,134],{"x":133,"y":76,"style":110},"474.5","Render",[73,136,137],{"x":133,"y":81,"style":82},"to_html \u002F Styler",[85,139],{"x1":140,"y1":88,"x2":141,"y2":88,"stroke":90,"style":60},"556.0","578.0",[92,143],{"points":144,"fill":95},"582.0,62.5 573.0,67.5 573.0,57.5",[44,146],{"x":147,"y":54,"width":55,"height":56,"rx":57,"fill":148,"stroke":149,"style":60},"587.0","#d9f4f1","var(--teal,#0f9488)",[62,151,153],{"transform":152},"translate(651.5,29.0) scale(1.000)",[66,154],{"d":155,"fill":69,"stroke":156,"style":71},"M12 3a9 9 0 1 0 .01 0z M3 12h18 M12 3c3.2 3 3.2 15 0 18 M12 3c-3.2 3-3.2 15 0 18","var(--teal-ink,#0b6157)",[73,158,161],{"x":159,"y":76,"style":160},"663.5","font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Publish",[73,163,164],{"x":159,"y":81,"style":82},"page or email",[73,166,170],{"x":167,"y":168,"style":169},"380.0","131.0","font-size:12.5px;font-weight:400;fill:var(--muted,#5b6780);text-anchor:middle","HTML carries the values and the structure — the look comes from CSS you control",[172,173,175],"h2",{"id":174},"prerequisites","Prerequisites",[177,178,183],"pre",{"className":179,"code":180,"language":181,"meta":182,"style":182},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install pandas openpyxl jinja2\n","bash","",[14,184,185],{"__ignoreMap":182},[186,187,189,193,197,200,203],"span",{"class":85,"line":188},1,[186,190,192],{"class":191},"sMTad","pip",[186,194,196],{"class":195},"srMev"," install",[186,198,199],{"class":195}," pandas",[186,201,202],{"class":195}," openpyxl",[186,204,205],{"class":195}," jinja2\n",[10,207,208,211],{},[14,209,210],{},"jinja2"," is needed only for Styler. The examples start from a small regional report:",[177,213,217],{"className":214,"code":215,"language":216,"meta":182,"style":182},"language-python shiki shiki-themes github-light github-dark-high-contrast","import pandas as pd\n\npd.DataFrame({\n    \"Region\": [\"North\", \"South\", \"East\", \"West\"],\n    \"Revenue\": [1234567.891, 987654.3, 1543210.0, 456789.12],\n    \"Growth\": [0.1234, -0.0342, 0.081, -0.12],\n    \"Updated\": pd.to_datetime([\"2026-09-01\", \"2026-09-01\", \"2026-09-02\", \"2026-09-02\"]),\n}).to_excel(\"regions.xlsx\", sheet_name=\"Summary\", index=False)\n\ndf = pd.read_excel(\"regions.xlsx\", sheet_name=\"Summary\")\n","python",[14,218,219,235,242,248,279,308,341,369,403,408],{"__ignoreMap":182},[186,220,221,225,229,232],{"class":85,"line":188},[186,222,224],{"class":223},"s-kum","import",[186,226,228],{"class":227},"skGVy"," pandas ",[186,230,231],{"class":223},"as",[186,233,234],{"class":227}," pd\n",[186,236,238],{"class":85,"line":237},2,[186,239,241],{"emptyLinePlaceholder":240},true,"\n",[186,243,245],{"class":85,"line":244},3,[186,246,247],{"class":227},"pd.DataFrame({\n",[186,249,251,254,257,260,263,266,268,271,273,276],{"class":85,"line":250},4,[186,252,253],{"class":195},"    \"Region\"",[186,255,256],{"class":227},": [",[186,258,259],{"class":195},"\"North\"",[186,261,262],{"class":227},", ",[186,264,265],{"class":195},"\"South\"",[186,267,262],{"class":227},[186,269,270],{"class":195},"\"East\"",[186,272,262],{"class":227},[186,274,275],{"class":195},"\"West\"",[186,277,278],{"class":227},"],\n",[186,280,282,285,287,291,293,296,298,301,303,306],{"class":85,"line":281},5,[186,283,284],{"class":195},"    \"Revenue\"",[186,286,256],{"class":227},[186,288,290],{"class":289},"sP0c6","1234567.891",[186,292,262],{"class":227},[186,294,295],{"class":289},"987654.3",[186,297,262],{"class":227},[186,299,300],{"class":289},"1543210.0",[186,302,262],{"class":227},[186,304,305],{"class":289},"456789.12",[186,307,278],{"class":227},[186,309,311,314,316,319,321,324,327,329,332,334,336,339],{"class":85,"line":310},6,[186,312,313],{"class":195},"    \"Growth\"",[186,315,256],{"class":227},[186,317,318],{"class":289},"0.1234",[186,320,262],{"class":227},[186,322,323],{"class":223},"-",[186,325,326],{"class":289},"0.0342",[186,328,262],{"class":227},[186,330,331],{"class":289},"0.081",[186,333,262],{"class":227},[186,335,323],{"class":223},[186,337,338],{"class":289},"0.12",[186,340,278],{"class":227},[186,342,344,347,350,353,355,357,359,362,364,366],{"class":85,"line":343},7,[186,345,346],{"class":195},"    \"Updated\"",[186,348,349],{"class":227},": pd.to_datetime([",[186,351,352],{"class":195},"\"2026-09-01\"",[186,354,262],{"class":227},[186,356,352],{"class":195},[186,358,262],{"class":227},[186,360,361],{"class":195},"\"2026-09-02\"",[186,363,262],{"class":227},[186,365,361],{"class":195},[186,367,368],{"class":227},"]),\n",[186,370,372,375,378,380,384,387,390,392,395,397,400],{"class":85,"line":371},8,[186,373,374],{"class":227},"}).to_excel(",[186,376,377],{"class":195},"\"regions.xlsx\"",[186,379,262],{"class":227},[186,381,383],{"class":382},"sa561","sheet_name",[186,385,386],{"class":223},"=",[186,388,389],{"class":195},"\"Summary\"",[186,391,262],{"class":227},[186,393,394],{"class":382},"index",[186,396,386],{"class":223},[186,398,399],{"class":289},"False",[186,401,402],{"class":227},")\n",[186,404,406],{"class":85,"line":405},9,[186,407,241],{"emptyLinePlaceholder":240},[186,409,411,414,416,419,421,423,425,427,429],{"class":85,"line":410},10,[186,412,413],{"class":227},"df ",[186,415,386],{"class":223},[186,417,418],{"class":227}," pd.read_excel(",[186,420,377],{"class":195},[186,422,262],{"class":227},[186,424,383],{"class":382},[186,426,386],{"class":223},[186,428,389],{"class":195},[186,430,402],{"class":227},[172,432,434],{"id":433},"step-1-the-plain-conversion","Step 1 — The plain conversion",[10,436,437,440,441,443,444,447],{},[14,438,439],{},"to_html"," returns a string containing a ",[14,442,16],{},". Two options are almost always right: ",[14,445,446],{},"index=False",", because the row numbers mean nothing to a reader, and a CSS class so the page can style the table:",[177,449,451],{"className":214,"code":450,"language":216,"meta":182,"style":182},"html = df.to_html(index=False, classes=\"report\", border=0)\nprint(html[:160])\n",[14,452,453,490],{"__ignoreMap":182},[186,454,455,458,460,463,465,467,469,471,474,476,479,481,484,486,488],{"class":85,"line":188},[186,456,457],{"class":227},"html ",[186,459,386],{"class":223},[186,461,462],{"class":227}," df.to_html(",[186,464,394],{"class":382},[186,466,386],{"class":223},[186,468,399],{"class":289},[186,470,262],{"class":227},[186,472,473],{"class":382},"classes",[186,475,386],{"class":223},[186,477,478],{"class":195},"\"report\"",[186,480,262],{"class":227},[186,482,483],{"class":382},"border",[186,485,386],{"class":223},[186,487,47],{"class":289},[186,489,402],{"class":227},[186,491,492,495,498,501],{"class":85,"line":237},[186,493,494],{"class":289},"print",[186,496,497],{"class":227},"(html[:",[186,499,500],{"class":289},"160",[186,502,503],{"class":227},"])\n",[10,505,506,507,510,511,514,515,518,519,262,521,262,523,526],{},"The output has a ",[14,508,509],{},"\u003Cthead>"," with the column names as ",[14,512,513],{},"\u003Cth>"," cells and a ",[14,516,517],{},"\u003Ctbody>"," of rows — correct structure — but the values are raw: ",[14,520,290],{},[14,522,318],{},[14,524,525],{},"2026-09-01 00:00:00",". Nobody wants to read those.",[172,528,530],{"id":529},"step-2-format-numbers-and-dates","Step 2 — Format numbers and dates",[10,532,533,534,537],{},"Pass a ",[14,535,536],{},"formatters"," dict mapping each column to a function that returns the display string. The DataFrame keeps its real values; only the HTML changes:",[177,539,541],{"className":214,"code":540,"language":216,"meta":182,"style":182},"formatters = {\n    \"Revenue\": lambda v: f\"{v:,.0f}\",\n    \"Growth\": lambda v: f\"{v:+.1%}\",\n    \"Updated\": lambda d: d.strftime(\"%d %b %Y\"),\n}\nhtml = df.to_html(index=False, classes=\"report\", border=0, formatters=formatters)\nprint(html.split(\"\u003Ctbody>\")[1].split(\"\u003C\u002Ftr>\")[0])\n",[14,542,543,553,590,617,642,647,686],{"__ignoreMap":182},[186,544,545,548,550],{"class":85,"line":188},[186,546,547],{"class":227},"formatters ",[186,549,386],{"class":223},[186,551,552],{"class":227}," {\n",[186,554,555,557,560,563,566,569,572,576,579,582,585,587],{"class":85,"line":237},[186,556,284],{"class":195},[186,558,559],{"class":227},": ",[186,561,562],{"class":223},"lambda",[186,564,565],{"class":227}," v: ",[186,567,568],{"class":223},"f",[186,570,571],{"class":195},"\"",[186,573,575],{"class":574},"sSjpA","{",[186,577,578],{"class":227},"v",[186,580,581],{"class":223},":,.0f",[186,583,584],{"class":574},"}",[186,586,571],{"class":195},[186,588,589],{"class":227},",\n",[186,591,592,594,596,598,600,602,604,606,608,611,613,615],{"class":85,"line":244},[186,593,313],{"class":195},[186,595,559],{"class":227},[186,597,562],{"class":223},[186,599,565],{"class":227},[186,601,568],{"class":223},[186,603,571],{"class":195},[186,605,575],{"class":574},[186,607,578],{"class":227},[186,609,610],{"class":223},":+.1%",[186,612,584],{"class":574},[186,614,571],{"class":195},[186,616,589],{"class":227},[186,618,619,621,623,625,628,630,633,636,639],{"class":85,"line":250},[186,620,346],{"class":195},[186,622,559],{"class":227},[186,624,562],{"class":223},[186,626,627],{"class":227}," d: d.strftime(",[186,629,571],{"class":195},[186,631,632],{"class":574},"%d",[186,634,635],{"class":574}," %b",[186,637,638],{"class":195}," %Y\"",[186,640,641],{"class":227},"),\n",[186,643,644],{"class":85,"line":281},[186,645,646],{"class":227},"}\n",[186,648,649,651,653,655,657,659,661,663,665,667,669,671,673,675,677,679,681,683],{"class":85,"line":310},[186,650,457],{"class":227},[186,652,386],{"class":223},[186,654,462],{"class":227},[186,656,394],{"class":382},[186,658,386],{"class":223},[186,660,399],{"class":289},[186,662,262],{"class":227},[186,664,473],{"class":382},[186,666,386],{"class":223},[186,668,478],{"class":195},[186,670,262],{"class":227},[186,672,483],{"class":382},[186,674,386],{"class":223},[186,676,47],{"class":289},[186,678,262],{"class":227},[186,680,536],{"class":382},[186,682,386],{"class":223},[186,684,685],{"class":227},"formatters)\n",[186,687,688,690,693,696,699,702,705,708,710,712],{"class":85,"line":343},[186,689,494],{"class":289},[186,691,692],{"class":227},"(html.split(",[186,694,695],{"class":195},"\"\u003Ctbody>\"",[186,697,698],{"class":227},")[",[186,700,701],{"class":289},"1",[186,703,704],{"class":227},"].split(",[186,706,707],{"class":195},"\"\u003C\u002Ftr>\"",[186,709,698],{"class":227},[186,711,47],{"class":289},[186,713,503],{"class":227},[10,715,716,717,262,720,723,724,727,728,732],{},"The first row now reads ",[14,718,719],{},"1,234,568",[14,721,722],{},"+12.3%"," and ",[14,725,726],{},"01 Sep 2026",". The formats deliberately mirror Excel's number formats — thousands separators, signed percentages — so the table reads like the sheet it came from. When the workbook already defines formats per cell and you want exactly what Excel shows, read the displayed text instead, as described in ",[19,729,731],{"href":730},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fapplying-number-and-date-formats-in-excel\u002Fread-cell-values-as-displayed-in-excel\u002F","Read Cell Values as Displayed in Excel with Python",".",[25,734,34,739,34,742,34,745,34,748,34,754,34,758,34,764,34,768,34,772,34,776,34,780,34,784,34,788,34,790,34,794,34,796,34,799,34,801,34,804,34,807,34,811,34,816,34,819,34,821,34,823,34,825,34,827,34,830,34,834,34,837,34,841,34,844,34,848,34,851,34,853,34,856,34,858,34,860,34,862,34,864,34,866,34,868,34,870,34,872,34,874,34,877,34,879,34,881,34,883,34,885,34,891,34,895,34,900,34,903,34,911],{"viewBox":735,"role":28,"ariaLabelledBy":736,"xmlns":32,"style":33},"4 0 752 136",[737,738],"html-format-t","html-format-d",[36,740,741],{"id":737},"Raw values and the formatted cells in the HTML table",[40,743,744],{"id":738},"Without formatters, revenue appears as 1234567.891, growth as 0.1234 and the date with a midnight timestamp. With formatters, the same values render as 1,234,568, plus 12.3 percent and 01 Sep 2026, while the DataFrame keeps the raw numbers.",[44,746],{"x":46,"y":47,"width":48,"height":747,"fill":50},"136",[44,749],{"x":53,"y":750,"width":751,"height":752,"rx":47,"fill":58,"stroke":59,"style":753},"40.0","32.0","24.0","stroke-width:1px",[44,755],{"x":756,"y":750,"width":757,"height":752,"rx":47,"fill":58,"stroke":59,"style":753},"52.0","89.6",[73,759,763],{"x":760,"y":761,"style":762},"96.8","57.0","font-size:11px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","A",[44,765],{"x":766,"y":750,"width":767,"height":752,"rx":47,"fill":58,"stroke":59,"style":753},"141.6","60.2",[73,769,771],{"x":770,"y":761,"style":762},"171.8","B",[44,773],{"x":774,"y":750,"width":775,"height":752,"rx":47,"fill":58,"stroke":59,"style":753},"201.9","139.8",[73,777,779],{"x":778,"y":761,"style":762},"271.8","C",[44,781],{"x":53,"y":782,"width":751,"height":783,"rx":47,"fill":58,"stroke":59,"style":753},"64.0","28.0",[73,785,701],{"x":786,"y":787,"style":762},"36.0","83.0",[44,789],{"x":756,"y":782,"width":757,"height":783,"rx":47,"fill":50,"stroke":59,"style":753},[73,791,793],{"x":760,"y":787,"style":792},"font-size:12px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Revenue",[44,795],{"x":766,"y":782,"width":767,"height":783,"rx":47,"fill":50,"stroke":59,"style":753},[73,797,798],{"x":770,"y":787,"style":792},"Growth",[44,800],{"x":774,"y":782,"width":775,"height":783,"rx":47,"fill":50,"stroke":59,"style":753},[73,802,803],{"x":778,"y":787,"style":792},"Updated",[44,805],{"x":53,"y":806,"width":751,"height":783,"rx":47,"fill":58,"stroke":59,"style":753},"92.0",[73,808,810],{"x":786,"y":809,"style":762},"111.0","2",[44,812],{"x":756,"y":806,"width":757,"height":783,"rx":47,"fill":813,"stroke":814,"style":815},"#fee8f2","var(--accent,#f43f8f)","stroke-width:1.5px",[73,817,290],{"x":760,"y":809,"style":818},"font-size:12px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle",[44,820],{"x":766,"y":806,"width":767,"height":783,"rx":47,"fill":813,"stroke":814,"style":815},[73,822,318],{"x":770,"y":809,"style":818},[44,824],{"x":774,"y":806,"width":775,"height":783,"rx":47,"fill":813,"stroke":814,"style":815},[73,826,525],{"x":778,"y":809,"style":818},[44,828],{"x":829,"y":750,"width":751,"height":752,"rx":47,"fill":58,"stroke":59,"style":753},"485.3",[44,831],{"x":832,"y":750,"width":833,"height":752,"rx":47,"fill":58,"stroke":59,"style":753},"517.3","74.8",[73,835,763],{"x":836,"y":761,"style":762},"554.7",[44,838],{"x":839,"y":750,"width":840,"height":752,"rx":47,"fill":58,"stroke":59,"style":753},"592.1","61.4",[73,842,771],{"x":843,"y":761,"style":762},"622.8",[44,845],{"x":846,"y":750,"width":847,"height":752,"rx":47,"fill":58,"stroke":59,"style":753},"653.5","86.5",[73,849,779],{"x":850,"y":761,"style":762},"696.8",[44,852],{"x":829,"y":782,"width":751,"height":783,"rx":47,"fill":58,"stroke":59,"style":753},[73,854,701],{"x":855,"y":787,"style":762},"501.3",[44,857],{"x":832,"y":782,"width":833,"height":783,"rx":47,"fill":50,"stroke":59,"style":753},[73,859,793],{"x":836,"y":787,"style":792},[44,861],{"x":839,"y":782,"width":840,"height":783,"rx":47,"fill":50,"stroke":59,"style":753},[73,863,798],{"x":843,"y":787,"style":792},[44,865],{"x":846,"y":782,"width":847,"height":783,"rx":47,"fill":50,"stroke":59,"style":753},[73,867,803],{"x":850,"y":787,"style":792},[44,869],{"x":829,"y":806,"width":751,"height":783,"rx":47,"fill":58,"stroke":59,"style":753},[73,871,810],{"x":855,"y":809,"style":762},[44,873],{"x":832,"y":806,"width":833,"height":783,"rx":47,"fill":148,"stroke":149,"style":815},[73,875,719],{"x":836,"y":809,"style":876},"font-size:12px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle",[44,878],{"x":839,"y":806,"width":840,"height":783,"rx":47,"fill":148,"stroke":149,"style":815},[73,880,722],{"x":843,"y":809,"style":876},[44,882],{"x":846,"y":806,"width":847,"height":783,"rx":47,"fill":148,"stroke":149,"style":815},[73,884,726],{"x":850,"y":809,"style":876},[73,886,890],{"x":887,"y":888,"style":889},"180.9","29.0","font-size:12.5px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","to_html()",[73,892,894],{"x":893,"y":888,"style":889},"612.7","with formatters",[85,896],{"x1":897,"y1":898,"x2":899,"y2":898,"stroke":90,"style":60},"351.7","80.0","471.3",[92,901],{"points":902,"fill":95},"475.3,80.0 466.3,85.0 466.3,75.0",[44,904],{"x":905,"y":906,"width":907,"height":908,"rx":909,"fill":50,"stroke":59,"style":910},"372.1","47.0","82.9","22.0","11","stroke-width:1.2px",[73,912,536],{"x":913,"y":914,"style":915},"413.5","62.0","font-size:11.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle",[172,917,919],{"id":918},"step-3-highlight-values-with-styler","Step 3 — Highlight values with Styler",[10,921,922,923,926,927,930],{},"For colour that depends on the data — negative growth in red, the best region in bold — use ",[14,924,925],{},"df.style",". Each method adds CSS to individual cells, and ",[14,928,929],{},"format"," applies display formats like the formatters above:",[177,932,934],{"className":214,"code":933,"language":216,"meta":182,"style":182},"def negative_red(v):\n    return \"color: #b91c1c; font-weight: 600;\" if v \u003C 0 else \"\"\n\nstyled = (\n    df.style\n      .format({\"Revenue\": \"{:,.0f}\", \"Growth\": \"{:+.1%}\", \"Updated\": \"{:%d %b %Y}\"})\n      .map(negative_red, subset=[\"Growth\"])\n      .highlight_max(subset=[\"Revenue\"], props=\"font-weight: 700;\")\n      .hide(axis=\"index\")\n      .set_table_attributes('class=\"report\"')\n)\nstyled_html = styled.to_html()\nprint(\"color: #b91c1c\" in styled_html, 'class=\"report\"' in styled_html)   # True True\n",[14,935,936,948,974,978,988,993,1052,1069,1095,1110,1120,1125,1136],{"__ignoreMap":182},[186,937,938,941,945],{"class":85,"line":188},[186,939,940],{"class":223},"def",[186,942,944],{"class":943},"s_Opv"," negative_red",[186,946,947],{"class":227},"(v):\n",[186,949,950,953,956,959,962,965,968,971],{"class":85,"line":237},[186,951,952],{"class":223},"    return",[186,954,955],{"class":195}," \"color: #b91c1c; font-weight: 600;\"",[186,957,958],{"class":223}," if",[186,960,961],{"class":227}," v ",[186,963,964],{"class":223},"\u003C",[186,966,967],{"class":289}," 0",[186,969,970],{"class":223}," else",[186,972,973],{"class":195}," \"\"\n",[186,975,976],{"class":85,"line":244},[186,977,241],{"emptyLinePlaceholder":240},[186,979,980,983,985],{"class":85,"line":250},[186,981,982],{"class":227},"styled ",[186,984,386],{"class":223},[186,986,987],{"class":227}," (\n",[186,989,990],{"class":85,"line":281},[186,991,992],{"class":227},"    df.style\n",[186,994,995,998,1001,1003,1005,1007,1009,1011,1013,1015,1018,1020,1022,1024,1026,1028,1030,1032,1035,1037,1039,1041,1044,1047,1049],{"class":85,"line":310},[186,996,997],{"class":227},"      .format({",[186,999,1000],{"class":195},"\"Revenue\"",[186,1002,559],{"class":227},[186,1004,571],{"class":195},[186,1006,575],{"class":574},[186,1008,581],{"class":223},[186,1010,584],{"class":574},[186,1012,571],{"class":195},[186,1014,262],{"class":227},[186,1016,1017],{"class":195},"\"Growth\"",[186,1019,559],{"class":227},[186,1021,571],{"class":195},[186,1023,575],{"class":574},[186,1025,610],{"class":223},[186,1027,584],{"class":574},[186,1029,571],{"class":195},[186,1031,262],{"class":227},[186,1033,1034],{"class":195},"\"Updated\"",[186,1036,559],{"class":227},[186,1038,571],{"class":195},[186,1040,575],{"class":574},[186,1042,1043],{"class":223},":",[186,1045,1046],{"class":574},"%d %b %Y}",[186,1048,571],{"class":195},[186,1050,1051],{"class":227},"})\n",[186,1053,1054,1057,1060,1062,1065,1067],{"class":85,"line":343},[186,1055,1056],{"class":227},"      .map(negative_red, ",[186,1058,1059],{"class":382},"subset",[186,1061,386],{"class":223},[186,1063,1064],{"class":227},"[",[186,1066,1017],{"class":195},[186,1068,503],{"class":227},[186,1070,1071,1074,1076,1078,1080,1082,1085,1088,1090,1093],{"class":85,"line":371},[186,1072,1073],{"class":227},"      .highlight_max(",[186,1075,1059],{"class":382},[186,1077,386],{"class":223},[186,1079,1064],{"class":227},[186,1081,1000],{"class":195},[186,1083,1084],{"class":227},"], ",[186,1086,1087],{"class":382},"props",[186,1089,386],{"class":223},[186,1091,1092],{"class":195},"\"font-weight: 700;\"",[186,1094,402],{"class":227},[186,1096,1097,1100,1103,1105,1108],{"class":85,"line":405},[186,1098,1099],{"class":227},"      .hide(",[186,1101,1102],{"class":382},"axis",[186,1104,386],{"class":223},[186,1106,1107],{"class":195},"\"index\"",[186,1109,402],{"class":227},[186,1111,1112,1115,1118],{"class":85,"line":410},[186,1113,1114],{"class":227},"      .set_table_attributes(",[186,1116,1117],{"class":195},"'class=\"report\"'",[186,1119,402],{"class":227},[186,1121,1123],{"class":85,"line":1122},11,[186,1124,402],{"class":227},[186,1126,1128,1131,1133],{"class":85,"line":1127},12,[186,1129,1130],{"class":227},"styled_html ",[186,1132,386],{"class":223},[186,1134,1135],{"class":227}," styled.to_html()\n",[186,1137,1139,1141,1144,1147,1150,1153,1155,1157,1160],{"class":85,"line":1138},13,[186,1140,494],{"class":289},[186,1142,1143],{"class":227},"(",[186,1145,1146],{"class":195},"\"color: #b91c1c\"",[186,1148,1149],{"class":223}," in",[186,1151,1152],{"class":227}," styled_html, ",[186,1154,1117],{"class":195},[186,1156,1149],{"class":223},[186,1158,1159],{"class":227}," styled_html)   ",[186,1161,1163],{"class":1162},"s-wDw","# True True\n",[10,1165,1166,1167,1170,1171,1173],{},"Styler writes the per-cell styles as a ",[14,1168,1169],{},"\u003Cstyle>"," block with generated ids plus the table. That works on web pages; for email, where many clients discard ",[14,1172,1169],{}," blocks, see Step 5.",[172,1175,1177],{"id":1176},"step-4-make-the-table-accessible","Step 4 — Make the table accessible",[10,1179,1180,1181,1183,1184,1187],{},"Screen readers rely on table structure. Add a caption that says what the table is, and make sure column headers are ",[14,1182,513],{}," elements with ",[14,1185,1186],{},"scope=\"col\"",". Styler handles the caption; a small regular expression adds the scope attribute to every column-heading cell, whatever other attributes Styler has put on it:",[177,1189,1191],{"className":214,"code":1190,"language":216,"meta":182,"style":182},"import re\n\naccessible = re.sub(\n    r'\u003Cth (?=[^>]*class=\"col_heading)',\n    '\u003Cth scope=\"col\" ',\n    styled.set_caption(\"Revenue and growth by region, September 2026\").to_html(),\n)\nprint(\"\u003Ccaption>\" in accessible, 'scope=\"col\"' in accessible)   # True True\n",[14,1192,1193,1200,1204,1214,1250,1257,1268,1272],{"__ignoreMap":182},[186,1194,1195,1197],{"class":85,"line":188},[186,1196,224],{"class":223},[186,1198,1199],{"class":227}," re\n",[186,1201,1202],{"class":85,"line":237},[186,1203,241],{"emptyLinePlaceholder":240},[186,1205,1206,1209,1211],{"class":85,"line":244},[186,1207,1208],{"class":227},"accessible ",[186,1210,386],{"class":223},[186,1212,1213],{"class":227}," re.sub(\n",[186,1215,1216,1219,1222,1225,1227,1230,1233,1236,1239,1242,1245,1248],{"class":85,"line":250},[186,1217,1218],{"class":223},"    r",[186,1220,1221],{"class":195},"'\u003Cth ",[186,1223,1224],{"class":223},"(?=",[186,1226,1064],{"class":289},[186,1228,1229],{"class":223},"^",[186,1231,1232],{"class":574},">",[186,1234,1235],{"class":289},"]",[186,1237,1238],{"class":223},"*",[186,1240,1241],{"class":195},"class=\"col_heading",[186,1243,1244],{"class":223},")",[186,1246,1247],{"class":195},"'",[186,1249,589],{"class":227},[186,1251,1252,1255],{"class":85,"line":281},[186,1253,1254],{"class":195},"    '\u003Cth scope=\"col\" '",[186,1256,589],{"class":227},[186,1258,1259,1262,1265],{"class":85,"line":310},[186,1260,1261],{"class":227},"    styled.set_caption(",[186,1263,1264],{"class":195},"\"Revenue and growth by region, September 2026\"",[186,1266,1267],{"class":227},").to_html(),\n",[186,1269,1270],{"class":85,"line":343},[186,1271,402],{"class":227},[186,1273,1274,1276,1278,1281,1283,1286,1289,1291,1294],{"class":85,"line":371},[186,1275,494],{"class":289},[186,1277,1143],{"class":227},[186,1279,1280],{"class":195},"\"\u003Ccaption>\"",[186,1282,1149],{"class":223},[186,1284,1285],{"class":227}," accessible, ",[186,1287,1288],{"class":195},"'scope=\"col\"'",[186,1290,1149],{"class":223},[186,1292,1293],{"class":227}," accessible)   ",[186,1295,1163],{"class":1162},[10,1297,1298],{},"Keep the caption meaningful — \"Revenue and growth by region\" rather than \"Table 1\" — and avoid merged header cells in HTML output; a flat header row is both easier to style and easier for assistive technology to announce.",[172,1300,1302],{"id":1301},"step-5-inline-styles-for-email-bodies","Step 5 — Inline styles for email bodies",[10,1304,1305,1306,1308,1309,1311],{},"Email clients vary wildly in their CSS support, and several strip ",[14,1307,1169],{}," blocks entirely. For an email body, put the styles directly on the elements with plain ",[14,1310,439],{}," and a little string work, which survives every client:",[177,1313,1315],{"className":214,"code":1314,"language":216,"meta":182,"style":182},"TH = \"text-align:left;padding:6px 10px;border-bottom:2px solid #4338ca;\"\nTD = \"padding:6px 10px;border-bottom:1px solid #cdd5e6;\"\n\nemail_html = (\n    df.to_html(index=False, border=0, formatters=formatters, escape=True)\n      .replace('\u003Ctable class=\"dataframe\">', '\u003Ctable style=\"border-collapse:collapse;font-family:Arial,sans-serif;font-size:14px;\">')\n      .replace(\"\u003Cth>\", f'\u003Cth style=\"{TH}\">')\n      .replace(\"\u003Ctd>\", f'\u003Ctd style=\"{TD}\">')\n)\nprint(email_html[:120])\n",[14,1316,1317,1328,1338,1342,1351,1389,1404,1429,1453,1457],{"__ignoreMap":182},[186,1318,1319,1322,1325],{"class":85,"line":188},[186,1320,1321],{"class":289},"TH",[186,1323,1324],{"class":223}," =",[186,1326,1327],{"class":195}," \"text-align:left;padding:6px 10px;border-bottom:2px solid #4338ca;\"\n",[186,1329,1330,1333,1335],{"class":85,"line":237},[186,1331,1332],{"class":289},"TD",[186,1334,1324],{"class":223},[186,1336,1337],{"class":195}," \"padding:6px 10px;border-bottom:1px solid #cdd5e6;\"\n",[186,1339,1340],{"class":85,"line":244},[186,1341,241],{"emptyLinePlaceholder":240},[186,1343,1344,1347,1349],{"class":85,"line":250},[186,1345,1346],{"class":227},"email_html ",[186,1348,386],{"class":223},[186,1350,987],{"class":227},[186,1352,1353,1356,1358,1360,1362,1364,1366,1368,1370,1372,1374,1376,1379,1382,1384,1387],{"class":85,"line":281},[186,1354,1355],{"class":227},"    df.to_html(",[186,1357,394],{"class":382},[186,1359,386],{"class":223},[186,1361,399],{"class":289},[186,1363,262],{"class":227},[186,1365,483],{"class":382},[186,1367,386],{"class":223},[186,1369,47],{"class":289},[186,1371,262],{"class":227},[186,1373,536],{"class":382},[186,1375,386],{"class":223},[186,1377,1378],{"class":227},"formatters, ",[186,1380,1381],{"class":382},"escape",[186,1383,386],{"class":223},[186,1385,1386],{"class":289},"True",[186,1388,402],{"class":227},[186,1390,1391,1394,1397,1399,1402],{"class":85,"line":310},[186,1392,1393],{"class":227},"      .replace(",[186,1395,1396],{"class":195},"'\u003Ctable class=\"dataframe\">'",[186,1398,262],{"class":227},[186,1400,1401],{"class":195},"'\u003Ctable style=\"border-collapse:collapse;font-family:Arial,sans-serif;font-size:14px;\">'",[186,1403,402],{"class":227},[186,1405,1406,1408,1411,1413,1415,1418,1420,1422,1424,1427],{"class":85,"line":343},[186,1407,1393],{"class":227},[186,1409,1410],{"class":195},"\"\u003Cth>\"",[186,1412,262],{"class":227},[186,1414,568],{"class":223},[186,1416,1417],{"class":195},"'\u003Cth style=\"",[186,1419,575],{"class":574},[186,1421,1321],{"class":289},[186,1423,584],{"class":574},[186,1425,1426],{"class":195},"\">'",[186,1428,402],{"class":227},[186,1430,1431,1433,1436,1438,1440,1443,1445,1447,1449,1451],{"class":85,"line":371},[186,1432,1393],{"class":227},[186,1434,1435],{"class":195},"\"\u003Ctd>\"",[186,1437,262],{"class":227},[186,1439,568],{"class":223},[186,1441,1442],{"class":195},"'\u003Ctd style=\"",[186,1444,575],{"class":574},[186,1446,1332],{"class":289},[186,1448,584],{"class":574},[186,1450,1426],{"class":195},[186,1452,402],{"class":227},[186,1454,1455],{"class":85,"line":405},[186,1456,402],{"class":227},[186,1458,1459,1461,1464,1467],{"class":85,"line":410},[186,1460,494],{"class":289},[186,1462,1463],{"class":227},"(email_html[:",[186,1465,1466],{"class":289},"120",[186,1468,503],{"class":227},[10,1470,1471,1472,732],{},"The result renders consistently in Outlook, Gmail and mobile clients. Sending it as the HTML part of a message is covered in ",[19,1473,1475],{"href":1474},"\u002Fautomating-reporting-workflows\u002Femailing-excel-reports-with-smtplib\u002Femail-an-excel-report-with-an-html-summary-body\u002F","Email an Excel Report with an HTML Summary Body",[172,1477,1479],{"id":1478},"step-6-several-sheets-on-one-page","Step 6 — Several sheets on one page",[10,1481,1482,1483,1486],{},"To publish a whole workbook as one page, read every sheet with ",[14,1484,1485],{},"sheet_name=None",", render each as a section with its own heading and anchor, and wrap them in a minimal HTML document with a stylesheet:",[177,1488,1490],{"className":214,"code":1489,"language":216,"meta":182,"style":182},"from html import escape\n\nsheets = pd.read_excel(\"regions.xlsx\", sheet_name=None)\nsections, links = [], []\nfor i, (name, frame) in enumerate(sheets.items(), start=1):\n    anchor = f\"sheet-{i}\"\n    links.append(f'\u003Cli>\u003Ca href=\"#{anchor}\">{escape(name)}\u003C\u002Fa>\u003C\u002Fli>')\n    sections.append(f'\u003Csection id=\"{anchor}\">\u003Ch2>{escape(name)}\u003C\u002Fh2>'\n                    f'{frame.to_html(index=False, classes=\"report\", border=0)}\u003C\u002Fsection>')\n\npage = f\"\"\"\u003C!doctype html>\n\u003Chtml lang=\"en\">\u003Chead>\u003Cmeta charset=\"utf-8\">\u003Ctitle>Regional report\u003C\u002Ftitle>\n\u003Cstyle>\n  body {{ font-family: system-ui, sans-serif; margin: 2rem; }}\n  table.report {{ border-collapse: collapse; }}\n  table.report th, table.report td {{ padding: .4rem .8rem; border-bottom: 1px solid #cdd5e6; text-align: left; }}\n\u003C\u002Fstyle>\u003C\u002Fhead>\n\u003Cbody>\u003Ch1>Regional report\u003C\u002Fh1>\u003Cul>{''.join(links)}\u003C\u002Ful>{''.join(sections)}\u003C\u002Fbody>\u003C\u002Fhtml>\"\"\"\nwith open(\"regions.html\", \"w\", encoding=\"utf-8\") as fh:\n    fh.write(page)\nprint(len(sheets), \"sheet(s) written to regions.html\")\n",[14,1491,1492,1505,1509,1531,1541,1568,1591,1623,1651,1694,1698,1710,1715,1720,1735,1748,1761,1767,1798,1835,1841],{"__ignoreMap":182},[186,1493,1494,1497,1500,1502],{"class":85,"line":188},[186,1495,1496],{"class":223},"from",[186,1498,1499],{"class":227}," html ",[186,1501,224],{"class":223},[186,1503,1504],{"class":227}," escape\n",[186,1506,1507],{"class":85,"line":237},[186,1508,241],{"emptyLinePlaceholder":240},[186,1510,1511,1514,1516,1518,1520,1522,1524,1526,1529],{"class":85,"line":244},[186,1512,1513],{"class":227},"sheets ",[186,1515,386],{"class":223},[186,1517,418],{"class":227},[186,1519,377],{"class":195},[186,1521,262],{"class":227},[186,1523,383],{"class":382},[186,1525,386],{"class":223},[186,1527,1528],{"class":289},"None",[186,1530,402],{"class":227},[186,1532,1533,1536,1538],{"class":85,"line":250},[186,1534,1535],{"class":227},"sections, links ",[186,1537,386],{"class":223},[186,1539,1540],{"class":227}," [], []\n",[186,1542,1543,1546,1549,1552,1555,1558,1561,1563,1565],{"class":85,"line":281},[186,1544,1545],{"class":223},"for",[186,1547,1548],{"class":227}," i, (name, frame) ",[186,1550,1551],{"class":223},"in",[186,1553,1554],{"class":289}," enumerate",[186,1556,1557],{"class":227},"(sheets.items(), ",[186,1559,1560],{"class":382},"start",[186,1562,386],{"class":223},[186,1564,701],{"class":289},[186,1566,1567],{"class":227},"):\n",[186,1569,1570,1573,1575,1578,1581,1583,1586,1588],{"class":85,"line":310},[186,1571,1572],{"class":227},"    anchor ",[186,1574,386],{"class":223},[186,1576,1577],{"class":223}," f",[186,1579,1580],{"class":195},"\"sheet-",[186,1582,575],{"class":574},[186,1584,1585],{"class":227},"i",[186,1587,584],{"class":574},[186,1589,1590],{"class":195},"\"\n",[186,1592,1593,1596,1598,1601,1603,1606,1608,1611,1613,1616,1618,1621],{"class":85,"line":343},[186,1594,1595],{"class":227},"    links.append(",[186,1597,568],{"class":223},[186,1599,1600],{"class":195},"'\u003Cli>\u003Ca href=\"#",[186,1602,575],{"class":574},[186,1604,1605],{"class":227},"anchor",[186,1607,584],{"class":574},[186,1609,1610],{"class":195},"\">",[186,1612,575],{"class":574},[186,1614,1615],{"class":227},"escape(name)",[186,1617,584],{"class":574},[186,1619,1620],{"class":195},"\u003C\u002Fa>\u003C\u002Fli>'",[186,1622,402],{"class":227},[186,1624,1625,1628,1630,1633,1635,1637,1639,1642,1644,1646,1648],{"class":85,"line":371},[186,1626,1627],{"class":227},"    sections.append(",[186,1629,568],{"class":223},[186,1631,1632],{"class":195},"'\u003Csection id=\"",[186,1634,575],{"class":574},[186,1636,1605],{"class":227},[186,1638,584],{"class":574},[186,1640,1641],{"class":195},"\">\u003Ch2>",[186,1643,575],{"class":574},[186,1645,1615],{"class":227},[186,1647,584],{"class":574},[186,1649,1650],{"class":195},"\u003C\u002Fh2>'\n",[186,1652,1653,1656,1658,1660,1663,1665,1667,1669,1671,1673,1675,1677,1679,1681,1683,1685,1687,1689,1692],{"class":85,"line":405},[186,1654,1655],{"class":223},"                    f",[186,1657,1247],{"class":195},[186,1659,575],{"class":574},[186,1661,1662],{"class":227},"frame.to_html(",[186,1664,394],{"class":382},[186,1666,386],{"class":223},[186,1668,399],{"class":289},[186,1670,262],{"class":227},[186,1672,473],{"class":382},[186,1674,386],{"class":223},[186,1676,478],{"class":195},[186,1678,262],{"class":227},[186,1680,483],{"class":382},[186,1682,386],{"class":223},[186,1684,47],{"class":289},[186,1686,1244],{"class":227},[186,1688,584],{"class":574},[186,1690,1691],{"class":195},"\u003C\u002Fsection>'",[186,1693,402],{"class":227},[186,1695,1696],{"class":85,"line":410},[186,1697,241],{"emptyLinePlaceholder":240},[186,1699,1700,1703,1705,1707],{"class":85,"line":1122},[186,1701,1702],{"class":227},"page ",[186,1704,386],{"class":223},[186,1706,1577],{"class":223},[186,1708,1709],{"class":195},"\"\"\"\u003C!doctype html>\n",[186,1711,1712],{"class":85,"line":1127},[186,1713,1714],{"class":195},"\u003Chtml lang=\"en\">\u003Chead>\u003Cmeta charset=\"utf-8\">\u003Ctitle>Regional report\u003C\u002Ftitle>\n",[186,1716,1717],{"class":85,"line":1138},[186,1718,1719],{"class":195},"\u003Cstyle>\n",[186,1721,1723,1726,1729,1732],{"class":85,"line":1722},14,[186,1724,1725],{"class":195},"  body ",[186,1727,1728],{"class":574},"{{",[186,1730,1731],{"class":195}," font-family: system-ui, sans-serif; margin: 2rem; ",[186,1733,1734],{"class":574},"}}\n",[186,1736,1738,1741,1743,1746],{"class":85,"line":1737},15,[186,1739,1740],{"class":195},"  table.report ",[186,1742,1728],{"class":574},[186,1744,1745],{"class":195}," border-collapse: collapse; ",[186,1747,1734],{"class":574},[186,1749,1751,1754,1756,1759],{"class":85,"line":1750},16,[186,1752,1753],{"class":195},"  table.report th, table.report td ",[186,1755,1728],{"class":574},[186,1757,1758],{"class":195}," padding: .4rem .8rem; border-bottom: 1px solid #cdd5e6; text-align: left; ",[186,1760,1734],{"class":574},[186,1762,1764],{"class":85,"line":1763},17,[186,1765,1766],{"class":195},"\u003C\u002Fstyle>\u003C\u002Fhead>\n",[186,1768,1770,1773,1775,1778,1781,1783,1786,1788,1790,1793,1795],{"class":85,"line":1769},18,[186,1771,1772],{"class":195},"\u003Cbody>\u003Ch1>Regional report\u003C\u002Fh1>\u003Cul>",[186,1774,575],{"class":574},[186,1776,1777],{"class":195},"''",[186,1779,1780],{"class":227},".join(links)",[186,1782,584],{"class":574},[186,1784,1785],{"class":195},"\u003C\u002Ful>",[186,1787,575],{"class":574},[186,1789,1777],{"class":195},[186,1791,1792],{"class":227},".join(sections)",[186,1794,584],{"class":574},[186,1796,1797],{"class":195},"\u003C\u002Fbody>\u003C\u002Fhtml>\"\"\"\n",[186,1799,1801,1804,1807,1809,1812,1814,1817,1819,1822,1824,1827,1830,1832],{"class":85,"line":1800},19,[186,1802,1803],{"class":223},"with",[186,1805,1806],{"class":289}," open",[186,1808,1143],{"class":227},[186,1810,1811],{"class":195},"\"regions.html\"",[186,1813,262],{"class":227},[186,1815,1816],{"class":195},"\"w\"",[186,1818,262],{"class":227},[186,1820,1821],{"class":382},"encoding",[186,1823,386],{"class":223},[186,1825,1826],{"class":195},"\"utf-8\"",[186,1828,1829],{"class":227},") ",[186,1831,231],{"class":223},[186,1833,1834],{"class":227}," fh:\n",[186,1836,1838],{"class":85,"line":1837},20,[186,1839,1840],{"class":227},"    fh.write(page)\n",[186,1842,1844,1846,1848,1851,1854,1857],{"class":85,"line":1843},21,[186,1845,494],{"class":289},[186,1847,1143],{"class":227},[186,1849,1850],{"class":289},"len",[186,1852,1853],{"class":227},"(sheets), ",[186,1855,1856],{"class":195},"\"sheet(s) written to regions.html\"",[186,1858,402],{"class":227},[10,1860,1861,1862,1865,1866,1868],{},"Sheet names go through ",[14,1863,1864],{},"html.escape"," because they are text from the workbook; ",[14,1867,439],{}," already escapes cell values. The anchors let readers jump to a sheet, which matters once a workbook has more than two or three.",[25,1870,34,1875,34,1878,34,1881,34,1884,34,1888,34,1893,34,1896,34,1900,34,1904,34,1907,34,1910,34,1916,34,1921,34,1925,34,1930,34,1934,34,1938,34,1940,34,1943,34,1947,34,1950,34,1953,34,1958,34,1961,34,1964,34,1966,34,1969,34,1973,34,1976,34,1981,34,1988,34,1992],{"viewBox":1871,"role":28,"ariaLabelledBy":1872,"xmlns":32,"style":33},"4 0 752 272",[1873,1874],"html-which-t","html-which-d",[36,1876,1877],{"id":1873},"Choosing how to render the HTML table",[40,1879,1880],{"id":1874},"For a web page, use to_html with a CSS class and style it from the page's stylesheet, or Styler when cell colours depend on values. For an email body, use inline styles because many mail clients remove style blocks.",[44,1882],{"x":46,"y":47,"width":48,"height":1883,"fill":50},"272",[44,1885],{"x":1886,"y":54,"width":1887,"height":76,"rx":57,"fill":99,"stroke":90,"style":60},"240.0","280.0",[62,1889,1891],{"transform":1890},"translate(368.0,29.0) scale(1.000)",[66,1892],{"d":155,"fill":69,"stroke":106,"style":71},[73,1894,1895],{"x":167,"y":76,"style":110},"Where will the table be read?",[85,1897],{"x1":167,"y1":1898,"x2":167,"y2":1899,"stroke":90,"style":60},"91.5","111.5",[85,1901],{"x1":1902,"y1":1899,"x2":1903,"y2":1899,"stroke":90,"style":60},"134.7","625.3",[85,1905],{"x1":1902,"y1":1899,"x2":1902,"y2":1906,"stroke":90,"style":60},"157.5",[92,1908],{"points":1909,"fill":95},"134.7,161.5 129.7,152.5 139.7,152.5",[44,1911],{"x":806,"y":1912,"width":1913,"height":1914,"rx":1915,"fill":50,"stroke":59,"style":910},"121.5","85.3","21.0","10",[73,1917,1920],{"x":1902,"y":1918,"style":1919},"136.0","font-size:11.5px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","a web page",[44,1922],{"x":53,"y":1923,"width":1924,"height":56,"rx":57,"fill":148,"stroke":149,"style":60},"163.5","229.3",[62,1926,1928],{"transform":1927},"translate(122.7,176.5) scale(1.000)",[66,1929],{"d":155,"fill":69,"stroke":156,"style":71},[73,1931,1933],{"x":1902,"y":1932,"style":160},"223.0","to_html + CSS class",[73,1935,1937],{"x":1902,"y":1936,"style":82},"242.5","styled by the page",[85,1939],{"x1":167,"y1":1899,"x2":167,"y2":1906,"stroke":90,"style":60},[92,1941],{"points":1942,"fill":95},"380.0,161.5 375.0,152.5 385.0,152.5",[44,1944],{"x":1945,"y":1912,"width":1946,"height":1914,"rx":1915,"fill":50,"stroke":59,"style":910},"310.3","139.3",[73,1948,1949],{"x":167,"y":1918,"style":1919},"value-based colours",[44,1951],{"x":1952,"y":1923,"width":1924,"height":56,"rx":57,"fill":99,"stroke":90,"style":60},"265.3",[62,1954,1956],{"transform":1955},"translate(368.0,176.5) scale(1.000)",[66,1957],{"d":130,"fill":69,"stroke":106,"style":71},[73,1959,1960],{"x":167,"y":1932,"style":110},"Styler.to_html",[73,1962,1963],{"x":167,"y":1936,"style":82},"generated style block",[85,1965],{"x1":1903,"y1":1899,"x2":1903,"y2":1906,"stroke":90,"style":60},[92,1967],{"points":1968,"fill":95},"625.3,161.5 620.3,152.5 630.3,152.5",[44,1970],{"x":1971,"y":1912,"width":1972,"height":1914,"rx":1915,"fill":50,"stroke":59,"style":910},"591.7","67.2",[73,1974,1975],{"x":1903,"y":1918,"style":1919},"an email",[44,1977],{"x":1978,"y":1923,"width":1924,"height":56,"rx":57,"fill":1979,"stroke":1980,"style":60},"510.7","#fdefd8","var(--gold,#b4740a)",[62,1982,1984],{"transform":1983},"translate(613.3,176.5) scale(1.000)",[66,1985],{"d":1986,"fill":69,"stroke":1987,"style":71},"M3 6h18v12H3z M3 7l9 6 9-6","var(--gold-ink,#7a4e06)",[73,1989,1991],{"x":1903,"y":1932,"style":1990},"font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","inline styles",[73,1993,1994],{"x":1903,"y":1936,"style":82},"survive every client",[172,1996,1998],{"id":1997},"step-7-right-align-numbers-and-add-a-total-row","Step 7 — Right-align numbers and add a total row",[10,2000,2001],{},"Numbers are easier to compare when their digits line up, so right-align numeric columns, and give the reader the total they would otherwise work out in their head. Add the total as a formatted row before rendering, and mark it with a class so the stylesheet can make it bold:",[177,2003,2005],{"className":214,"code":2004,"language":216,"meta":182,"style":182},"total = pd.DataFrame([{\"Region\": \"Total\", \"Revenue\": df[\"Revenue\"].sum(),\n                       \"Growth\": None, \"Updated\": df[\"Updated\"].max()}])\nwith_total = pd.concat([df, total], ignore_index=True)\ntable = with_total.to_html(index=False, classes=\"report\", border=0, na_rep=\"\",\n                           formatters={**formatters, \"Growth\": lambda v: \"\" if pd.isna(v) else f\"{v:+.1%}\"})\ntable = table.replace(\"\u003Ctr>\\n      \u003Ctd>Total\u003C\u002Ftd>\", '\u003Ctr class=\"total\">\\n      \u003Ctd>Total\u003C\u002Ftd>')\nprint('class=\"total\"' in table)   # True\n",[14,2006,2007,2037,2057,2076,2120,2168,2198],{"__ignoreMap":182},[186,2008,2009,2012,2014,2017,2020,2022,2025,2027,2029,2032,2034],{"class":85,"line":188},[186,2010,2011],{"class":227},"total ",[186,2013,386],{"class":223},[186,2015,2016],{"class":227}," pd.DataFrame([{",[186,2018,2019],{"class":195},"\"Region\"",[186,2021,559],{"class":227},[186,2023,2024],{"class":195},"\"Total\"",[186,2026,262],{"class":227},[186,2028,1000],{"class":195},[186,2030,2031],{"class":227},": df[",[186,2033,1000],{"class":195},[186,2035,2036],{"class":227},"].sum(),\n",[186,2038,2039,2042,2044,2046,2048,2050,2052,2054],{"class":85,"line":237},[186,2040,2041],{"class":195},"                       \"Growth\"",[186,2043,559],{"class":227},[186,2045,1528],{"class":289},[186,2047,262],{"class":227},[186,2049,1034],{"class":195},[186,2051,2031],{"class":227},[186,2053,1034],{"class":195},[186,2055,2056],{"class":227},"].max()}])\n",[186,2058,2059,2062,2064,2067,2070,2072,2074],{"class":85,"line":244},[186,2060,2061],{"class":227},"with_total ",[186,2063,386],{"class":223},[186,2065,2066],{"class":227}," pd.concat([df, total], ",[186,2068,2069],{"class":382},"ignore_index",[186,2071,386],{"class":223},[186,2073,1386],{"class":289},[186,2075,402],{"class":227},[186,2077,2078,2081,2083,2086,2088,2090,2092,2094,2096,2098,2100,2102,2104,2106,2108,2110,2113,2115,2118],{"class":85,"line":250},[186,2079,2080],{"class":227},"table ",[186,2082,386],{"class":223},[186,2084,2085],{"class":227}," with_total.to_html(",[186,2087,394],{"class":382},[186,2089,386],{"class":223},[186,2091,399],{"class":289},[186,2093,262],{"class":227},[186,2095,473],{"class":382},[186,2097,386],{"class":223},[186,2099,478],{"class":195},[186,2101,262],{"class":227},[186,2103,483],{"class":382},[186,2105,386],{"class":223},[186,2107,47],{"class":289},[186,2109,262],{"class":227},[186,2111,2112],{"class":382},"na_rep",[186,2114,386],{"class":223},[186,2116,2117],{"class":195},"\"\"",[186,2119,589],{"class":227},[186,2121,2122,2125,2127,2129,2132,2134,2136,2138,2140,2142,2144,2146,2149,2152,2154,2156,2158,2160,2162,2164,2166],{"class":85,"line":281},[186,2123,2124],{"class":382},"                           formatters",[186,2126,386],{"class":223},[186,2128,575],{"class":227},[186,2130,2131],{"class":223},"**",[186,2133,1378],{"class":227},[186,2135,1017],{"class":195},[186,2137,559],{"class":227},[186,2139,562],{"class":223},[186,2141,565],{"class":227},[186,2143,2117],{"class":195},[186,2145,958],{"class":223},[186,2147,2148],{"class":227}," pd.isna(v) ",[186,2150,2151],{"class":223},"else",[186,2153,1577],{"class":223},[186,2155,571],{"class":195},[186,2157,575],{"class":574},[186,2159,578],{"class":227},[186,2161,610],{"class":223},[186,2163,584],{"class":574},[186,2165,571],{"class":195},[186,2167,1051],{"class":227},[186,2169,2170,2172,2174,2177,2180,2183,2186,2188,2191,2193,2196],{"class":85,"line":310},[186,2171,2080],{"class":227},[186,2173,386],{"class":223},[186,2175,2176],{"class":227}," table.replace(",[186,2178,2179],{"class":195},"\"\u003Ctr>",[186,2181,2182],{"class":574},"\\n",[186,2184,2185],{"class":195},"      \u003Ctd>Total\u003C\u002Ftd>\"",[186,2187,262],{"class":227},[186,2189,2190],{"class":195},"'\u003Ctr class=\"total\">",[186,2192,2182],{"class":574},[186,2194,2195],{"class":195},"      \u003Ctd>Total\u003C\u002Ftd>'",[186,2197,402],{"class":227},[186,2199,2200,2202,2204,2207,2209,2212],{"class":85,"line":343},[186,2201,494],{"class":289},[186,2203,1143],{"class":227},[186,2205,2206],{"class":195},"'class=\"total\"'",[186,2208,1149],{"class":223},[186,2210,2211],{"class":227}," table)   ",[186,2213,2214],{"class":1162},"# True\n",[10,2216,2217,2218,2221,2222,2225,2226,2229],{},"In the page stylesheet, ",[14,2219,2220],{},"table.report td:nth-child(2), table.report td:nth-child(3) { text-align: right; font-variant-numeric: tabular-nums; }"," aligns the figures, and ",[14,2223,2224],{},"tr.total td { font-weight: 700; border-top: 2px solid; }"," sets off the total. Wide tables also need a wrapper such as ",[14,2227,2228],{},"\u003Cdiv style=\"overflow-x:auto\">"," around them, so that on a phone the table scrolls sideways instead of stretching the whole page.",[172,2231,2233],{"id":2232},"common-pitfalls","Common pitfalls",[2235,2236,2237,2253,2262,2280,2290,2300,2314],"ul",{},[2238,2239,2240,2244,2245,2248,2249,2252],"li",{},[2241,2242,2243],"strong",{},"Turning off escaping for data."," ",[14,2246,2247],{},"escape=False"," lets a cell value like ",[14,2250,2251],{},"\u003Cimg src=x onerror=…>"," become live markup. Keep escaping on for anything read from a workbook.",[2238,2254,2255,2258,2259,732],{},[2241,2256,2257],{},"Losing leading zeros."," Codes read as numbers lose their zeros before they ever reach HTML. Read identifier columns with ",[14,2260,2261],{},"dtype=str",[2238,2263,2264,2267,2268,2271,2272,2275,2276,2279],{},[2241,2265,2266],{},"NaN in the output."," Missing values render as ",[14,2269,2270],{},"NaN",". Pass ",[14,2273,2274],{},"na_rep=\"\""," or ",[14,2277,2278],{},"na_rep=\"–\""," to show a blank or a dash.",[2238,2281,2282,2285,2286,2289],{},[2241,2283,2284],{},"Dates written as text in the workbook."," A date typed as text arrives as a string, and the date formatter then fails on it. Convert with ",[14,2287,2288],{},"pd.to_datetime(..., errors=\"coerce\")"," before formatting, so every value in the column is a real date or clearly missing.",[2238,2291,2292,2295,2296,2299],{},[2241,2293,2294],{},"Styler ids that change on every run."," Styler generates random ids for its style block, so the HTML differs byte for byte between runs even when the data is identical. Call ",[14,2297,2298],{},"df.style.set_uuid(\"report\")"," to fix the prefix when you compare, cache or version-control the generated HTML.",[2238,2301,2302,2305,2306,2309,2310,2313],{},[2241,2303,2304],{},"Merged header cells."," A sheet with merged group headings above the column names reads into pandas as a two-row header full of ",[14,2307,2308],{},"Unnamed: 1","-style labels. Read with ",[14,2311,2312],{},"header=[0, 1]"," for a real two-level header, or skip the group row and name the columns yourself, before converting.",[2238,2315,2316,2319],{},[2241,2317,2318],{},"Huge tables."," A 50,000-row table makes a slow, unusable page. Publish a summary and link to the full workbook for download.",[172,2321,2323],{"id":2322},"conclusion","Conclusion",[10,2325,2326,2329,2330,2332],{},[14,2327,2328],{},"to_html(index=False, classes=...)"," gives correct table structure; ",[14,2331,536],{}," turns raw numbers and dates into readable text without changing the data; Styler adds value-based colours for web pages; inline styles make the same table safe for email. Add a caption and header scope for accessibility, keep escaping on, and render multi-sheet workbooks as sections with anchors on one page.",[172,2334,2336],{"id":2335},"frequently-asked-questions","Frequently asked questions",[10,2338,2339,2342],{},[2241,2340,2341],{},"How do I convert an Excel sheet to HTML in Python?","\nRead it with pd.read_excel and call to_html on the DataFrame. Pass index=False to drop the row numbers, and formatters or float_format to control how numbers appear.",[10,2344,2345,2348],{},[2241,2346,2347],{},"Will the HTML keep the colours and fonts from Excel?","\nNo. to_html converts values, not cell formatting. Re-create the formatting that matters with CSS classes or with pandas Styler, which lets you colour cells based on their values.",[10,2350,2351,2354,2355],{},[2241,2352,2353],{},"Is to_html safe for values that contain HTML?","\nYes, by default. to_html escapes characters like \u003C and & so a value such as ",[2356,2357,2358],"script",{}," is shown as text. Only turn escaping off for content you generated yourself.",[10,2360,2361,2364],{},[2241,2362,2363],{},"How do I put the table in an email?","\nBuild the HTML with to_html or Styler.to_html, use inline styles rather than a stylesheet because many mail clients strip style blocks, and send it as the HTML part of the message.",[172,2366,2368],{"id":2367},"related","Related",[2235,2370,2371,2377,2384,2391],{},[2238,2372,2373,2374,2376],{},"Up one level: ",[19,2375,22],{"href":21}," — every format in and out.",[2238,2378,2379,2383],{},[19,2380,2382],{"href":2381},"\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Fconvert-an-excel-sheet-to-json-with-python\u002F","Convert an Excel Sheet to JSON with Python"," — the other web-facing format.",[2238,2385,2386,2390],{},[19,2387,2389],{"href":2388},"\u002Fgetting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas\u002Fexport-a-styled-pandas-dataframe-to-excel\u002F","Export a Styled pandas DataFrame to Excel"," — Styler going the other way.",[2238,2392,2393,2397],{},[19,2394,2396],{"href":2395},"\u002Fautomating-reporting-workflows\u002Fserving-excel-files-from-python-web-apps\u002F","Serving Excel Files from Python Web Apps"," — offering the workbook for download beside the table.",[2399,2400,2401],"style",{},"html pre.shiki code .sMTad, html code.shiki .sMTad{--shiki-default:#6F42C1;--shiki-dark:#FFB757}html pre.shiki code .srMev, html code.shiki .srMev{--shiki-default:#032F62;--shiki-dark:#ADDCFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s-kum, html code.shiki .s-kum{--shiki-default:#D73A49;--shiki-dark:#FF9492}html pre.shiki code .skGVy, html code.shiki .skGVy{--shiki-default:#24292E;--shiki-dark:#F0F3F6}html pre.shiki code .sP0c6, html code.shiki .sP0c6{--shiki-default:#005CC5;--shiki-dark:#91CBFF}html pre.shiki code .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html pre.shiki code .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}html pre.shiki code .s_Opv, html code.shiki .s_Opv{--shiki-default:#6F42C1;--shiki-dark:#DBB7FF}html pre.shiki code .s-wDw, html code.shiki .s-wDw{--shiki-default:#6A737D;--shiki-dark:#BDC4CC}",{"title":182,"searchDepth":237,"depth":237,"links":2403},[2404,2405,2406,2407,2408,2409,2410,2411,2412,2413,2414,2415],{"id":174,"depth":237,"text":175},{"id":433,"depth":237,"text":434},{"id":529,"depth":237,"text":530},{"id":918,"depth":237,"text":919},{"id":1176,"depth":237,"text":1177},{"id":1301,"depth":237,"text":1302},{"id":1478,"depth":237,"text":1479},{"id":1997,"depth":237,"text":1998},{"id":2232,"depth":237,"text":2233},{"id":2322,"depth":237,"text":2323},{"id":2335,"depth":237,"text":2336},{"id":2367,"depth":237,"text":2368},"2026-09-23","Turn a worksheet into clean HTML for a web page, an email or an intranet report — pandas to_html, number and date formatting, Styler for highlights, captions and accessible headers, and several sheets on one page.","md",[2420,2422,2424,2426],{"q":2341,"a":2421},"Read it with pd.read_excel and call to_html on the DataFrame. Pass index=False to drop the row numbers, and formatters or float_format to control how numbers appear.",{"q":2347,"a":2423},"No. to_html converts values, not cell formatting. Re-create the formatting that matters with CSS classes or with pandas Styler, which lets you colour cells based on their values.",{"q":2353,"a":2425},"Yes, by default. to_html escapes characters like \u003C and & so a value such as \u003Cscript> is shown as text. Only turn escaping off for content you generated yourself.",{"q":2363,"a":2427},"Build the HTML with to_html or Styler.to_html, use inline styles rather than a stylesheet because many mail clients strip style blocks, and send it as the HTML part of the message.","convert an excel sheet to an html table with python",null,{"breadcrumb":2431},[2432,2435,2438],{"name":2433,"item":2434},"Home","\u002F",{"name":2436,"item":2437},"Getting Started with Python Excel Automation","\u002Fgetting-started-with-python-excel-automation\u002F",{"name":22,"item":21},"\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Fconvert-an-excel-sheet-to-an-html-table",{"title":2441,"description":2442},"Convert Excel to an HTML Table with Python (pandas to_html, Styler)","Convert an Excel sheet to an HTML table with pandas — formatting numbers and dates, escaping, CSS classes, Styler highlights, accessible captions and headers, and combining several sheets into one HTML page.","convert-an-excel-sheet-to-an-html-table","getting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Fconvert-an-excel-sheet-to-an-html-table\u002Findex",[2446,2447],"file-formats","pandas","how-to","-FEEmymhCpr76vLf8ShxcRif2zYgPlJYFYT9hF69-sw",[2451,2455],{"title":2452,"path":2453,"stem":2454,"children":-1},"Convert an Excel Sheet to a Markdown Table with Python","\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Fconvert-an-excel-sheet-to-a-markdown-table","getting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Fconvert-an-excel-sheet-to-a-markdown-table\u002Findex",{"title":2382,"path":2456,"stem":2457,"children":-1},"\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Fconvert-an-excel-sheet-to-json-with-python","getting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Fconvert-an-excel-sheet-to-json-with-python\u002Findex",[2459,2461],{"path":2460,"title":22},"\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions",{"path":2462,"title":2436},"\u002Fgetting-started-with-python-excel-automation",[],[2465,2468,2471,2475,2478,2482],{"path":2466,"title":2467,"kind":2448},"\u002Fadvanced-data-transformation-and-cleaning\u002Freading-excel-with-polars-and-arrow\u002Fconvert-excel-files-to-parquet-with-python","Convert Excel Files to Parquet with Python",{"path":2469,"title":2470,"kind":2448},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-large-excel-files-in-python\u002Fconvert-excel-to-csv-with-python","Convert Excel to CSV with Python",{"path":2472,"title":2473,"kind":2474},"\u002Fgetting-started-with-python-excel-automation\u002Fchoosing-a-python-excel-library\u002Fexcel-vs-csv-vs-parquet-for-python-data-pipelines","Excel vs CSV vs Parquet for Python Data Pipelines","compare",{"path":2476,"title":2477,"kind":2474},"\u002Fgetting-started-with-python-excel-automation\u002Fchoosing-a-python-excel-library\u002Fpick-an-excel-engine-for-xlsx-xlsm-xls-xlsb-and-ods","Pick an Excel Engine for .xlsx, .xlsm, .xls, .xlsb and .ods",{"path":2479,"title":2480,"kind":2481},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Ffix-garbled-characters-in-excel-data","Fix Garbled Characters Like \"CafÃ©\" and \"â€™\" in Excel Data","fix",{"path":2483,"title":2484,"kind":2448},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Fextract-vba-macro-code-from-an-excel-file","Extract VBA Macro Code from an Excel File",1790972059070]