[{"data":1,"prerenderedAt":2410},["ShallowReactive",2],{"doc:\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fadd-hyperlinks-to-excel-cells-with-python":3,"surround:\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fadd-hyperlinks-to-excel-cells-with-python":2403},{"id":4,"title":5,"body":6,"dateModified":2375,"datePublished":2375,"description":2376,"extension":2377,"faq":2378,"meta":2387,"navigation":206,"path":2396,"seo":2397,"slug":2399,"stem":2400,"type":2401,"__hash__":2402},"docs\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fadd-hyperlinks-to-excel-cells-with-python\u002Findex.md","Add Hyperlinks to Excel Cells with Python",{"type":7,"value":8,"toc":2359},"minimark",[9,19,140,145,174,178,314,325,329,332,571,574,578,656,659,963,966,970,990,993,996,1000,1007,1176,1191,1195,1205,1492,1507,1514,1518,1521,1797,1805,1809,1909,1913,1923,2077,2080,2084,2168,2171,2174,2250,2257,2261,2284,2288,2295,2301,2307,2313,2317,2355],[10,11,12,13,18],"p",{},"Links turn a multi-sheet workbook from a stack of tabs into something navigable: a contents page that\njumps to each section, an identifier column where every row opens the record it came from, a footer\npointing back to the dashboard. openpyxl writes all three, and the one thing it does not do\nautomatically is make them look like links. This guide is part of\n",[14,15,17],"a",{"href":16},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002F","Styling Excel Cells with openpyxl",".",[20,21,29,30,29,34,29,38,29,45,29,54,29,61,29,65,29,69,29,74,29,79,29,83,29,86,29,91,29,96,29,99,29,102,29,107,29,112,29,115,29,118,29,123,29,128,29,131,29,134],"svg",{"viewBox":22,"role":23,"ariaLabelledBy":24,"xmlns":27,"style":28},"0 0 760 256","img",[25,26],"hl-kinds-t","hl-kinds-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:760px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[31,32,33],"title",{"id":25},"Four link targets and how each is written",[35,36,37],"desc",{"id":26},"A web address is a plain URL, another sheet needs a quoted location, an email address uses the mailto scheme, and another file is best written as a relative external target.",[39,40],"rect",{"x":41,"y":41,"width":42,"height":43,"fill":44},"0","760","256","#ffffff",[39,46],{"x":47,"y":48,"width":49,"height":50,"rx":51,"fill":52,"stroke":53},"18","30","724","34","8","#e7ebef","var(--line,#cdd5e6)",[55,56,60],"text",{"x":57,"y":58,"style":59},"126.6","52","font-size:12px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","Target",[55,62,64],{"x":63,"y":58,"style":59},"361.9","openpyxl",[55,66,68],{"x":67,"y":58,"style":59},"615.3000000000001","xlsxwriter",[39,70],{"x":47,"y":71,"width":49,"height":50,"rx":51,"fill":72,"stroke":73},"67","#f0f4ff","var(--brand,#5b5cf0)",[55,75,78],{"x":57,"y":76,"style":77},"88.0","font-size:12px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","a web page",[55,80,82],{"x":63,"y":76,"style":81},"font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","the URL as a string",[55,84,85],{"x":67,"y":76,"style":81},"write_url(url)",[39,87],{"x":47,"y":88,"width":49,"height":50,"rx":51,"fill":89,"stroke":90},"107","#d9f4f1","var(--teal,#0f9488)",[55,92,95],{"x":57,"y":93,"style":94},"128.0","font-size:12px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","another sheet",[55,97,98],{"x":63,"y":93,"style":81},"Hyperlink(location=...)",[55,100,101],{"x":67,"y":93,"style":81},"internal:'Sheet'!A1",[39,103],{"x":47,"y":104,"width":49,"height":50,"rx":51,"fill":105,"stroke":106},"147","#fdefd8","var(--gold,#b4740a)",[55,108,111],{"x":57,"y":109,"style":110},"168.0","font-size:12px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","an email address",[55,113,114],{"x":63,"y":109,"style":81},"mailto: URL",[55,116,117],{"x":67,"y":109,"style":81},"mailto:someone@…",[39,119],{"x":47,"y":120,"width":49,"height":50,"rx":51,"fill":121,"stroke":122},"187","#fee8f2","var(--accent,#d81b73)",[55,124,127],{"x":57,"y":125,"style":126},"208.0","font-size:12px;font-weight:700;fill:var(--accent,#d81b73);text-anchor:middle","another file",[55,129,130],{"x":63,"y":125,"style":81},"a relative path",[55,132,133],{"x":67,"y":125,"style":81},"external:reports\u002Fx.xlsx",[55,135,139],{"x":136,"y":137,"style":138},"380.0","244","font-size:12.5px;font-weight:400;fill:var(--muted,#5b6780);text-anchor:middle","the link is one line; the appearance is a second",[141,142,144],"h2",{"id":143},"prerequisites","Prerequisites",[146,147,152],"pre",{"className":148,"code":149,"language":150,"meta":151,"style":151},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install openpyxl xlsxwriter\n","bash","",[153,154,155],"code",{"__ignoreMap":151},[156,157,160,164,168,171],"span",{"class":158,"line":159},"line",1,[156,161,163],{"class":162},"sMTad","pip",[156,165,167],{"class":166},"srMev"," install",[156,169,170],{"class":166}," openpyxl",[156,172,173],{"class":166}," xlsxwriter\n",[141,175,177],{"id":176},"a-link-to-a-web-address","A link to a web address",[146,179,183],{"className":180,"code":181,"language":182,"meta":151,"style":151},"language-python shiki shiki-themes github-light github-dark-high-contrast","from openpyxl import Workbook\n\nbook = Workbook()\nsheet = book.active\nsheet.title = \"Orders\"\n\ncell = sheet[\"A1\"]\ncell.value = \"Open the order in the CRM\"\ncell.hyperlink = \"https:\u002F\u002Fcrm.example.com\u002Forders\u002F1001\"\ncell.style = \"Hyperlink\"\n\nbook.save(\"links.xlsx\")\n","python",[153,184,185,201,208,220,231,242,247,264,275,286,297,302],{"__ignoreMap":151},[156,186,187,191,195,198],{"class":158,"line":159},[156,188,190],{"class":189},"s-kum","from",[156,192,194],{"class":193},"skGVy"," openpyxl ",[156,196,197],{"class":189},"import",[156,199,200],{"class":193}," Workbook\n",[156,202,204],{"class":158,"line":203},2,[156,205,207],{"emptyLinePlaceholder":206},true,"\n",[156,209,211,214,217],{"class":158,"line":210},3,[156,212,213],{"class":193},"book ",[156,215,216],{"class":189},"=",[156,218,219],{"class":193}," Workbook()\n",[156,221,223,226,228],{"class":158,"line":222},4,[156,224,225],{"class":193},"sheet ",[156,227,216],{"class":189},[156,229,230],{"class":193}," book.active\n",[156,232,234,237,239],{"class":158,"line":233},5,[156,235,236],{"class":193},"sheet.title ",[156,238,216],{"class":189},[156,240,241],{"class":166}," \"Orders\"\n",[156,243,245],{"class":158,"line":244},6,[156,246,207],{"emptyLinePlaceholder":206},[156,248,250,253,255,258,261],{"class":158,"line":249},7,[156,251,252],{"class":193},"cell ",[156,254,216],{"class":189},[156,256,257],{"class":193}," sheet[",[156,259,260],{"class":166},"\"A1\"",[156,262,263],{"class":193},"]\n",[156,265,267,270,272],{"class":158,"line":266},8,[156,268,269],{"class":193},"cell.value ",[156,271,216],{"class":189},[156,273,274],{"class":166}," \"Open the order in the CRM\"\n",[156,276,278,281,283],{"class":158,"line":277},9,[156,279,280],{"class":193},"cell.hyperlink ",[156,282,216],{"class":189},[156,284,285],{"class":166}," \"https:\u002F\u002Fcrm.example.com\u002Forders\u002F1001\"\n",[156,287,289,292,294],{"class":158,"line":288},10,[156,290,291],{"class":193},"cell.style ",[156,293,216],{"class":189},[156,295,296],{"class":166}," \"Hyperlink\"\n",[156,298,300],{"class":158,"line":299},11,[156,301,207],{"emptyLinePlaceholder":206},[156,303,305,308,311],{"class":158,"line":304},12,[156,306,307],{"class":193},"book.save(",[156,309,310],{"class":166},"\"links.xlsx\"",[156,312,313],{"class":193},")\n",[10,315,316,317,320,321,324],{},"Assigning a string to ",[153,318,319],{},"cell.hyperlink"," is the short form; openpyxl builds the relationship for you.\n",[153,322,323],{},"cell.style = \"Hyperlink\""," is the line people leave out — without it the cell is clickable and looks\nexactly like plain text, which means nobody clicks it.",[141,326,328],{"id":327},"linking-a-whole-column","Linking a whole column",[10,330,331],{},"The realistic case is one link per row, built from an identifier.",[146,333,335],{"className":180,"code":334,"language":182,"meta":151,"style":151},"from openpyxl import Workbook\n\norders = [(1001, \"A-100\", 12400.0), (1002, \"B-200\", 9800.5), (1003, \"C-300\", 15320.25)]\n\nbook = Workbook()\nsheet = book.active\nsheet.append([\"Order\", \"SKU\", \"Revenue\"])\n\nfor order_id, sku, revenue in orders:\n    sheet.append([order_id, sku, revenue])\n    cell = sheet.cell(row=sheet.max_row, column=1)\n    cell.hyperlink = f\"https:\u002F\u002Fcrm.example.com\u002Forders\u002F{order_id}\"\n    cell.style = \"Hyperlink\"\n\nsheet.column_dimensions[\"A\"].width = 12\nbook.save(\"orders-linked.xlsx\")\n",[153,336,337,347,351,410,414,422,430,451,455,469,474,503,529,539,544,561],{"__ignoreMap":151},[156,338,339,341,343,345],{"class":158,"line":159},[156,340,190],{"class":189},[156,342,194],{"class":193},[156,344,197],{"class":189},[156,346,200],{"class":193},[156,348,349],{"class":158,"line":203},[156,350,207],{"emptyLinePlaceholder":206},[156,352,353,356,358,361,365,368,371,373,376,379,382,384,387,389,392,394,397,399,402,404,407],{"class":158,"line":210},[156,354,355],{"class":193},"orders ",[156,357,216],{"class":189},[156,359,360],{"class":193}," [(",[156,362,364],{"class":363},"sP0c6","1001",[156,366,367],{"class":193},", ",[156,369,370],{"class":166},"\"A-100\"",[156,372,367],{"class":193},[156,374,375],{"class":363},"12400.0",[156,377,378],{"class":193},"), (",[156,380,381],{"class":363},"1002",[156,383,367],{"class":193},[156,385,386],{"class":166},"\"B-200\"",[156,388,367],{"class":193},[156,390,391],{"class":363},"9800.5",[156,393,378],{"class":193},[156,395,396],{"class":363},"1003",[156,398,367],{"class":193},[156,400,401],{"class":166},"\"C-300\"",[156,403,367],{"class":193},[156,405,406],{"class":363},"15320.25",[156,408,409],{"class":193},")]\n",[156,411,412],{"class":158,"line":222},[156,413,207],{"emptyLinePlaceholder":206},[156,415,416,418,420],{"class":158,"line":233},[156,417,213],{"class":193},[156,419,216],{"class":189},[156,421,219],{"class":193},[156,423,424,426,428],{"class":158,"line":244},[156,425,225],{"class":193},[156,427,216],{"class":189},[156,429,230],{"class":193},[156,431,432,435,438,440,443,445,448],{"class":158,"line":249},[156,433,434],{"class":193},"sheet.append([",[156,436,437],{"class":166},"\"Order\"",[156,439,367],{"class":193},[156,441,442],{"class":166},"\"SKU\"",[156,444,367],{"class":193},[156,446,447],{"class":166},"\"Revenue\"",[156,449,450],{"class":193},"])\n",[156,452,453],{"class":158,"line":266},[156,454,207],{"emptyLinePlaceholder":206},[156,456,457,460,463,466],{"class":158,"line":277},[156,458,459],{"class":189},"for",[156,461,462],{"class":193}," order_id, sku, revenue ",[156,464,465],{"class":189},"in",[156,467,468],{"class":193}," orders:\n",[156,470,471],{"class":158,"line":288},[156,472,473],{"class":193},"    sheet.append([order_id, sku, revenue])\n",[156,475,476,479,481,484,488,490,493,496,498,501],{"class":158,"line":299},[156,477,478],{"class":193},"    cell ",[156,480,216],{"class":189},[156,482,483],{"class":193}," sheet.cell(",[156,485,487],{"class":486},"sa561","row",[156,489,216],{"class":189},[156,491,492],{"class":193},"sheet.max_row, ",[156,494,495],{"class":486},"column",[156,497,216],{"class":189},[156,499,500],{"class":363},"1",[156,502,313],{"class":193},[156,504,505,508,510,513,516,520,523,526],{"class":158,"line":304},[156,506,507],{"class":193},"    cell.hyperlink ",[156,509,216],{"class":189},[156,511,512],{"class":189}," f",[156,514,515],{"class":166},"\"https:\u002F\u002Fcrm.example.com\u002Forders\u002F",[156,517,519],{"class":518},"sSjpA","{",[156,521,522],{"class":193},"order_id",[156,524,525],{"class":518},"}",[156,527,528],{"class":166},"\"\n",[156,530,532,535,537],{"class":158,"line":531},13,[156,533,534],{"class":193},"    cell.style ",[156,536,216],{"class":189},[156,538,296],{"class":166},[156,540,542],{"class":158,"line":541},14,[156,543,207],{"emptyLinePlaceholder":206},[156,545,547,550,553,556,558],{"class":158,"line":546},15,[156,548,549],{"class":193},"sheet.column_dimensions[",[156,551,552],{"class":166},"\"A\"",[156,554,555],{"class":193},"].width ",[156,557,216],{"class":189},[156,559,560],{"class":363}," 12\n",[156,562,564,566,569],{"class":158,"line":563},16,[156,565,307],{"class":193},[156,567,568],{"class":166},"\"orders-linked.xlsx\"",[156,570,313],{"class":193},[10,572,573],{},"Writing the value first and then attaching the link keeps the cell's displayed text as the order\nnumber rather than the URL, which is what a reader wants. The alternative — writing the URL as the\nvalue — produces a column of unreadable addresses.",[141,575,577],{"id":576},"internal-links-a-contents-sheet","Internal links: a contents sheet",[20,579,29,584,29,587,29,590,29,593,29,598,29,605,29,610,29,615,29,620,29,625,29,628,29,631,29,634,29,638,29,641,29,644,29,649,29,652],{"viewBox":580,"role":23,"ariaLabelledBy":581,"xmlns":27,"style":28},"0 0 760 232",[582,583],"hl-nav-t","hl-nav-d",[31,585,586],{"id":582},"What makes a multi-tab workbook navigable",[35,588,589],{"id":583},"A contents sheet links out to every section and each section carries a link back, so a reader moves between tabs without hunting along the tab bar.",[39,591],{"x":41,"y":41,"width":42,"height":592,"fill":44},"232",[55,594,597],{"x":136,"y":595,"style":596},"32","font-size:13px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","two directions",[39,599],{"x":600,"y":601,"width":125,"height":602,"rx":603,"fill":72,"stroke":73,"style":604},"24.0","74","96","12","stroke-width:2px",[55,606,609],{"x":93,"y":607,"style":608},"114","font-size:14px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Contents sheet",[55,611,614],{"x":93,"y":612,"style":613},"136","font-size:11.5px;font-weight:400;fill:var(--muted,#5b6780);text-anchor:middle","one row per section",[158,616],{"x1":617,"y1":618,"x2":619,"y2":618,"stroke":73,"style":604},"237.0","122.0","269.0",[621,622],"polygon",{"points":623,"fill":624},"269.0,122.0 260.0,117.0 260.0,127.0","#5b5cf0",[39,626],{"x":627,"y":601,"width":125,"height":602,"rx":603,"fill":72,"stroke":73,"style":604},"276.0",[55,629,630],{"x":136,"y":607,"style":608},"section sheets",[55,632,633],{"x":136,"y":612,"style":613},"each linked from above",[158,635],{"x1":636,"y1":618,"x2":637,"y2":618,"stroke":73,"style":604},"489.0","521.0",[621,639],{"points":640,"fill":624},"521.0,122.0 512.0,117.0 512.0,127.0",[39,642],{"x":643,"y":601,"width":125,"height":602,"rx":603,"fill":89,"stroke":90,"style":604},"528.0",[55,645,648],{"x":646,"y":607,"style":647},"632.0","font-size:14px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","back links",[55,650,651],{"x":646,"y":612,"style":613},"return in one click",[55,653,655],{"x":136,"y":654,"style":138},"210","the reciprocal link is three lines and doubles the usefulness",[10,657,658],{},"Links within a workbook use a location rather than a URL, and they are what make a twelve-tab report\nnavigable.",[146,660,662],{"className":180,"code":661,"language":182,"meta":151,"style":151},"from openpyxl import Workbook\nfrom openpyxl.worksheet.hyperlink import Hyperlink\n\nbook = Workbook()\ncontents = book.active\ncontents.title = \"Contents\"\ncontents[\"A1\"] = \"Sections\"\n\nfor index, name in enumerate([\"Summary\", \"North\", \"South\", \"West\"], start=2):\n    book.create_sheet(name)\n    cell = contents.cell(row=index, column=1, value=name)\n    cell.hyperlink = Hyperlink(ref=cell.coordinate, location=f\"'{name}'!A1\")\n    cell.style = \"Hyperlink\"\n\n    back = book[name][\"A1\"]\n    back.value = \"← Contents\"\n    back.hyperlink = Hyperlink(ref=\"A1\", location=\"'Contents'!A1\")\n    back.style = \"Hyperlink\"\n\ncontents.column_dimensions[\"A\"].width = 24\nbook.save(\"navigable.xlsx\")\n",[153,663,664,674,686,690,698,707,717,732,736,783,788,820,860,868,872,886,896,923,933,938,953],{"__ignoreMap":151},[156,665,666,668,670,672],{"class":158,"line":159},[156,667,190],{"class":189},[156,669,194],{"class":193},[156,671,197],{"class":189},[156,673,200],{"class":193},[156,675,676,678,681,683],{"class":158,"line":203},[156,677,190],{"class":189},[156,679,680],{"class":193}," openpyxl.worksheet.hyperlink ",[156,682,197],{"class":189},[156,684,685],{"class":193}," Hyperlink\n",[156,687,688],{"class":158,"line":210},[156,689,207],{"emptyLinePlaceholder":206},[156,691,692,694,696],{"class":158,"line":222},[156,693,213],{"class":193},[156,695,216],{"class":189},[156,697,219],{"class":193},[156,699,700,703,705],{"class":158,"line":233},[156,701,702],{"class":193},"contents ",[156,704,216],{"class":189},[156,706,230],{"class":193},[156,708,709,712,714],{"class":158,"line":244},[156,710,711],{"class":193},"contents.title ",[156,713,216],{"class":189},[156,715,716],{"class":166}," \"Contents\"\n",[156,718,719,722,724,727,729],{"class":158,"line":249},[156,720,721],{"class":193},"contents[",[156,723,260],{"class":166},[156,725,726],{"class":193},"] ",[156,728,216],{"class":189},[156,730,731],{"class":166}," \"Sections\"\n",[156,733,734],{"class":158,"line":266},[156,735,207],{"emptyLinePlaceholder":206},[156,737,738,740,743,745,748,751,754,756,759,761,764,766,769,772,775,777,780],{"class":158,"line":277},[156,739,459],{"class":189},[156,741,742],{"class":193}," index, name ",[156,744,465],{"class":189},[156,746,747],{"class":363}," enumerate",[156,749,750],{"class":193},"([",[156,752,753],{"class":166},"\"Summary\"",[156,755,367],{"class":193},[156,757,758],{"class":166},"\"North\"",[156,760,367],{"class":193},[156,762,763],{"class":166},"\"South\"",[156,765,367],{"class":193},[156,767,768],{"class":166},"\"West\"",[156,770,771],{"class":193},"], ",[156,773,774],{"class":486},"start",[156,776,216],{"class":189},[156,778,779],{"class":363},"2",[156,781,782],{"class":193},"):\n",[156,784,785],{"class":158,"line":288},[156,786,787],{"class":193},"    book.create_sheet(name)\n",[156,789,790,792,794,797,799,801,804,806,808,810,812,815,817],{"class":158,"line":299},[156,791,478],{"class":193},[156,793,216],{"class":189},[156,795,796],{"class":193}," contents.cell(",[156,798,487],{"class":486},[156,800,216],{"class":189},[156,802,803],{"class":193},"index, ",[156,805,495],{"class":486},[156,807,216],{"class":189},[156,809,500],{"class":363},[156,811,367],{"class":193},[156,813,814],{"class":486},"value",[156,816,216],{"class":189},[156,818,819],{"class":193},"name)\n",[156,821,822,824,826,829,832,834,837,840,842,845,848,850,853,855,858],{"class":158,"line":304},[156,823,507],{"class":193},[156,825,216],{"class":189},[156,827,828],{"class":193}," Hyperlink(",[156,830,831],{"class":486},"ref",[156,833,216],{"class":189},[156,835,836],{"class":193},"cell.coordinate, ",[156,838,839],{"class":486},"location",[156,841,216],{"class":189},[156,843,844],{"class":189},"f",[156,846,847],{"class":166},"\"'",[156,849,519],{"class":518},[156,851,852],{"class":193},"name",[156,854,525],{"class":518},[156,856,857],{"class":166},"'!A1\"",[156,859,313],{"class":193},[156,861,862,864,866],{"class":158,"line":531},[156,863,534],{"class":193},[156,865,216],{"class":189},[156,867,296],{"class":166},[156,869,870],{"class":158,"line":541},[156,871,207],{"emptyLinePlaceholder":206},[156,873,874,877,879,882,884],{"class":158,"line":546},[156,875,876],{"class":193},"    back ",[156,878,216],{"class":189},[156,880,881],{"class":193}," book[name][",[156,883,260],{"class":166},[156,885,263],{"class":193},[156,887,888,891,893],{"class":158,"line":563},[156,889,890],{"class":193},"    back.value ",[156,892,216],{"class":189},[156,894,895],{"class":166}," \"← Contents\"\n",[156,897,899,902,904,906,908,910,912,914,916,918,921],{"class":158,"line":898},17,[156,900,901],{"class":193},"    back.hyperlink ",[156,903,216],{"class":189},[156,905,828],{"class":193},[156,907,831],{"class":486},[156,909,216],{"class":189},[156,911,260],{"class":166},[156,913,367],{"class":193},[156,915,839],{"class":486},[156,917,216],{"class":189},[156,919,920],{"class":166},"\"'Contents'!A1\"",[156,922,313],{"class":193},[156,924,926,929,931],{"class":158,"line":925},18,[156,927,928],{"class":193},"    back.style ",[156,930,216],{"class":189},[156,932,296],{"class":166},[156,934,936],{"class":158,"line":935},19,[156,937,207],{"emptyLinePlaceholder":206},[156,939,941,944,946,948,950],{"class":158,"line":940},20,[156,942,943],{"class":193},"contents.column_dimensions[",[156,945,552],{"class":166},[156,947,555],{"class":193},[156,949,216],{"class":189},[156,951,952],{"class":363}," 24\n",[156,954,956,958,961],{"class":158,"line":955},21,[156,957,307],{"class":193},[156,959,960],{"class":166},"\"navigable.xlsx\"",[156,962,313],{"class":193},[10,964,965],{},"Quoting the sheet name in the location handles the ones containing spaces, and it costs nothing on\nthe ones that do not. The reciprocal \"back to contents\" link in each sheet is what turns a list of\njumps into actual navigation — it is three lines and it is the difference between a workbook people\nexplore and one they scroll.",[141,967,969],{"id":968},"the-hyperlink-formula-and-when-to-prefer-it","The HYPERLINK formula, and when to prefer it",[146,971,973],{"className":180,"code":972,"language":182,"meta":151,"style":151},"sheet[\"D2\"] = '=HYPERLINK(\"https:\u002F\u002Fcrm.example.com\u002Forders\u002F\" & A2, \"Open \" & A2)'\n",[153,974,975],{"__ignoreMap":151},[156,976,977,980,983,985,987],{"class":158,"line":159},[156,978,979],{"class":193},"sheet[",[156,981,982],{"class":166},"\"D2\"",[156,984,726],{"class":193},[156,986,216],{"class":189},[156,988,989],{"class":166}," '=HYPERLINK(\"https:\u002F\u002Fcrm.example.com\u002Forders\u002F\" & A2, \"Open \" & A2)'\n",[10,991,992],{},"A formula is the better choice when the target depends on other cells and those cells may change:\nthe link follows the value automatically. A real hyperlink is better when the target is fixed,\nbecause it survives being sorted, copied into another workbook, or opened in a viewer that does not\ncalculate formulas.",[10,994,995],{},"A practical rule: use the relationship for links you generate once, and the formula for links that\nhave to track a cell the recipient will edit.",[141,997,999],{"id":998},"links-in-xlsxwriter","Links in xlsxwriter",[10,1001,1002,1003,1006],{},"For a workbook built from scratch, ",[153,1004,1005],{},"write_url"," does both halves in one call — the link and the\nappearance.",[146,1008,1010],{"className":180,"code":1009,"language":182,"meta":151,"style":151},"import xlsxwriter\n\nbook = xlsxwriter.Workbook(\"links-xw.xlsx\")\nsheet = book.add_worksheet(\"Orders\")\nlink = book.add_format({\"font_color\": \"#4338CA\", \"underline\": 1})\n\nsheet.write_url(\"A1\", \"https:\u002F\u002Fcrm.example.com\u002Forders\u002F1001\", link, \"Order 1001\")\nsheet.write_url(\"A2\", \"internal:'Summary'!A1\", link, \"Go to summary\")\nsheet.write_url(\"A3\", \"mailto:reports@example.com\", link, \"Email the team\")\nsheet.write_url(\"A4\", \"external:reports\u002Faugust.xlsx\", link, \"August workbook\")\nbook.add_worksheet(\"Summary\")\nbook.close()\n",[153,1011,1012,1018,1022,1036,1050,1081,1085,1105,1124,1143,1162,1171],{"__ignoreMap":151},[156,1013,1014,1016],{"class":158,"line":159},[156,1015,197],{"class":189},[156,1017,173],{"class":193},[156,1019,1020],{"class":158,"line":203},[156,1021,207],{"emptyLinePlaceholder":206},[156,1023,1024,1026,1028,1031,1034],{"class":158,"line":210},[156,1025,213],{"class":193},[156,1027,216],{"class":189},[156,1029,1030],{"class":193}," xlsxwriter.Workbook(",[156,1032,1033],{"class":166},"\"links-xw.xlsx\"",[156,1035,313],{"class":193},[156,1037,1038,1040,1042,1045,1048],{"class":158,"line":222},[156,1039,225],{"class":193},[156,1041,216],{"class":189},[156,1043,1044],{"class":193}," book.add_worksheet(",[156,1046,1047],{"class":166},"\"Orders\"",[156,1049,313],{"class":193},[156,1051,1052,1055,1057,1060,1063,1066,1069,1071,1074,1076,1078],{"class":158,"line":233},[156,1053,1054],{"class":193},"link ",[156,1056,216],{"class":189},[156,1058,1059],{"class":193}," book.add_format({",[156,1061,1062],{"class":166},"\"font_color\"",[156,1064,1065],{"class":193},": ",[156,1067,1068],{"class":166},"\"#4338CA\"",[156,1070,367],{"class":193},[156,1072,1073],{"class":166},"\"underline\"",[156,1075,1065],{"class":193},[156,1077,500],{"class":363},[156,1079,1080],{"class":193},"})\n",[156,1082,1083],{"class":158,"line":244},[156,1084,207],{"emptyLinePlaceholder":206},[156,1086,1087,1090,1092,1094,1097,1100,1103],{"class":158,"line":249},[156,1088,1089],{"class":193},"sheet.write_url(",[156,1091,260],{"class":166},[156,1093,367],{"class":193},[156,1095,1096],{"class":166},"\"https:\u002F\u002Fcrm.example.com\u002Forders\u002F1001\"",[156,1098,1099],{"class":193},", link, ",[156,1101,1102],{"class":166},"\"Order 1001\"",[156,1104,313],{"class":193},[156,1106,1107,1109,1112,1114,1117,1119,1122],{"class":158,"line":266},[156,1108,1089],{"class":193},[156,1110,1111],{"class":166},"\"A2\"",[156,1113,367],{"class":193},[156,1115,1116],{"class":166},"\"internal:'Summary'!A1\"",[156,1118,1099],{"class":193},[156,1120,1121],{"class":166},"\"Go to summary\"",[156,1123,313],{"class":193},[156,1125,1126,1128,1131,1133,1136,1138,1141],{"class":158,"line":277},[156,1127,1089],{"class":193},[156,1129,1130],{"class":166},"\"A3\"",[156,1132,367],{"class":193},[156,1134,1135],{"class":166},"\"mailto:reports@example.com\"",[156,1137,1099],{"class":193},[156,1139,1140],{"class":166},"\"Email the team\"",[156,1142,313],{"class":193},[156,1144,1145,1147,1150,1152,1155,1157,1160],{"class":158,"line":288},[156,1146,1089],{"class":193},[156,1148,1149],{"class":166},"\"A4\"",[156,1151,367],{"class":193},[156,1153,1154],{"class":166},"\"external:reports\u002Faugust.xlsx\"",[156,1156,1099],{"class":193},[156,1158,1159],{"class":166},"\"August workbook\"",[156,1161,313],{"class":193},[156,1163,1164,1167,1169],{"class":158,"line":299},[156,1165,1166],{"class":193},"book.add_worksheet(",[156,1168,753],{"class":166},[156,1170,313],{"class":193},[156,1172,1173],{"class":158,"line":304},[156,1174,1175],{"class":193},"book.close()\n",[10,1177,1178,1179,1182,1183,1186,1187,1190],{},"The four prefixes cover every target type: a bare URL, ",[153,1180,1181],{},"internal:"," for another sheet, ",[153,1184,1185],{},"mailto:"," for\nan address, and ",[153,1188,1189],{},"external:"," for another file relative to this one. That last is the one worth knowing\nabout — a monthly report can link to its predecessor without an absolute path that breaks the moment\nthe folder moves.",[141,1192,1194],{"id":1193},"adding-links-to-a-sheet-pandas-wrote","Adding links to a sheet pandas wrote",[10,1196,1197,1198,1201,1202,1204],{},"The common shape is a DataFrame written with ",[153,1199,1200],{},"to_excel"," and then decorated, and the order matters:\nattaching links before the data is written means they are overwritten, since ",[153,1203,1200],{}," rewrites the\ncells it covers.",[146,1206,1208],{"className":180,"code":1207,"language":182,"meta":151,"style":151},"import pandas as pd\nfrom openpyxl.styles import Font\n\norders = pd.DataFrame({\n    \"Order\": [1001, 1002, 1003],\n    \"SKU\": [\"A-100\", \"B-200\", \"C-300\"],\n    \"Revenue\": [12400.0, 9800.5, 15320.25],\n})\n\nwith pd.ExcelWriter(\"orders.xlsx\", engine=\"openpyxl\") as writer:\n    orders.to_excel(writer, sheet_name=\"Orders\", index=False)\n    sheet = writer.sheets[\"Orders\"]\n    link_font = Font(color=\"4338CA\", underline=\"single\")\n    for offset, order_id in enumerate(orders[\"Order\"], start=2):\n        cell = sheet.cell(row=offset, column=1)\n        cell.hyperlink = f\"https:\u002F\u002Fcrm.example.com\u002Forders\u002F{order_id}\"\n        cell.font = link_font\n",[153,1209,1210,1223,1235,1239,1248,1269,1288,1307,1311,1315,1344,1368,1382,1412,1439,1463,1482],{"__ignoreMap":151},[156,1211,1212,1214,1217,1220],{"class":158,"line":159},[156,1213,197],{"class":189},[156,1215,1216],{"class":193}," pandas ",[156,1218,1219],{"class":189},"as",[156,1221,1222],{"class":193}," pd\n",[156,1224,1225,1227,1230,1232],{"class":158,"line":203},[156,1226,190],{"class":189},[156,1228,1229],{"class":193}," openpyxl.styles ",[156,1231,197],{"class":189},[156,1233,1234],{"class":193}," Font\n",[156,1236,1237],{"class":158,"line":210},[156,1238,207],{"emptyLinePlaceholder":206},[156,1240,1241,1243,1245],{"class":158,"line":222},[156,1242,355],{"class":193},[156,1244,216],{"class":189},[156,1246,1247],{"class":193}," pd.DataFrame({\n",[156,1249,1250,1253,1256,1258,1260,1262,1264,1266],{"class":158,"line":233},[156,1251,1252],{"class":166},"    \"Order\"",[156,1254,1255],{"class":193},": [",[156,1257,364],{"class":363},[156,1259,367],{"class":193},[156,1261,381],{"class":363},[156,1263,367],{"class":193},[156,1265,396],{"class":363},[156,1267,1268],{"class":193},"],\n",[156,1270,1271,1274,1276,1278,1280,1282,1284,1286],{"class":158,"line":244},[156,1272,1273],{"class":166},"    \"SKU\"",[156,1275,1255],{"class":193},[156,1277,370],{"class":166},[156,1279,367],{"class":193},[156,1281,386],{"class":166},[156,1283,367],{"class":193},[156,1285,401],{"class":166},[156,1287,1268],{"class":193},[156,1289,1290,1293,1295,1297,1299,1301,1303,1305],{"class":158,"line":249},[156,1291,1292],{"class":166},"    \"Revenue\"",[156,1294,1255],{"class":193},[156,1296,375],{"class":363},[156,1298,367],{"class":193},[156,1300,391],{"class":363},[156,1302,367],{"class":193},[156,1304,406],{"class":363},[156,1306,1268],{"class":193},[156,1308,1309],{"class":158,"line":266},[156,1310,1080],{"class":193},[156,1312,1313],{"class":158,"line":277},[156,1314,207],{"emptyLinePlaceholder":206},[156,1316,1317,1320,1323,1326,1328,1331,1333,1336,1339,1341],{"class":158,"line":288},[156,1318,1319],{"class":189},"with",[156,1321,1322],{"class":193}," pd.ExcelWriter(",[156,1324,1325],{"class":166},"\"orders.xlsx\"",[156,1327,367],{"class":193},[156,1329,1330],{"class":486},"engine",[156,1332,216],{"class":189},[156,1334,1335],{"class":166},"\"openpyxl\"",[156,1337,1338],{"class":193},") ",[156,1340,1219],{"class":189},[156,1342,1343],{"class":193}," writer:\n",[156,1345,1346,1349,1352,1354,1356,1358,1361,1363,1366],{"class":158,"line":299},[156,1347,1348],{"class":193},"    orders.to_excel(writer, ",[156,1350,1351],{"class":486},"sheet_name",[156,1353,216],{"class":189},[156,1355,1047],{"class":166},[156,1357,367],{"class":193},[156,1359,1360],{"class":486},"index",[156,1362,216],{"class":189},[156,1364,1365],{"class":363},"False",[156,1367,313],{"class":193},[156,1369,1370,1373,1375,1378,1380],{"class":158,"line":304},[156,1371,1372],{"class":193},"    sheet ",[156,1374,216],{"class":189},[156,1376,1377],{"class":193}," writer.sheets[",[156,1379,1047],{"class":166},[156,1381,263],{"class":193},[156,1383,1384,1387,1389,1392,1395,1397,1400,1402,1405,1407,1410],{"class":158,"line":531},[156,1385,1386],{"class":193},"    link_font ",[156,1388,216],{"class":189},[156,1390,1391],{"class":193}," Font(",[156,1393,1394],{"class":486},"color",[156,1396,216],{"class":189},[156,1398,1399],{"class":166},"\"4338CA\"",[156,1401,367],{"class":193},[156,1403,1404],{"class":486},"underline",[156,1406,216],{"class":189},[156,1408,1409],{"class":166},"\"single\"",[156,1411,313],{"class":193},[156,1413,1414,1417,1420,1422,1424,1427,1429,1431,1433,1435,1437],{"class":158,"line":541},[156,1415,1416],{"class":189},"    for",[156,1418,1419],{"class":193}," offset, order_id ",[156,1421,465],{"class":189},[156,1423,747],{"class":363},[156,1425,1426],{"class":193},"(orders[",[156,1428,437],{"class":166},[156,1430,771],{"class":193},[156,1432,774],{"class":486},[156,1434,216],{"class":189},[156,1436,779],{"class":363},[156,1438,782],{"class":193},[156,1440,1441,1444,1446,1448,1450,1452,1455,1457,1459,1461],{"class":158,"line":546},[156,1442,1443],{"class":193},"        cell ",[156,1445,216],{"class":189},[156,1447,483],{"class":193},[156,1449,487],{"class":486},[156,1451,216],{"class":189},[156,1453,1454],{"class":193},"offset, ",[156,1456,495],{"class":486},[156,1458,216],{"class":189},[156,1460,500],{"class":363},[156,1462,313],{"class":193},[156,1464,1465,1468,1470,1472,1474,1476,1478,1480],{"class":158,"line":563},[156,1466,1467],{"class":193},"        cell.hyperlink ",[156,1469,216],{"class":189},[156,1471,512],{"class":189},[156,1473,515],{"class":166},[156,1475,519],{"class":518},[156,1477,522],{"class":193},[156,1479,525],{"class":518},[156,1481,528],{"class":166},[156,1483,1484,1487,1489],{"class":158,"line":898},[156,1485,1486],{"class":193},"        cell.font ",[156,1488,216],{"class":189},[156,1490,1491],{"class":193}," link_font\n",[10,1493,1494,1495,1498,1499,1502,1503,1506],{},"Reaching through ",[153,1496,1497],{},"writer.sheets"," means the decoration happens before the file is saved, so there is\nno second open-and-rewrite pass. Using an explicit ",[153,1500,1501],{},"Font"," rather than the named ",[153,1504,1505],{},"Hyperlink"," style is\nworth doing here because it keeps the colour under your control — the built-in style follows the\nworkbook theme, which can be an unexpected purple in a template somebody else designed.",[10,1508,1509,1510,18],{},"The wider pattern of writing with pandas and finishing with openpyxl is set out in\n",[14,1511,1513],{"href":1512},"\u002Fgetting-started-with-python-excel-automation\u002Fchoosing-a-python-excel-library\u002Fopenpyxl-vs-pandas-for-excel-automation\u002F","openpyxl vs pandas for Excel Automation",[141,1515,1517],{"id":1516},"checking-that-the-links-point-somewhere","Checking that the links point somewhere",[10,1519,1520],{},"A workbook full of links to a system that has been renamed is worse than one with none, because the\nreader trusts them. Where the targets follow a pattern, a short check before distribution is cheap\ninsurance — and for internal links it is entirely local.",[146,1522,1524],{"className":180,"code":1523,"language":182,"meta":151,"style":151},"from openpyxl import load_workbook\n\ndef broken_internal_links(path: str) -> list[str]:\n    book = load_workbook(path)\n    names = set(book.sheetnames)\n    problems = []\n    for sheet in book.worksheets:\n        for row in sheet.iter_rows():\n            for cell in row:\n                link = cell.hyperlink\n                if link is None or not getattr(link, \"location\", None):\n                    continue\n                target = link.location.split(\"!\")[0].strip(\"'\")\n                if target not in names:\n                    problems.append(f\"{sheet.title}!{cell.coordinate} -> missing sheet {target!r}\")\n    return problems\n\nprint(broken_internal_links(\"navigable.xlsx\"))\n",[153,1525,1526,1537,1541,1564,1574,1587,1597,1609,1622,1635,1645,1681,1686,1712,1728,1772,1780,1784],{"__ignoreMap":151},[156,1527,1528,1530,1532,1534],{"class":158,"line":159},[156,1529,190],{"class":189},[156,1531,194],{"class":193},[156,1533,197],{"class":189},[156,1535,1536],{"class":193}," load_workbook\n",[156,1538,1539],{"class":158,"line":203},[156,1540,207],{"emptyLinePlaceholder":206},[156,1542,1543,1546,1550,1553,1556,1559,1561],{"class":158,"line":210},[156,1544,1545],{"class":189},"def",[156,1547,1549],{"class":1548},"s_Opv"," broken_internal_links",[156,1551,1552],{"class":193},"(path: ",[156,1554,1555],{"class":363},"str",[156,1557,1558],{"class":193},") -> list[",[156,1560,1555],{"class":363},[156,1562,1563],{"class":193},"]:\n",[156,1565,1566,1569,1571],{"class":158,"line":222},[156,1567,1568],{"class":193},"    book ",[156,1570,216],{"class":189},[156,1572,1573],{"class":193}," load_workbook(path)\n",[156,1575,1576,1579,1581,1584],{"class":158,"line":233},[156,1577,1578],{"class":193},"    names ",[156,1580,216],{"class":189},[156,1582,1583],{"class":363}," set",[156,1585,1586],{"class":193},"(book.sheetnames)\n",[156,1588,1589,1592,1594],{"class":158,"line":244},[156,1590,1591],{"class":193},"    problems ",[156,1593,216],{"class":189},[156,1595,1596],{"class":193}," []\n",[156,1598,1599,1601,1604,1606],{"class":158,"line":249},[156,1600,1416],{"class":189},[156,1602,1603],{"class":193}," sheet ",[156,1605,465],{"class":189},[156,1607,1608],{"class":193}," book.worksheets:\n",[156,1610,1611,1614,1617,1619],{"class":158,"line":266},[156,1612,1613],{"class":189},"        for",[156,1615,1616],{"class":193}," row ",[156,1618,465],{"class":189},[156,1620,1621],{"class":193}," sheet.iter_rows():\n",[156,1623,1624,1627,1630,1632],{"class":158,"line":277},[156,1625,1626],{"class":189},"            for",[156,1628,1629],{"class":193}," cell ",[156,1631,465],{"class":189},[156,1633,1634],{"class":193}," row:\n",[156,1636,1637,1640,1642],{"class":158,"line":288},[156,1638,1639],{"class":193},"                link ",[156,1641,216],{"class":189},[156,1643,1644],{"class":193}," cell.hyperlink\n",[156,1646,1647,1650,1653,1656,1659,1662,1665,1668,1671,1674,1676,1679],{"class":158,"line":299},[156,1648,1649],{"class":189},"                if",[156,1651,1652],{"class":193}," link ",[156,1654,1655],{"class":189},"is",[156,1657,1658],{"class":363}," None",[156,1660,1661],{"class":189}," or",[156,1663,1664],{"class":189}," not",[156,1666,1667],{"class":363}," getattr",[156,1669,1670],{"class":193},"(link, ",[156,1672,1673],{"class":166},"\"location\"",[156,1675,367],{"class":193},[156,1677,1678],{"class":363},"None",[156,1680,782],{"class":193},[156,1682,1683],{"class":158,"line":304},[156,1684,1685],{"class":189},"                    continue\n",[156,1687,1688,1691,1693,1696,1699,1702,1704,1707,1710],{"class":158,"line":531},[156,1689,1690],{"class":193},"                target ",[156,1692,216],{"class":189},[156,1694,1695],{"class":193}," link.location.split(",[156,1697,1698],{"class":166},"\"!\"",[156,1700,1701],{"class":193},")[",[156,1703,41],{"class":363},[156,1705,1706],{"class":193},"].strip(",[156,1708,1709],{"class":166},"\"'\"",[156,1711,313],{"class":193},[156,1713,1714,1716,1719,1722,1725],{"class":158,"line":541},[156,1715,1649],{"class":189},[156,1717,1718],{"class":193}," target ",[156,1720,1721],{"class":189},"not",[156,1723,1724],{"class":189}," in",[156,1726,1727],{"class":193}," names:\n",[156,1729,1730,1733,1735,1738,1740,1743,1745,1748,1750,1753,1755,1758,1760,1763,1766,1768,1770],{"class":158,"line":546},[156,1731,1732],{"class":193},"                    problems.append(",[156,1734,844],{"class":189},[156,1736,1737],{"class":166},"\"",[156,1739,519],{"class":518},[156,1741,1742],{"class":193},"sheet.title",[156,1744,525],{"class":518},[156,1746,1747],{"class":166},"!",[156,1749,519],{"class":518},[156,1751,1752],{"class":193},"cell.coordinate",[156,1754,525],{"class":518},[156,1756,1757],{"class":166}," -> missing sheet ",[156,1759,519],{"class":518},[156,1761,1762],{"class":193},"target",[156,1764,1765],{"class":189},"!r",[156,1767,525],{"class":518},[156,1769,1737],{"class":166},[156,1771,313],{"class":193},[156,1773,1774,1777],{"class":158,"line":563},[156,1775,1776],{"class":189},"    return",[156,1778,1779],{"class":193}," problems\n",[156,1781,1782],{"class":158,"line":898},[156,1783,207],{"emptyLinePlaceholder":206},[156,1785,1786,1789,1792,1794],{"class":158,"line":925},[156,1787,1788],{"class":363},"print",[156,1790,1791],{"class":193},"(broken_internal_links(",[156,1793,960],{"class":166},[156,1795,1796],{"class":193},"))\n",[10,1798,1799,1800,1804],{},"Internal links are the ones worth checking automatically, because they break for a reason entirely\nwithin your control — a renamed or removed sheet — and Excel gives no warning until somebody clicks.\nFolding this into the pre-send checks in\n",[14,1801,1803],{"href":1802},"\u002Fautomating-reporting-workflows\u002Ferror-handling-and-logging-in-excel-automation\u002Fvalidate-an-excel-report-before-sending-it\u002F","Validate an Excel Report Before Sending It","\ncosts one function call.",[141,1806,1808],{"id":1807},"common-pitfalls","Common pitfalls",[1810,1811,1812,1828],"table",{},[1813,1814,1815],"thead",{},[1816,1817,1818,1822,1825],"tr",{},[1819,1820,1821],"th",{},"Symptom",[1819,1823,1824],{},"Cause",[1819,1826,1827],{},"Fix",[1829,1830,1831,1849,1860,1871,1884,1895],"tbody",{},[1816,1832,1833,1837,1844],{},[1834,1835,1836],"td",{},"The link works but looks like plain text",[1834,1838,1839,1840,1843],{},"Only ",[153,1841,1842],{},"hyperlink"," was set",[1834,1845,1846,1847],{},"Also set ",[153,1848,323],{},[1816,1850,1851,1854,1857],{},[1834,1852,1853],{},"The cell shows a long URL",[1834,1855,1856],{},"The URL was written as the value",[1834,1858,1859],{},"Write the label as the value, attach the link separately",[1816,1861,1862,1865,1868],{},[1834,1863,1864],{},"Excel reports a broken internal link",[1834,1866,1867],{},"The target sheet does not exist, or the name is unquoted",[1834,1869,1870],{},"Create the sheet first; quote names with spaces",[1816,1872,1873,1876,1881],{},[1834,1874,1875],{},"Links vanish after a rewrite",[1834,1877,1878,1879],{},"The cell was overwritten by a later ",[153,1880,1200],{},[1834,1882,1883],{},"Attach links after the data is written",[1816,1885,1886,1889,1892],{},[1834,1887,1888],{},"Only 65,530 links are written",[1834,1890,1891],{},"Excel's per-sheet hyperlink limit",[1834,1893,1894],{},"Use the HYPERLINK formula past that count",[1816,1896,1897,1900,1903],{},[1834,1898,1899],{},"Relative file links break",[1834,1901,1902],{},"The workbook moved",[1834,1904,1905,1906,1908],{},"Prefer ",[153,1907,1189],{}," relative targets, or absolute URLs",[141,1910,1912],{"id":1911},"removing-links-you-did-not-want","Removing links you did not want",[10,1914,1915,1916,1918,1919,1922],{},"Data pasted from a web page or an email export often arrives with hundreds of unwanted ",[153,1917,1185],{}," and\n",[153,1920,1921],{},"http:"," links attached. Stripping them is a short loop, and worth doing before the sheet is\ndistributed.",[146,1924,1926],{"className":180,"code":1925,"language":182,"meta":151,"style":151},"from openpyxl import load_workbook\n\nbook = load_workbook(\"pasted.xlsx\")\nremoved = 0\nfor sheet in book.worksheets:\n    for row in sheet.iter_rows():\n        for cell in row:\n            if cell.hyperlink is not None:\n                cell.hyperlink = None\n                cell.style = \"Normal\"\n                removed += 1\nbook.save(\"cleaned.xlsx\")\nprint(f\"removed {removed} hyperlink(s)\")\n",[153,1927,1928,1938,1942,1956,1966,1976,1986,1996,2013,2023,2033,2044,2053],{"__ignoreMap":151},[156,1929,1930,1932,1934,1936],{"class":158,"line":159},[156,1931,190],{"class":189},[156,1933,194],{"class":193},[156,1935,197],{"class":189},[156,1937,1536],{"class":193},[156,1939,1940],{"class":158,"line":203},[156,1941,207],{"emptyLinePlaceholder":206},[156,1943,1944,1946,1948,1951,1954],{"class":158,"line":210},[156,1945,213],{"class":193},[156,1947,216],{"class":189},[156,1949,1950],{"class":193}," load_workbook(",[156,1952,1953],{"class":166},"\"pasted.xlsx\"",[156,1955,313],{"class":193},[156,1957,1958,1961,1963],{"class":158,"line":222},[156,1959,1960],{"class":193},"removed ",[156,1962,216],{"class":189},[156,1964,1965],{"class":363}," 0\n",[156,1967,1968,1970,1972,1974],{"class":158,"line":233},[156,1969,459],{"class":189},[156,1971,1603],{"class":193},[156,1973,465],{"class":189},[156,1975,1608],{"class":193},[156,1977,1978,1980,1982,1984],{"class":158,"line":244},[156,1979,1416],{"class":189},[156,1981,1616],{"class":193},[156,1983,465],{"class":189},[156,1985,1621],{"class":193},[156,1987,1988,1990,1992,1994],{"class":158,"line":249},[156,1989,1613],{"class":189},[156,1991,1629],{"class":193},[156,1993,465],{"class":189},[156,1995,1634],{"class":193},[156,1997,1998,2001,2004,2006,2008,2010],{"class":158,"line":266},[156,1999,2000],{"class":189},"            if",[156,2002,2003],{"class":193}," cell.hyperlink ",[156,2005,1655],{"class":189},[156,2007,1664],{"class":189},[156,2009,1658],{"class":363},[156,2011,2012],{"class":193},":\n",[156,2014,2015,2018,2020],{"class":158,"line":277},[156,2016,2017],{"class":193},"                cell.hyperlink ",[156,2019,216],{"class":189},[156,2021,2022],{"class":363}," None\n",[156,2024,2025,2028,2030],{"class":158,"line":288},[156,2026,2027],{"class":193},"                cell.style ",[156,2029,216],{"class":189},[156,2031,2032],{"class":166}," \"Normal\"\n",[156,2034,2035,2038,2041],{"class":158,"line":299},[156,2036,2037],{"class":193},"                removed ",[156,2039,2040],{"class":189},"+=",[156,2042,2043],{"class":363}," 1\n",[156,2045,2046,2048,2051],{"class":158,"line":304},[156,2047,307],{"class":193},[156,2049,2050],{"class":166},"\"cleaned.xlsx\"",[156,2052,313],{"class":193},[156,2054,2055,2057,2060,2062,2065,2067,2070,2072,2075],{"class":158,"line":531},[156,2056,1788],{"class":363},[156,2058,2059],{"class":193},"(",[156,2061,844],{"class":189},[156,2063,2064],{"class":166},"\"removed ",[156,2066,519],{"class":518},[156,2068,2069],{"class":193},"removed",[156,2071,525],{"class":518},[156,2073,2074],{"class":166}," hyperlink(s)\"",[156,2076,313],{"class":193},[10,2078,2079],{},"Resetting the style as well as the link is the part that completes it — a cell left in the Hyperlink\nstyle still looks clickable, which is arguably worse than one that is.",[141,2081,2083],{"id":2082},"performance-and-scale","Performance and scale",[20,2085,29,2091,29,2094,29,2097,29,2101,29,2107,29,2114,29,2121,29,2127,29,2131,29,2134,29,2138,29,2143,29,2147,29,2150,29,2154,29,2159,29,2163],{"viewBox":2086,"role":23,"ariaLabelledBy":2087,"xmlns":27,"style":2090},"0 0 720 196",[2088,2089],"hl-cost-t","hl-cost-d","width:100%;max-width:720px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[31,2092,2093],{"id":2088},"File size with links on every row of a 50,000-row sheet",[35,2095,2096],{"id":2089},"Stored hyperlink relationships add substantially to the file and approach Excel's per-sheet limit, while HYPERLINK formulas keep the file small at the cost of needing formula evaluation.",[39,2098],{"x":41,"y":41,"width":2099,"height":2100,"fill":44},"720","196",[55,2102,2106],{"x":2103,"y":2104,"style":2105},"20","56","font-size:12px;font-weight:600;fill:var(--text,#172033);text-anchor:start","50,000 relationships",[39,2108],{"x":2109,"y":2110,"width":2111,"height":2112,"rx":2113,"fill":52,"stroke":53},"200","40","371.6","26","6",[39,2115],{"x":2116,"y":2117,"width":2118,"height":2119,"rx":2120,"fill":121,"stroke":122},"201","41","369.6","24","5",[55,2122,2126],{"x":2123,"y":2124,"style":2125},"583.6","58","font-size:12px;font-weight:700;fill:var(--accent,#d81b73);text-anchor:start","near the limit",[55,2128,2130],{"x":2103,"y":2129,"style":2105},"100","HYPERLINK formulas",[39,2132],{"x":2109,"y":2133,"width":2111,"height":2112,"rx":2113,"fill":52,"stroke":53},"84",[39,2135],{"x":2116,"y":2136,"width":2137,"height":2119,"rx":2120,"fill":89,"stroke":90},"85","78.3",[55,2139,2142],{"x":2123,"y":2140,"style":2141},"102","font-size:12px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:start","no limit applies",[55,2144,2146],{"x":2103,"y":2145,"style":2105},"144","no links",[39,2148],{"x":2109,"y":2149,"width":2111,"height":2112,"rx":2113,"fill":52,"stroke":53},"128",[39,2151],{"x":2116,"y":2152,"width":2153,"height":2119,"rx":2120,"fill":52,"stroke":53},"129","48.4",[55,2155,2158],{"x":2123,"y":2156,"style":2157},"146","font-size:12px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:start","baseline",[55,2160,2162],{"x":2103,"y":2103,"style":2161},"font-size:11.5px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:start","relative cost",[55,2164,2167],{"x":2165,"y":2166,"style":138},"360.0","186","Excel caps a worksheet at 65,530 stored hyperlinks",[10,2169,2170],{},"Each hyperlink is a relationship entry in the file's XML, so a sheet with fifty thousand of them is\nnoticeably larger and slower to open than the same data without. Excel's own limit is 65,530 per\nworksheet, and files approaching it behave badly well before they reach it.",[10,2172,2173],{},"Where a large table needs links on every row, the HYPERLINK formula is the lighter option: it is a\nformula rather than a stored relationship, so the file stays small and the limit does not apply.",[146,2175,2177],{"className":180,"code":2176,"language":182,"meta":151,"style":151},"for row in range(2, 50002):\n    sheet.cell(row=row, column=4).value = (\n        f'=HYPERLINK(\"https:\u002F\u002Fcrm.example.com\u002Forders\u002F\"&A{row}, \"Open\")'\n    )\n",[153,2178,2179,2201,2228,2245],{"__ignoreMap":151},[156,2180,2181,2183,2185,2187,2190,2192,2194,2196,2199],{"class":158,"line":159},[156,2182,459],{"class":189},[156,2184,1616],{"class":193},[156,2186,465],{"class":189},[156,2188,2189],{"class":363}," range",[156,2191,2059],{"class":193},[156,2193,779],{"class":363},[156,2195,367],{"class":193},[156,2197,2198],{"class":363},"50002",[156,2200,782],{"class":193},[156,2202,2203,2206,2208,2210,2213,2215,2217,2220,2223,2225],{"class":158,"line":203},[156,2204,2205],{"class":193},"    sheet.cell(",[156,2207,487],{"class":486},[156,2209,216],{"class":189},[156,2211,2212],{"class":193},"row, ",[156,2214,495],{"class":486},[156,2216,216],{"class":189},[156,2218,2219],{"class":363},"4",[156,2221,2222],{"class":193},").value ",[156,2224,216],{"class":189},[156,2226,2227],{"class":193}," (\n",[156,2229,2230,2233,2236,2238,2240,2242],{"class":158,"line":210},[156,2231,2232],{"class":189},"        f",[156,2234,2235],{"class":166},"'=HYPERLINK(\"https:\u002F\u002Fcrm.example.com\u002Forders\u002F\"&A",[156,2237,519],{"class":518},[156,2239,487],{"class":193},[156,2241,525],{"class":518},[156,2243,2244],{"class":166},", \"Open\")'\n",[156,2246,2247],{"class":158,"line":222},[156,2248,2249],{"class":193},"    )\n",[10,2251,2252,2253,18],{},"The trade is that the links only work where formulas are evaluated, which rules out some viewers and\nany downstream tool reading values rather than formulas — the distinction covered in\n",[14,2254,2256],{"href":2255},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fread-formula-results-with-openpyxl-data-only\u002F","Read Formula Results with openpyxl data_only",[141,2258,2260],{"id":2259},"conclusion","Conclusion",[10,2262,2263,2264,2266,2267,2269,2270,2272,2273,2275,2276,2278,2279,2266,2281,2283],{},"Set both ",[153,2265,319],{}," and ",[153,2268,323],{},", and keep the readable label as the cell\nvalue rather than the URL. Use a ",[153,2271,1505],{}," with a quoted ",[153,2274,839],{}," for internal jumps, add the\nreciprocal link back so navigation works in both directions, and prefer ",[153,2277,1005],{}," with its\n",[153,2280,1181],{},[153,2282,1189],{}," prefixes when building with xlsxwriter. Past a few thousand rows, switch\nto the HYPERLINK formula to keep the file small.",[141,2285,2287],{"id":2286},"frequently-asked-questions","Frequently asked questions",[10,2289,2290,2294],{},[2291,2292,2293],"strong",{},"Why does my hyperlink look like ordinary text?","\nSetting cell.hyperlink attaches the link but does not change the appearance — Excel's blue underline comes from the Hyperlink cell style. Set cell.style = 'Hyperlink' as well, or apply a font with a colour and underline yourself.",[10,2296,2297,2300],{},[2291,2298,2299],{},"What is the difference between the HYPERLINK formula and cell.hyperlink?","\ncell.hyperlink writes a real hyperlink relationship into the file, which survives sorting and is what Excel creates when you insert a link by hand. The HYPERLINK formula is a formula whose result happens to be clickable, and it recalculates — useful when the target is computed from other cells.",[10,2302,2303,2306],{},[2291,2304,2305],{},"How do I link to another sheet in the same workbook?","\nUse a location-style target: cell.hyperlink = Hyperlink(ref=cell.coordinate, location=\"'Summary'!A1\"). Quote the sheet name when it contains a space, and remember the sheet must exist or Excel reports a broken link on click.",[10,2308,2309,2312],{},[2291,2310,2311],{},"Can I remove every hyperlink from a sheet?","\nYes — iterate the cells and set cell.hyperlink = None. Worth doing on a sheet built from pasted content, where a column of email addresses arrives as several hundred mailto links nobody wants.",[141,2314,2316],{"id":2315},"related","Related",[2318,2319,2320,2327,2334,2341,2348],"ul",{},[2321,2322,2323,2324,2326],"li",{},"Up one level: ",[14,2325,17],{"href":16}," — the wider styling API these cells use.",[2321,2328,2329,2333],{},[14,2330,2332],{"href":2331},"\u002Fautomating-reporting-workflows\u002Fbuilding-multi-sheet-excel-dashboards\u002Fadd-a-table-of-contents-sheet-with-hyperlinks-in-excel\u002F","Add a Table of Contents Sheet with Hyperlinks in Excel"," — the navigation pattern built out in full.",[2321,2335,2336,2340],{},[14,2337,2339],{"href":2338},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fapply-a-reusable-style-theme-across-an-excel-report\u002F","Apply a Reusable Style Theme Across an Excel Report"," — named styles, of which Hyperlink is one.",[2321,2342,2343,2347],{},[14,2344,2346],{"href":2345},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fprotecting-and-sharing-excel-workbooks\u002Fadd-comments-and-notes-to-excel-cells-with-python\u002F","Add Comments and Notes to Excel Cells with Python"," — the other way to attach context to a cell.",[2321,2349,2350,2354],{},[14,2351,2353],{"href":2352},"\u002Fautomating-reporting-workflows\u002Fbuilding-multi-sheet-excel-dashboards\u002Fbuild-a-dashboard-sheet-with-charts-from-multiple-tabs\u002F","Build a Dashboard Sheet with Charts from Multiple Tabs"," — where internal links earn their place.",[2356,2357,2358],"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}",{"title":151,"searchDepth":203,"depth":203,"links":2360},[2361,2362,2363,2364,2365,2366,2367,2368,2369,2370,2371,2372,2373,2374],{"id":143,"depth":203,"text":144},{"id":176,"depth":203,"text":177},{"id":327,"depth":203,"text":328},{"id":576,"depth":203,"text":577},{"id":968,"depth":203,"text":969},{"id":998,"depth":203,"text":999},{"id":1193,"depth":203,"text":1194},{"id":1516,"depth":203,"text":1517},{"id":1807,"depth":203,"text":1808},{"id":1911,"depth":203,"text":1912},{"id":2082,"depth":203,"text":2083},{"id":2259,"depth":203,"text":2260},{"id":2286,"depth":203,"text":2287},{"id":2315,"depth":203,"text":2316},"2026-09-04","Attach web, sheet, email and file links with openpyxl and xlsxwriter — including the style line that makes them look clickable, and when the HYPERLINK formula is the better choice.","md",[2379,2381,2383,2385],{"q":2293,"a":2380},"Setting cell.hyperlink attaches the link but does not change the appearance — Excel's blue underline comes from the Hyperlink cell style. Set cell.style = 'Hyperlink' as well, or apply a font with a colour and underline yourself.",{"q":2299,"a":2382},"cell.hyperlink writes a real hyperlink relationship into the file, which survives sorting and is what Excel creates when you insert a link by hand. The HYPERLINK formula is a formula whose result happens to be clickable, and it recalculates — useful when the target is computed from other cells.",{"q":2305,"a":2384},"Use a location-style target: cell.hyperlink = Hyperlink(ref=cell.coordinate, location=\"'Summary'!A1\"). Quote the sheet name when it contains a space, and remember the sheet must exist or Excel reports a broken link on click.",{"q":2311,"a":2386},"Yes — iterate the cells and set cell.hyperlink = None. Worth doing on a sheet built from pasted content, where a column of email addresses arrives as several hundred mailto links nobody wants.",{"breadcrumb":2388},[2389,2392,2395],{"name":2390,"item":2391},"Home","\u002F",{"name":2393,"item":2394},"Formatting and Charting Excel Reports with Python","\u002Fformatting-and-charting-excel-reports-with-python\u002F",{"name":17,"item":16},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fadd-hyperlinks-to-excel-cells-with-python",{"title":5,"description":2398},"Write Excel hyperlinks from Python: cell.hyperlink plus the Hyperlink style, internal sheet jumps, xlsxwriter's internal and external prefixes, link removal and the 65,530 limit.","add-hyperlinks-to-excel-cells-with-python","formatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fadd-hyperlinks-to-excel-cells-with-python\u002Findex","how-to","Gyc6G8uKKaVuwmJ9JsH73lMhv9MkMgjloxcC9RUlRhQ",[2404,2407],{"title":17,"path":2405,"stem":2406,"children":-1},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl","formatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Findex",{"title":2339,"path":2408,"stem":2409,"children":-1},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fapply-a-reusable-style-theme-across-an-excel-report","formatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fapply-a-reusable-style-theme-across-an-excel-report\u002Findex",1788710162346]