[{"data":1,"prerenderedAt":2487},["ShallowReactive",2],{"doc:\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fadd-text-boxes-and-shapes-to-excel-with-xlsxwriter":3,"surround:\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fadd-text-boxes-and-shapes-to-excel-with-xlsxwriter":2451,"ancestors:\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fadd-text-boxes-and-shapes-to-excel-with-xlsxwriter":2460,"children:\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fadd-text-boxes-and-shapes-to-excel-with-xlsxwriter":2465,"related:\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fadd-text-boxes-and-shapes-to-excel-with-xlsxwriter":2466},{"id":4,"title":5,"body":6,"dateModified":2416,"datePublished":2416,"description":2417,"extension":2418,"faq":2419,"keyword":2428,"kind":2429,"meta":2430,"navigation":99,"path":2440,"seo":2441,"slug":2444,"stem":2445,"topics":2446,"type":2449,"__hash__":2450},"docs\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fadd-text-boxes-and-shapes-to-excel-with-xlsxwriter\u002Findex.md","Add Text Boxes and Shapes to Excel with XlsxWriter",{"type":7,"value":8,"toc":2402},"minimark",[9,24,29,60,67,71,77,379,423,574,578,589,874,883,887,894,1074,1082,1219,1225,1327,1331,1334,1661,1682,1686,1689,1819,1841,1845,1857,1861,1864,2079,2082,2280,2284,2325,2329,2337,2341,2347,2353,2359,2365,2369,2398],[10,11,12,13,17,18,23],"p",{},"A generated report often needs a sentence of commentary that does not belong in any cell: \"Revenue up 12% on last month — driven by the North region\", a \"figures unaudited\" warning, or a note pointing readers at the method. Typing it into a cell makes it fight with column widths and get sorted along with the data. A text box floats over the sheet instead, sized and styled independently of the grid. XlsxWriter adds them with ",[14,15,16],"code",{},"insert_textbox()",", and with a handful of options a box can carry fills, borders, fonts, rotated text and a hyperlink. This page goes through those options, the cell-linked text feature and its LibreOffice caveat, and how to place a box beneath a table whose length changes each run. It belongs to ",[19,20,22],"a",{"href":21},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002F","Building Excel Reports with XlsxWriter",".",[25,26,28],"h2",{"id":27},"prerequisites","Prerequisites",[30,31,36],"pre",{"className":32,"code":33,"language":34,"meta":35,"style":35},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install xlsxwriter pandas pypdf\n","bash","",[14,37,38],{"__ignoreMap":35},[39,40,43,47,51,54,57],"span",{"class":41,"line":42},"line",1,[39,44,46],{"class":45},"sMTad","pip",[39,48,50],{"class":49},"srMev"," install",[39,52,53],{"class":49}," xlsxwriter",[39,55,56],{"class":49}," pandas",[39,58,59],{"class":49}," pypdf\n",[10,61,62,63,66],{},"The examples write new workbooks, which is what XlsxWriter does — it cannot edit an existing file. LibreOffice (",[14,64,65],{},"soffice",") is used in Step 6 to render the result and check which text appears; it is optional.",[25,68,70],{"id":69},"step-1-a-first-text-box","Step 1 — A first text box",[10,72,73,76],{},[14,74,75],{},"insert_textbox(cell, text, options)"," anchors the box's top-left corner at a cell and draws it on top of the grid:",[30,78,82],{"className":79,"code":80,"language":81,"meta":35,"style":35},"language-python shiki shiki-themes github-light github-dark-high-contrast","import xlsxwriter\n\nbook = xlsxwriter.Workbook(\"textbox_basic.xlsx\")\nsheet = book.add_worksheet(\"Report\")\nsheet.write_column(\"A1\", [\"Month\", \"Jan\", \"Feb\", \"Mar\"])\nsheet.write_column(\"B1\", [\"Revenue\", 41200, 44100, 49400])\nsheet.insert_textbox(\"D2\", \"Figures are unaudited and may change.\", {\n    \"width\": 260, \"height\": 60,\n    \"font\": {\"bold\": True, \"color\": \"#4338CA\", \"size\": 12},\n    \"fill\": {\"color\": \"#EEF2FF\"},\n    \"line\": {\"color\": \"#4338CA\", \"width\": 1.25},\n    \"align\": {\"vertical\": \"middle\", \"horizontal\": \"center\"},\n})\nbook.close()\nprint(\"text box anchored at D2, 260 x 60 px\")\n","python",[14,83,84,94,101,119,135,169,200,217,242,282,299,325,353,359,365],{"__ignoreMap":35},[39,85,86,90],{"class":41,"line":42},[39,87,89],{"class":88},"s-kum","import",[39,91,93],{"class":92},"skGVy"," xlsxwriter\n",[39,95,97],{"class":41,"line":96},2,[39,98,100],{"emptyLinePlaceholder":99},true,"\n",[39,102,104,107,110,113,116],{"class":41,"line":103},3,[39,105,106],{"class":92},"book ",[39,108,109],{"class":88},"=",[39,111,112],{"class":92}," xlsxwriter.Workbook(",[39,114,115],{"class":49},"\"textbox_basic.xlsx\"",[39,117,118],{"class":92},")\n",[39,120,122,125,127,130,133],{"class":41,"line":121},4,[39,123,124],{"class":92},"sheet ",[39,126,109],{"class":88},[39,128,129],{"class":92}," book.add_worksheet(",[39,131,132],{"class":49},"\"Report\"",[39,134,118],{"class":92},[39,136,138,141,144,147,150,153,156,158,161,163,166],{"class":41,"line":137},5,[39,139,140],{"class":92},"sheet.write_column(",[39,142,143],{"class":49},"\"A1\"",[39,145,146],{"class":92},", [",[39,148,149],{"class":49},"\"Month\"",[39,151,152],{"class":92},", ",[39,154,155],{"class":49},"\"Jan\"",[39,157,152],{"class":92},[39,159,160],{"class":49},"\"Feb\"",[39,162,152],{"class":92},[39,164,165],{"class":49},"\"Mar\"",[39,167,168],{"class":92},"])\n",[39,170,172,174,177,179,182,184,188,190,193,195,198],{"class":41,"line":171},6,[39,173,140],{"class":92},[39,175,176],{"class":49},"\"B1\"",[39,178,146],{"class":92},[39,180,181],{"class":49},"\"Revenue\"",[39,183,152],{"class":92},[39,185,187],{"class":186},"sP0c6","41200",[39,189,152],{"class":92},[39,191,192],{"class":186},"44100",[39,194,152],{"class":92},[39,196,197],{"class":186},"49400",[39,199,168],{"class":92},[39,201,203,206,209,211,214],{"class":41,"line":202},7,[39,204,205],{"class":92},"sheet.insert_textbox(",[39,207,208],{"class":49},"\"D2\"",[39,210,152],{"class":92},[39,212,213],{"class":49},"\"Figures are unaudited and may change.\"",[39,215,216],{"class":92},", {\n",[39,218,220,223,226,229,231,234,236,239],{"class":41,"line":219},8,[39,221,222],{"class":49},"    \"width\"",[39,224,225],{"class":92},": ",[39,227,228],{"class":186},"260",[39,230,152],{"class":92},[39,232,233],{"class":49},"\"height\"",[39,235,225],{"class":92},[39,237,238],{"class":186},"60",[39,240,241],{"class":92},",\n",[39,243,245,248,251,254,256,259,261,264,266,269,271,274,276,279],{"class":41,"line":244},9,[39,246,247],{"class":49},"    \"font\"",[39,249,250],{"class":92},": {",[39,252,253],{"class":49},"\"bold\"",[39,255,225],{"class":92},[39,257,258],{"class":186},"True",[39,260,152],{"class":92},[39,262,263],{"class":49},"\"color\"",[39,265,225],{"class":92},[39,267,268],{"class":49},"\"#4338CA\"",[39,270,152],{"class":92},[39,272,273],{"class":49},"\"size\"",[39,275,225],{"class":92},[39,277,278],{"class":186},"12",[39,280,281],{"class":92},"},\n",[39,283,285,288,290,292,294,297],{"class":41,"line":284},10,[39,286,287],{"class":49},"    \"fill\"",[39,289,250],{"class":92},[39,291,263],{"class":49},[39,293,225],{"class":92},[39,295,296],{"class":49},"\"#EEF2FF\"",[39,298,281],{"class":92},[39,300,302,305,307,309,311,313,315,318,320,323],{"class":41,"line":301},11,[39,303,304],{"class":49},"    \"line\"",[39,306,250],{"class":92},[39,308,263],{"class":49},[39,310,225],{"class":92},[39,312,268],{"class":49},[39,314,152],{"class":92},[39,316,317],{"class":49},"\"width\"",[39,319,225],{"class":92},[39,321,322],{"class":186},"1.25",[39,324,281],{"class":92},[39,326,328,331,333,336,338,341,343,346,348,351],{"class":41,"line":327},12,[39,329,330],{"class":49},"    \"align\"",[39,332,250],{"class":92},[39,334,335],{"class":49},"\"vertical\"",[39,337,225],{"class":92},[39,339,340],{"class":49},"\"middle\"",[39,342,152],{"class":92},[39,344,345],{"class":49},"\"horizontal\"",[39,347,225],{"class":92},[39,349,350],{"class":49},"\"center\"",[39,352,281],{"class":92},[39,354,356],{"class":41,"line":355},13,[39,357,358],{"class":92},"})\n",[39,360,362],{"class":41,"line":361},14,[39,363,364],{"class":92},"book.close()\n",[39,366,368,371,374,377],{"class":41,"line":367},15,[39,369,370],{"class":186},"print",[39,372,373],{"class":92},"(",[39,375,376],{"class":49},"\"text box anchored at D2, 260 x 60 px\"",[39,378,118],{"class":92},[10,380,381,384,385,388,389,384,392,394,395,398,399,402,403,152,406,152,409,412,413,152,416,152,419,422],{},[14,382,383],{},"width"," and ",[14,386,387],{},"height"," are in pixels (the default box is 192 × 120). ",[14,390,391],{},"fill",[14,393,41],{}," take the same colour and width settings as chart elements in XlsxWriter, ",[14,396,397],{},"font"," takes name, size, bold, italic, underline and colour, and ",[14,400,401],{},"align"," places the text vertically (",[14,404,405],{},"top",[14,407,408],{},"middle",[14,410,411],{},"bottom",") and horizontally (",[14,414,415],{},"left",[14,417,418],{},"center",[14,420,421],{},"right","). The box is not part of any cell, so sorting, filtering or resizing columns leaves its text alone.",[424,425,433,434,433,438,433,442,433,450,433,459,433,470,433,477,433,482,433,486,433,491,433,496,433,501,433,508,433,514,433,518,433,522,433,525,433,530,433,537,433,542,433,545,433,549,433,552,433,557,433,564,433,569,433,572],"svg",{"viewBox":426,"role":427,"ariaLabelledBy":428,"xmlns":431,"style":432},"4 0 752 142","img",[429,430],"tb-anatomy-t","tb-anatomy-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  ",[435,436,437],"title",{"id":429},"What a text box option dict controls",[439,440,441],"desc",{"id":430},"The insert_textbox options split into four groups. Geometry sets the anchor cell, width, height and offsets. Appearance sets fill, line and gradient. Text sets font, alignment and rotation. Behaviour sets the hyperlink, object positioning and description for screen readers.",[443,444],"rect",{"x":445,"y":446,"width":447,"height":448,"fill":449},"4","0","752","142","#ffffff",[443,451],{"x":452,"y":453,"width":454,"height":455,"rx":278,"fill":456,"stroke":457,"style":458},"20.0","16.0","153.0","110.5","#f0f4ff","var(--brand,#5b5cf0)","stroke-width:2px",[460,461,463],"g",{"transform":462},"translate(84.5,29.0) scale(1.000)",[464,465],"path",{"d":466,"fill":467,"stroke":468,"style":469},"M3 5h18v14H3z M3 10h18 M3 15h18 M9 5v14","none","var(--brand-strong,#4338ca)","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[471,472,476],"text",{"x":473,"y":474,"style":475},"96.5","75.5","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Geometry",[471,478,481],{"x":473,"y":479,"style":480},"95.0","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","anchor cell, size,",[471,483,485],{"x":473,"y":484,"style":480},"112.5","offsets",[41,487],{"x1":488,"y1":489,"x2":490,"y2":489,"stroke":457,"style":458},"178.0","71.2","200.0",[492,493],"polygon",{"points":494,"fill":495},"204.0,71.2 195.0,76.2 195.0,66.2","#5b5cf0",[443,497],{"x":498,"y":453,"width":454,"height":455,"rx":278,"fill":499,"stroke":500,"style":458},"209.0","#d9f4f1","var(--teal,#0f9488)",[460,502,504],{"transform":503},"translate(273.5,37.8) scale(1.000)",[464,505],{"d":506,"fill":467,"stroke":507,"style":469},"M4 5h16v14H4z M4 16l5-5 4 4 3-3 4 4 M15 9h.01","var(--teal-ink,#0b6157)",[471,509,513],{"x":510,"y":511,"style":512},"285.5","84.2","font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Appearance",[471,515,517],{"x":510,"y":516,"style":480},"103.8","fill, line, gradient",[41,519],{"x1":520,"y1":489,"x2":521,"y2":489,"stroke":457,"style":458},"367.0","389.0",[492,523],{"points":524,"fill":495},"393.0,71.2 384.0,76.2 384.0,66.2",[443,526],{"x":527,"y":453,"width":454,"height":455,"rx":278,"fill":528,"stroke":529,"style":458},"398.0","#fdefd8","var(--gold,#b4740a)",[460,531,533],{"transform":532},"translate(462.5,37.8) scale(1.000)",[464,534],{"d":535,"fill":467,"stroke":536,"style":469},"M6 3h9l4 4v14H6z M15 3v4h4","var(--gold-ink,#7a4e06)",[471,538,541],{"x":539,"y":511,"style":540},"474.5","font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","Text",[471,543,544],{"x":539,"y":516,"style":480},"font, align, rotation",[41,546],{"x1":547,"y1":489,"x2":548,"y2":489,"stroke":457,"style":458},"556.0","578.0",[492,550],{"points":551,"fill":495},"582.0,71.2 573.0,76.2 573.0,66.2",[443,553],{"x":554,"y":453,"width":454,"height":455,"rx":278,"fill":555,"stroke":556,"style":458},"587.0","#fee8f2","var(--accent,#f43f8f)",[460,558,560],{"transform":559},"translate(651.5,29.0) scale(1.000)",[464,561],{"d":562,"fill":467,"stroke":563,"style":469},"M10 14a4 4 0 0 0 5.7 0l3-3a4 4 0 0 0-5.7-5.7l-1 1 M14 10a4 4 0 0 0-5.7 0l-3 3a4 4 0 0 0 5.7 5.7l1-1","var(--accent-ink,#be185d)",[471,565,568],{"x":566,"y":474,"style":567},"663.5","font-size:13.5px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","Behaviour",[471,570,571],{"x":566,"y":479,"style":480},"link, positioning, alt",[471,573,471],{"x":566,"y":484,"style":480},[25,575,577],{"id":576},"step-2-multi-line-rotated-and-borderless-text","Step 2 — Multi-line, rotated and borderless text",[10,579,580,581,584,585,588],{},"A newline in the text starts a new line in the box. ",[14,582,583],{},"text_rotation"," turns the text, which suits a vertical \"DRAFT\" strip down the side of a page, and ",[14,586,587],{},"\"line\": {\"none\": True}"," removes the border so the box reads as a shaded note:",[30,590,592],{"className":79,"code":591,"language":81,"meta":35,"style":35},"book = xlsxwriter.Workbook(\"textbox_styles.xlsx\")\nsheet = book.add_worksheet(\"Report\")\nsheet.insert_textbox(\"B2\", \"Method\\n• Totals exclude returns\\n• Prices in EUR\", {\n    \"width\": 220, \"height\": 80,\n    \"line\": {\"none\": True},\n    \"fill\": {\"color\": \"#E0E7FF\"},\n})\nsheet.insert_textbox(\"F2\", \"DRAFT\", {\n    \"width\": 40, \"height\": 160,\n    \"text_rotation\": 90,\n    \"font\": {\"bold\": True, \"size\": 16, \"color\": \"#B91C1C\"},\n})\nsheet.insert_textbox(\"B9\", \"Quarter highlights\", {\n    \"width\": 220, \"height\": 40,\n    \"gradient\": {\"colors\": [\"#DDEBCF\", \"#9CB86E\"]},\n    \"font\": {\"bold\": True},\n})\nbook.close()\nprint(\"three styled boxes\")\n",[14,593,594,607,619,645,665,680,695,699,713,733,745,777,781,795,813,837,852,857,862],{"__ignoreMap":35},[39,595,596,598,600,602,605],{"class":41,"line":42},[39,597,106],{"class":92},[39,599,109],{"class":88},[39,601,112],{"class":92},[39,603,604],{"class":49},"\"textbox_styles.xlsx\"",[39,606,118],{"class":92},[39,608,609,611,613,615,617],{"class":41,"line":96},[39,610,124],{"class":92},[39,612,109],{"class":88},[39,614,129],{"class":92},[39,616,132],{"class":49},[39,618,118],{"class":92},[39,620,621,623,626,628,631,635,638,640,643],{"class":41,"line":103},[39,622,205],{"class":92},[39,624,625],{"class":49},"\"B2\"",[39,627,152],{"class":92},[39,629,630],{"class":49},"\"Method",[39,632,634],{"class":633},"sSjpA","\\n",[39,636,637],{"class":49},"• Totals exclude returns",[39,639,634],{"class":633},[39,641,642],{"class":49},"• Prices in EUR\"",[39,644,216],{"class":92},[39,646,647,649,651,654,656,658,660,663],{"class":41,"line":121},[39,648,222],{"class":49},[39,650,225],{"class":92},[39,652,653],{"class":186},"220",[39,655,152],{"class":92},[39,657,233],{"class":49},[39,659,225],{"class":92},[39,661,662],{"class":186},"80",[39,664,241],{"class":92},[39,666,667,669,671,674,676,678],{"class":41,"line":137},[39,668,304],{"class":49},[39,670,250],{"class":92},[39,672,673],{"class":49},"\"none\"",[39,675,225],{"class":92},[39,677,258],{"class":186},[39,679,281],{"class":92},[39,681,682,684,686,688,690,693],{"class":41,"line":171},[39,683,287],{"class":49},[39,685,250],{"class":92},[39,687,263],{"class":49},[39,689,225],{"class":92},[39,691,692],{"class":49},"\"#E0E7FF\"",[39,694,281],{"class":92},[39,696,697],{"class":41,"line":202},[39,698,358],{"class":92},[39,700,701,703,706,708,711],{"class":41,"line":219},[39,702,205],{"class":92},[39,704,705],{"class":49},"\"F2\"",[39,707,152],{"class":92},[39,709,710],{"class":49},"\"DRAFT\"",[39,712,216],{"class":92},[39,714,715,717,719,722,724,726,728,731],{"class":41,"line":244},[39,716,222],{"class":49},[39,718,225],{"class":92},[39,720,721],{"class":186},"40",[39,723,152],{"class":92},[39,725,233],{"class":49},[39,727,225],{"class":92},[39,729,730],{"class":186},"160",[39,732,241],{"class":92},[39,734,735,738,740,743],{"class":41,"line":284},[39,736,737],{"class":49},"    \"text_rotation\"",[39,739,225],{"class":92},[39,741,742],{"class":186},"90",[39,744,241],{"class":92},[39,746,747,749,751,753,755,757,759,761,763,766,768,770,772,775],{"class":41,"line":301},[39,748,247],{"class":49},[39,750,250],{"class":92},[39,752,253],{"class":49},[39,754,225],{"class":92},[39,756,258],{"class":186},[39,758,152],{"class":92},[39,760,273],{"class":49},[39,762,225],{"class":92},[39,764,765],{"class":186},"16",[39,767,152],{"class":92},[39,769,263],{"class":49},[39,771,225],{"class":92},[39,773,774],{"class":49},"\"#B91C1C\"",[39,776,281],{"class":92},[39,778,779],{"class":41,"line":327},[39,780,358],{"class":92},[39,782,783,785,788,790,793],{"class":41,"line":355},[39,784,205],{"class":92},[39,786,787],{"class":49},"\"B9\"",[39,789,152],{"class":92},[39,791,792],{"class":49},"\"Quarter highlights\"",[39,794,216],{"class":92},[39,796,797,799,801,803,805,807,809,811],{"class":41,"line":361},[39,798,222],{"class":49},[39,800,225],{"class":92},[39,802,653],{"class":186},[39,804,152],{"class":92},[39,806,233],{"class":49},[39,808,225],{"class":92},[39,810,721],{"class":186},[39,812,241],{"class":92},[39,814,815,818,820,823,826,829,831,834],{"class":41,"line":367},[39,816,817],{"class":49},"    \"gradient\"",[39,819,250],{"class":92},[39,821,822],{"class":49},"\"colors\"",[39,824,825],{"class":92},": [",[39,827,828],{"class":49},"\"#DDEBCF\"",[39,830,152],{"class":92},[39,832,833],{"class":49},"\"#9CB86E\"",[39,835,836],{"class":92},"]},\n",[39,838,840,842,844,846,848,850],{"class":41,"line":839},16,[39,841,247],{"class":49},[39,843,250],{"class":92},[39,845,253],{"class":49},[39,847,225],{"class":92},[39,849,258],{"class":186},[39,851,281],{"class":92},[39,853,855],{"class":41,"line":854},17,[39,856,358],{"class":92},[39,858,860],{"class":41,"line":859},18,[39,861,364],{"class":92},[39,863,865,867,869,872],{"class":41,"line":864},19,[39,866,370],{"class":186},[39,868,373],{"class":92},[39,870,871],{"class":49},"\"three styled boxes\"",[39,873,118],{"class":92},[10,875,876,878,879,882],{},[14,877,583],{}," accepts 0, 90, −90, 270 and 271 (stacked letters). A ",[14,880,881],{},"gradient"," takes two or more colours and replaces the solid fill. In a LibreOffice rendering, all three boxes appeared as set: the bullet list on three lines, the rotated red DRAFT strip and the green gradient.",[25,884,886],{"id":885},"step-3-link-a-box-to-a-cell-and-a-caveat","Step 3 — Link a box to a cell, and a caveat",[10,888,889,890,893],{},"Instead of fixed text, a box can display the value of a cell with ",[14,891,892],{},"textlink",". When the cell changes — say, a formula that builds a commentary sentence — the box follows:",[30,895,897],{"className":79,"code":896,"language":81,"meta":35,"style":35},"book = xlsxwriter.Workbook(\"textbox_linked.xlsx\")\nsheet = book.add_worksheet(\"Report\")\nsheet.write_column(\"A1\", [\"Month\", \"Jan\", \"Feb\", \"Mar\"])\nsheet.write_column(\"B1\", [\"Revenue\", 41200, 44100, 49400])\nsheet.write_formula(\"D1\", '=\"Revenue up \"&TEXT(B4\u002FB3-1,\"0%\")&\" on last month\"', None, \"Revenue up 12% on last month\")\nsheet.insert_textbox(\"D3\", \"\", {\"textlink\": \"=Report!$D$1\", \"width\": 260, \"height\": 40, \"fill\": {\"color\": \"#FEF3C7\"}})\nbook.close()\nprint(\"box linked to Report!$D$1\")\n",[14,898,899,912,924,948,972,1003,1059,1063],{"__ignoreMap":35},[39,900,901,903,905,907,910],{"class":41,"line":42},[39,902,106],{"class":92},[39,904,109],{"class":88},[39,906,112],{"class":92},[39,908,909],{"class":49},"\"textbox_linked.xlsx\"",[39,911,118],{"class":92},[39,913,914,916,918,920,922],{"class":41,"line":96},[39,915,124],{"class":92},[39,917,109],{"class":88},[39,919,129],{"class":92},[39,921,132],{"class":49},[39,923,118],{"class":92},[39,925,926,928,930,932,934,936,938,940,942,944,946],{"class":41,"line":103},[39,927,140],{"class":92},[39,929,143],{"class":49},[39,931,146],{"class":92},[39,933,149],{"class":49},[39,935,152],{"class":92},[39,937,155],{"class":49},[39,939,152],{"class":92},[39,941,160],{"class":49},[39,943,152],{"class":92},[39,945,165],{"class":49},[39,947,168],{"class":92},[39,949,950,952,954,956,958,960,962,964,966,968,970],{"class":41,"line":121},[39,951,140],{"class":92},[39,953,176],{"class":49},[39,955,146],{"class":92},[39,957,181],{"class":49},[39,959,152],{"class":92},[39,961,187],{"class":186},[39,963,152],{"class":92},[39,965,192],{"class":186},[39,967,152],{"class":92},[39,969,197],{"class":186},[39,971,168],{"class":92},[39,973,974,977,980,982,985,987,990,992,995,998,1001],{"class":41,"line":137},[39,975,976],{"class":92},"sheet.write_formula(",[39,978,979],{"class":49},"\"D1\"",[39,981,152],{"class":92},[39,983,984],{"class":49},"'=\"Revenue up \"&TEXT(B4\u002FB3-1,\"0%\")&\" on last month\"'",[39,986,152],{"class":92},[39,988,989],{"class":186},"None",[39,991,152],{"class":92},[39,993,994],{"class":49},"\"Revenue up 12",[39,996,997],{"class":633},"% o",[39,999,1000],{"class":49},"n last month\"",[39,1002,118],{"class":92},[39,1004,1005,1007,1010,1012,1015,1018,1021,1023,1026,1028,1030,1032,1034,1036,1038,1040,1042,1044,1047,1049,1051,1053,1056],{"class":41,"line":171},[39,1006,205],{"class":92},[39,1008,1009],{"class":49},"\"D3\"",[39,1011,152],{"class":92},[39,1013,1014],{"class":49},"\"\"",[39,1016,1017],{"class":92},", {",[39,1019,1020],{"class":49},"\"textlink\"",[39,1022,225],{"class":92},[39,1024,1025],{"class":49},"\"=Report!$D$1\"",[39,1027,152],{"class":92},[39,1029,317],{"class":49},[39,1031,225],{"class":92},[39,1033,228],{"class":186},[39,1035,152],{"class":92},[39,1037,233],{"class":49},[39,1039,225],{"class":92},[39,1041,721],{"class":186},[39,1043,152],{"class":92},[39,1045,1046],{"class":49},"\"fill\"",[39,1048,250],{"class":92},[39,1050,263],{"class":49},[39,1052,225],{"class":92},[39,1054,1055],{"class":49},"\"#FEF3C7\"",[39,1057,1058],{"class":92},"}})\n",[39,1060,1061],{"class":41,"line":202},[39,1062,364],{"class":92},[39,1064,1065,1067,1069,1072],{"class":41,"line":219},[39,1066,370],{"class":186},[39,1068,373],{"class":92},[39,1070,1071],{"class":49},"\"box linked to Report!$D$1\"",[39,1073,118],{"class":92},[10,1075,1076,1077,1081],{},"Excel resolves the link when it opens the file and shows \"Revenue up 12% on last month\" in the box. But XlsxWriter stores the link with an empty cached text, and LibreOffice (tested with version 26.2) shows the box ",[1078,1079,1080],"em",{},"empty"," — it does not resolve the link. If your readers use LibreOffice, or the workbook is converted to PDF on a server, write the text into the box yourself. A report generator usually knows the numbers anyway, so composing the sentence in Python is no extra work:",[30,1083,1085],{"className":79,"code":1084,"language":81,"meta":35,"style":35},"growth = 49400 \u002F 44100 - 1\nbook = xlsxwriter.Workbook(\"textbox_computed.xlsx\")\nsheet = book.add_worksheet(\"Report\")\nsheet.insert_textbox(\"D3\", f\"Revenue up {growth:.0%} on last month\", {\"width\": 260, \"height\": 40, \"fill\": {\"color\": \"#FEF3C7\"}})\nbook.close()\nprint(f\"Revenue up {growth:.0%} on last month\")\n",[14,1086,1087,1109,1122,1134,1193,1197],{"__ignoreMap":35},[39,1088,1089,1092,1094,1097,1100,1103,1106],{"class":41,"line":42},[39,1090,1091],{"class":92},"growth ",[39,1093,109],{"class":88},[39,1095,1096],{"class":186}," 49400",[39,1098,1099],{"class":88}," \u002F",[39,1101,1102],{"class":186}," 44100",[39,1104,1105],{"class":88}," -",[39,1107,1108],{"class":186}," 1\n",[39,1110,1111,1113,1115,1117,1120],{"class":41,"line":96},[39,1112,106],{"class":92},[39,1114,109],{"class":88},[39,1116,112],{"class":92},[39,1118,1119],{"class":49},"\"textbox_computed.xlsx\"",[39,1121,118],{"class":92},[39,1123,1124,1126,1128,1130,1132],{"class":41,"line":103},[39,1125,124],{"class":92},[39,1127,109],{"class":88},[39,1129,129],{"class":92},[39,1131,132],{"class":49},[39,1133,118],{"class":92},[39,1135,1136,1138,1140,1142,1145,1148,1151,1154,1157,1160,1163,1165,1167,1169,1171,1173,1175,1177,1179,1181,1183,1185,1187,1189,1191],{"class":41,"line":121},[39,1137,205],{"class":92},[39,1139,1009],{"class":49},[39,1141,152],{"class":92},[39,1143,1144],{"class":88},"f",[39,1146,1147],{"class":49},"\"Revenue up ",[39,1149,1150],{"class":633},"{",[39,1152,1153],{"class":92},"growth",[39,1155,1156],{"class":88},":.0%",[39,1158,1159],{"class":633},"}",[39,1161,1162],{"class":49}," on last month\"",[39,1164,1017],{"class":92},[39,1166,317],{"class":49},[39,1168,225],{"class":92},[39,1170,228],{"class":186},[39,1172,152],{"class":92},[39,1174,233],{"class":49},[39,1176,225],{"class":92},[39,1178,721],{"class":186},[39,1180,152],{"class":92},[39,1182,1046],{"class":49},[39,1184,250],{"class":92},[39,1186,263],{"class":49},[39,1188,225],{"class":92},[39,1190,1055],{"class":49},[39,1192,1058],{"class":92},[39,1194,1195],{"class":41,"line":137},[39,1196,364],{"class":92},[39,1198,1199,1201,1203,1205,1207,1209,1211,1213,1215,1217],{"class":41,"line":171},[39,1200,370],{"class":186},[39,1202,373],{"class":92},[39,1204,1144],{"class":88},[39,1206,1147],{"class":49},[39,1208,1150],{"class":633},[39,1210,1153],{"class":92},[39,1212,1156],{"class":88},[39,1214,1159],{"class":633},[39,1216,1162],{"class":49},[39,1218,118],{"class":92},[10,1220,1221,1222,1224],{},"Use ",[14,1223,892],{}," when people will edit the workbook in Excel and expect the commentary to follow their changes; use computed text when the file is a finished report.",[424,1226,433,1231,433,1234,433,1237,433,1240,433,1244,433,1250,433,1254,433,1258,433,1262,433,1265,433,1268,433,1277,433,1282,433,1287,433,1292,433,1296,433,1300,433,1302,433,1305,433,1309,433,1312,433,1315,433,1321,433,1324],{"viewBox":1227,"role":427,"ariaLabelledBy":1228,"xmlns":431,"style":432},"4 0 752 272",[1229,1230],"tb-link-t","tb-link-d",[435,1232,1233],{"id":1229},"Fixed text or a cell link?",[439,1235,1236],{"id":1230},"If the workbook is a finished report or may be opened in LibreOffice, compose the text in Python and pass it to the box. If people will edit the source cells in Excel and the commentary should follow, use textlink, accepting that LibreOffice shows the box empty.",[443,1238],{"x":445,"y":446,"width":447,"height":1239,"fill":449},"272",[443,1241],{"x":1242,"y":453,"width":1243,"height":474,"rx":278,"fill":456,"stroke":457,"style":458},"230.4","299.3",[460,1245,1247],{"transform":1246},"translate(368.0,29.0) scale(1.000)",[464,1248],{"d":1249,"fill":467,"stroke":468,"style":469},"M11 4a7 7 0 1 0 .01 0z M16 16l5 5",[471,1251,1253],{"x":1252,"y":474,"style":475},"380.0","Will readers edit the cells in Excel?",[41,1255],{"x1":1252,"y1":1256,"x2":1252,"y2":1257,"stroke":457,"style":458},"91.5","111.5",[41,1259],{"x1":1260,"y1":1257,"x2":1261,"y2":1257,"stroke":457,"style":458},"196.0","564.0",[41,1263],{"x1":1260,"y1":1257,"x2":1260,"y2":1264,"stroke":457,"style":458},"157.5",[492,1266],{"points":1267,"fill":495},"196.0,161.5 191.0,152.5 201.0,152.5",[443,1269],{"x":1270,"y":1271,"width":1272,"height":1273,"rx":1274,"fill":449,"stroke":1275,"style":1276},"131.5","121.5","129.0","21.0","10","var(--line,#cdd5e6)","stroke-width:1.2px",[471,1278,1281],{"x":1260,"y":1279,"style":1280},"136.0","font-size:11.5px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","yes, live workbook",[443,1283],{"x":452,"y":1284,"width":1285,"height":1286,"rx":278,"fill":528,"stroke":529,"style":458},"163.5","352.0","93.0",[460,1288,1290],{"transform":1289},"translate(184.0,176.5) scale(1.000)",[464,1291],{"d":562,"fill":467,"stroke":536,"style":469},[471,1293,1295],{"x":1260,"y":1294,"style":540},"223.0","textlink to the cell",[471,1297,1299],{"x":1260,"y":1298,"style":480},"242.5","Excel resolves it on open",[41,1301],{"x1":1261,"y1":1257,"x2":1261,"y2":1264,"stroke":457,"style":458},[492,1303],{"points":1304,"fill":495},"564.0,161.5 559.0,152.5 569.0,152.5",[443,1306],{"x":1307,"y":1271,"width":1308,"height":1273,"rx":1274,"fill":449,"stroke":1275,"style":1276},"500.5","127.1",[471,1310,1311],{"x":1261,"y":1279,"style":1280},"no, finished report",[443,1313],{"x":1314,"y":1284,"width":1285,"height":1286,"rx":278,"fill":499,"stroke":500,"style":458},"388.0",[460,1316,1318],{"transform":1317},"translate(552.0,176.5) scale(1.000)",[464,1319],{"d":1320,"fill":467,"stroke":507,"style":469},"M12 3c-4 0-4 1.6-4 3v2h4.2v1H6c-2 0-3 1.4-3 4s1 4 3 4h2v-2.6c0-1.6 1.3-2.9 2.9-2.9h4.2c1.3 0 2.4-1.1 2.4-2.4V6c0-1.6-1.8-3-5.5-3z M10 5.5h.01 M12 21c4 0 4-1.6 4-3v-2h-4.2v-1H18c2 0 3-1.4 3-4s-1-4-3-4h-2v2.6c0 1.6-1.3 2.9-2.9 2.9H8.9c-1.3 0-2.4 1.1-2.4 2.4V18c0 1.6 1.8 3 5.5 3z M14 18.5h.01",[471,1322,1323],{"x":1261,"y":1294,"style":512},"text composed in Python",[471,1325,1326],{"x":1261,"y":1298,"style":480},"shows in every application",[25,1328,1330],{"id":1329},"step-4-place-a-box-below-a-table-of-any-length","Step 4 — Place a box below a table of any length",[10,1332,1333],{},"Anchoring a note at a fixed cell breaks when next month's table has more rows. Compute the anchor from the data instead — two rows below the last one written:",[30,1335,1337],{"className":79,"code":1336,"language":81,"meta":35,"style":35},"import pandas as pd\n\nsales = pd.DataFrame({\"Region\": [\"North\", \"South\", \"East\", \"West\", \"Central\"],\n                      \"Revenue\": [18400, 12100, 9800, 15300, 7200]})\n\nwith pd.ExcelWriter(\"textbox_after_table.xlsx\", engine=\"xlsxwriter\") as writer:\n    sales.to_excel(writer, sheet_name=\"Report\", index=False)\n    sheet = writer.sheets[\"Report\"]\n    note_row = len(sales) + 2                       # header + data + one blank row\n    top = sales.loc[sales[\"Revenue\"].idxmax(), \"Region\"]\n    sheet.insert_textbox(note_row, 0, f\"{top} led with {sales['Revenue'].max():,} in revenue.\", {\n        \"width\": 300, \"height\": 36, \"line\": {\"none\": True}, \"fill\": {\"color\": \"#F1F5F9\"},\n    })\nprint(\"note anchored at row\", note_row + 1)\n",[14,1338,1339,1352,1356,1397,1430,1434,1464,1488,1503,1526,1545,1589,1637,1642],{"__ignoreMap":35},[39,1340,1341,1343,1346,1349],{"class":41,"line":42},[39,1342,89],{"class":88},[39,1344,1345],{"class":92}," pandas ",[39,1347,1348],{"class":88},"as",[39,1350,1351],{"class":92}," pd\n",[39,1353,1354],{"class":41,"line":96},[39,1355,100],{"emptyLinePlaceholder":99},[39,1357,1358,1361,1363,1366,1369,1371,1374,1376,1379,1381,1384,1386,1389,1391,1394],{"class":41,"line":103},[39,1359,1360],{"class":92},"sales ",[39,1362,109],{"class":88},[39,1364,1365],{"class":92}," pd.DataFrame({",[39,1367,1368],{"class":49},"\"Region\"",[39,1370,825],{"class":92},[39,1372,1373],{"class":49},"\"North\"",[39,1375,152],{"class":92},[39,1377,1378],{"class":49},"\"South\"",[39,1380,152],{"class":92},[39,1382,1383],{"class":49},"\"East\"",[39,1385,152],{"class":92},[39,1387,1388],{"class":49},"\"West\"",[39,1390,152],{"class":92},[39,1392,1393],{"class":49},"\"Central\"",[39,1395,1396],{"class":92},"],\n",[39,1398,1399,1402,1404,1407,1409,1412,1414,1417,1419,1422,1424,1427],{"class":41,"line":121},[39,1400,1401],{"class":49},"                      \"Revenue\"",[39,1403,825],{"class":92},[39,1405,1406],{"class":186},"18400",[39,1408,152],{"class":92},[39,1410,1411],{"class":186},"12100",[39,1413,152],{"class":92},[39,1415,1416],{"class":186},"9800",[39,1418,152],{"class":92},[39,1420,1421],{"class":186},"15300",[39,1423,152],{"class":92},[39,1425,1426],{"class":186},"7200",[39,1428,1429],{"class":92},"]})\n",[39,1431,1432],{"class":41,"line":137},[39,1433,100],{"emptyLinePlaceholder":99},[39,1435,1436,1439,1442,1445,1447,1451,1453,1456,1459,1461],{"class":41,"line":171},[39,1437,1438],{"class":88},"with",[39,1440,1441],{"class":92}," pd.ExcelWriter(",[39,1443,1444],{"class":49},"\"textbox_after_table.xlsx\"",[39,1446,152],{"class":92},[39,1448,1450],{"class":1449},"sa561","engine",[39,1452,109],{"class":88},[39,1454,1455],{"class":49},"\"xlsxwriter\"",[39,1457,1458],{"class":92},") ",[39,1460,1348],{"class":88},[39,1462,1463],{"class":92}," writer:\n",[39,1465,1466,1469,1472,1474,1476,1478,1481,1483,1486],{"class":41,"line":202},[39,1467,1468],{"class":92},"    sales.to_excel(writer, ",[39,1470,1471],{"class":1449},"sheet_name",[39,1473,109],{"class":88},[39,1475,132],{"class":49},[39,1477,152],{"class":92},[39,1479,1480],{"class":1449},"index",[39,1482,109],{"class":88},[39,1484,1485],{"class":186},"False",[39,1487,118],{"class":92},[39,1489,1490,1493,1495,1498,1500],{"class":41,"line":219},[39,1491,1492],{"class":92},"    sheet ",[39,1494,109],{"class":88},[39,1496,1497],{"class":92}," writer.sheets[",[39,1499,132],{"class":49},[39,1501,1502],{"class":92},"]\n",[39,1504,1505,1508,1510,1513,1516,1519,1522],{"class":41,"line":244},[39,1506,1507],{"class":92},"    note_row ",[39,1509,109],{"class":88},[39,1511,1512],{"class":186}," len",[39,1514,1515],{"class":92},"(sales) ",[39,1517,1518],{"class":88},"+",[39,1520,1521],{"class":186}," 2",[39,1523,1525],{"class":1524},"s-wDw","                       # header + data + one blank row\n",[39,1527,1528,1531,1533,1536,1538,1541,1543],{"class":41,"line":284},[39,1529,1530],{"class":92},"    top ",[39,1532,109],{"class":88},[39,1534,1535],{"class":92}," sales.loc[sales[",[39,1537,181],{"class":49},[39,1539,1540],{"class":92},"].idxmax(), ",[39,1542,1368],{"class":49},[39,1544,1502],{"class":92},[39,1546,1547,1550,1552,1554,1556,1559,1561,1563,1565,1568,1570,1573,1576,1579,1582,1584,1587],{"class":41,"line":301},[39,1548,1549],{"class":92},"    sheet.insert_textbox(note_row, ",[39,1551,446],{"class":186},[39,1553,152],{"class":92},[39,1555,1144],{"class":88},[39,1557,1558],{"class":49},"\"",[39,1560,1150],{"class":633},[39,1562,405],{"class":92},[39,1564,1159],{"class":633},[39,1566,1567],{"class":49}," led with ",[39,1569,1150],{"class":633},[39,1571,1572],{"class":92},"sales[",[39,1574,1575],{"class":49},"'Revenue'",[39,1577,1578],{"class":92},"].max()",[39,1580,1581],{"class":88},":,",[39,1583,1159],{"class":633},[39,1585,1586],{"class":49}," in revenue.\"",[39,1588,216],{"class":92},[39,1590,1591,1594,1596,1599,1601,1603,1605,1608,1610,1613,1615,1617,1619,1621,1624,1626,1628,1630,1632,1635],{"class":41,"line":327},[39,1592,1593],{"class":49},"        \"width\"",[39,1595,225],{"class":92},[39,1597,1598],{"class":186},"300",[39,1600,152],{"class":92},[39,1602,233],{"class":49},[39,1604,225],{"class":92},[39,1606,1607],{"class":186},"36",[39,1609,152],{"class":92},[39,1611,1612],{"class":49},"\"line\"",[39,1614,250],{"class":92},[39,1616,673],{"class":49},[39,1618,225],{"class":92},[39,1620,258],{"class":186},[39,1622,1623],{"class":92},"}, ",[39,1625,1046],{"class":49},[39,1627,250],{"class":92},[39,1629,263],{"class":49},[39,1631,225],{"class":92},[39,1633,1634],{"class":49},"\"#F1F5F9\"",[39,1636,281],{"class":92},[39,1638,1639],{"class":41,"line":355},[39,1640,1641],{"class":92},"    })\n",[39,1643,1644,1646,1648,1651,1654,1656,1659],{"class":41,"line":361},[39,1645,370],{"class":186},[39,1647,373],{"class":92},[39,1649,1650],{"class":49},"\"note anchored at row\"",[39,1652,1653],{"class":92},", note_row ",[39,1655,1518],{"class":88},[39,1657,1658],{"class":186}," 1",[39,1660,118],{"class":92},[10,1662,1663,1666,1667,1670,1671,384,1674,1677,1678,23],{},[14,1664,1665],{},"insert_textbox"," accepts a zero-based ",[14,1668,1669],{},"(row, col)"," pair as well as an A1 string, which makes computed positions straightforward. With five data rows plus a header, the note lands at row 8, one blank row below the table; with fifty rows it moves down with them. ",[14,1672,1673],{},"x_offset",[14,1675,1676],{},"y_offset"," nudge the box within its anchor cell in pixels. Choosing between the writer engines is covered in ",[19,1679,1681],{"href":1680},"\u002Fgetting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas\u002Fopenpyxl-vs-xlsxwriter-vs-pandas-excelwriter\u002F","openpyxl vs XlsxWriter vs pandas ExcelWriter",[25,1683,1685],{"id":1684},"step-5-links-positioning-and-accessibility","Step 5 — Links, positioning and accessibility",[10,1687,1688],{},"A few more options control how the box behaves:",[30,1690,1692],{"className":79,"code":1691,"language":81,"meta":35,"style":35},"book = xlsxwriter.Workbook(\"textbox_behaviour.xlsx\")\nsheet = book.add_worksheet(\"Report\")\nsheet.insert_textbox(\"B2\", \"Read the methodology\", {\n    \"url\": \"https:\u002F\u002Fexample.com\u002Fmethod\",\n    \"tip\": \"Opens the methodology page\",\n    \"object_position\": 1,\n    \"description\": \"Link to the report methodology\",\n    \"width\": 200, \"height\": 30,\n})\nbook.close()\nprint(\"linked box written\")\n",[14,1693,1694,1707,1719,1732,1744,1756,1768,1780,1800,1804,1808],{"__ignoreMap":35},[39,1695,1696,1698,1700,1702,1705],{"class":41,"line":42},[39,1697,106],{"class":92},[39,1699,109],{"class":88},[39,1701,112],{"class":92},[39,1703,1704],{"class":49},"\"textbox_behaviour.xlsx\"",[39,1706,118],{"class":92},[39,1708,1709,1711,1713,1715,1717],{"class":41,"line":96},[39,1710,124],{"class":92},[39,1712,109],{"class":88},[39,1714,129],{"class":92},[39,1716,132],{"class":49},[39,1718,118],{"class":92},[39,1720,1721,1723,1725,1727,1730],{"class":41,"line":103},[39,1722,205],{"class":92},[39,1724,625],{"class":49},[39,1726,152],{"class":92},[39,1728,1729],{"class":49},"\"Read the methodology\"",[39,1731,216],{"class":92},[39,1733,1734,1737,1739,1742],{"class":41,"line":121},[39,1735,1736],{"class":49},"    \"url\"",[39,1738,225],{"class":92},[39,1740,1741],{"class":49},"\"https:\u002F\u002Fexample.com\u002Fmethod\"",[39,1743,241],{"class":92},[39,1745,1746,1749,1751,1754],{"class":41,"line":137},[39,1747,1748],{"class":49},"    \"tip\"",[39,1750,225],{"class":92},[39,1752,1753],{"class":49},"\"Opens the methodology page\"",[39,1755,241],{"class":92},[39,1757,1758,1761,1763,1766],{"class":41,"line":171},[39,1759,1760],{"class":49},"    \"object_position\"",[39,1762,225],{"class":92},[39,1764,1765],{"class":186},"1",[39,1767,241],{"class":92},[39,1769,1770,1773,1775,1778],{"class":41,"line":202},[39,1771,1772],{"class":49},"    \"description\"",[39,1774,225],{"class":92},[39,1776,1777],{"class":49},"\"Link to the report methodology\"",[39,1779,241],{"class":92},[39,1781,1782,1784,1786,1789,1791,1793,1795,1798],{"class":41,"line":219},[39,1783,222],{"class":49},[39,1785,225],{"class":92},[39,1787,1788],{"class":186},"200",[39,1790,152],{"class":92},[39,1792,233],{"class":49},[39,1794,225],{"class":92},[39,1796,1797],{"class":186},"30",[39,1799,241],{"class":92},[39,1801,1802],{"class":41,"line":244},[39,1803,358],{"class":92},[39,1805,1806],{"class":41,"line":284},[39,1807,364],{"class":92},[39,1809,1810,1812,1814,1817],{"class":41,"line":301},[39,1811,370],{"class":186},[39,1813,373],{"class":92},[39,1815,1816],{"class":49},"\"linked box written\"",[39,1818,118],{"class":92},[10,1820,1821,1824,1825,1828,1829,1832,1833,1836,1837,23],{},[14,1822,1823],{},"url"," makes the whole box clickable (and ",[14,1826,1827],{},"tip"," sets the hover text). ",[14,1830,1831],{},"object_position"," decides what happens when rows and columns around the box are resized: 1 (the default) moves and sizes it with the cells, 2 moves it without resizing, 3 leaves it fixed in place, and 4 behaves like 1 but also lets XlsxWriter account for rows and columns hidden after the box is inserted. ",[14,1834,1835],{},"description"," is the alternative text screen readers announce — part of making a report usable for everyone, as in ",[19,1838,1840],{"href":1839},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fprotecting-and-sharing-excel-workbooks\u002Fmake-an-excel-report-accessible\u002F","Make an Excel Report Accessible",[25,1842,1844],{"id":1843},"what-about-other-shapes","What about other shapes?",[10,1846,1847,1848,1852,1853,23],{},"XlsxWriter's text boxes are rectangles; it has no API for arrows, ovals or callouts. For a highlighted callout next to a figure, a text box with a coloured fill and no border usually does the job. For a pointer to a specific value, conditional formatting or a bold, coloured cell is more robust, because it stays attached to the value when rows are sorted. openpyxl does not add shapes either, and it drops existing shapes and text boxes when it saves a workbook — see ",[19,1849,1851],{"href":1850},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fwhat-openpyxl-loses-when-saving-an-existing-workbook\u002F","What openpyxl Loses When Saving an Existing Workbook",". For an image-based overlay such as a logo or a \"Confidential\" mark, use a picture instead: ",[19,1854,1856],{"href":1855},"\u002Fformatting-and-charting-excel-reports-with-python\u002Finserting-images-and-logos-into-excel\u002Fadd-a-watermark-to-an-excel-sheet\u002F","Add a Watermark to an Excel Sheet",[25,1858,1860],{"id":1859},"step-6-check-the-text-in-the-rendered-output","Step 6 — Check the text in the rendered output",[10,1862,1863],{},"Floating objects are easy to get wrong without seeing them. Render the workbook and check that each box's text is present:",[30,1865,1867],{"className":79,"code":1866,"language":81,"meta":35,"style":35},"import subprocess\nfrom pypdf import PdfReader\n\ndef page_text(xlsx):\n    subprocess.run([\"soffice\", \"--headless\", \"--convert-to\", \"pdf\", xlsx], check=True, capture_output=True)\n    return PdfReader(xlsx.replace(\".xlsx\", \".pdf\")).pages[0].extract_text()\n\nsentence = \"Revenue up 12% on last month\"\nfor f in (\"textbox_linked.xlsx\", \"textbox_computed.xlsx\", \"textbox_after_table.xlsx\"):\n    text = page_text(f)\n    print(f\"{f:26} sentence x{text.count(sentence)}  note: {'North led' in text}\")\n",[14,1868,1869,1876,1889,1893,1905,1949,1973,1977,1992,2019,2029],{"__ignoreMap":35},[39,1870,1871,1873],{"class":41,"line":42},[39,1872,89],{"class":88},[39,1874,1875],{"class":92}," subprocess\n",[39,1877,1878,1881,1884,1886],{"class":41,"line":96},[39,1879,1880],{"class":88},"from",[39,1882,1883],{"class":92}," pypdf ",[39,1885,89],{"class":88},[39,1887,1888],{"class":92}," PdfReader\n",[39,1890,1891],{"class":41,"line":103},[39,1892,100],{"emptyLinePlaceholder":99},[39,1894,1895,1898,1902],{"class":41,"line":121},[39,1896,1897],{"class":88},"def",[39,1899,1901],{"class":1900},"s_Opv"," page_text",[39,1903,1904],{"class":92},"(xlsx):\n",[39,1906,1907,1910,1913,1915,1918,1920,1923,1925,1928,1931,1934,1936,1938,1940,1943,1945,1947],{"class":41,"line":137},[39,1908,1909],{"class":92},"    subprocess.run([",[39,1911,1912],{"class":49},"\"soffice\"",[39,1914,152],{"class":92},[39,1916,1917],{"class":49},"\"--headless\"",[39,1919,152],{"class":92},[39,1921,1922],{"class":49},"\"--convert-to\"",[39,1924,152],{"class":92},[39,1926,1927],{"class":49},"\"pdf\"",[39,1929,1930],{"class":92},", xlsx], ",[39,1932,1933],{"class":1449},"check",[39,1935,109],{"class":88},[39,1937,258],{"class":186},[39,1939,152],{"class":92},[39,1941,1942],{"class":1449},"capture_output",[39,1944,109],{"class":88},[39,1946,258],{"class":186},[39,1948,118],{"class":92},[39,1950,1951,1954,1957,1960,1962,1965,1968,1970],{"class":41,"line":171},[39,1952,1953],{"class":88},"    return",[39,1955,1956],{"class":92}," PdfReader(xlsx.replace(",[39,1958,1959],{"class":49},"\".xlsx\"",[39,1961,152],{"class":92},[39,1963,1964],{"class":49},"\".pdf\"",[39,1966,1967],{"class":92},")).pages[",[39,1969,446],{"class":186},[39,1971,1972],{"class":92},"].extract_text()\n",[39,1974,1975],{"class":41,"line":202},[39,1976,100],{"emptyLinePlaceholder":99},[39,1978,1979,1982,1984,1987,1989],{"class":41,"line":219},[39,1980,1981],{"class":92},"sentence ",[39,1983,109],{"class":88},[39,1985,1986],{"class":49}," \"Revenue up 12",[39,1988,997],{"class":633},[39,1990,1991],{"class":49},"n last month\"\n",[39,1993,1994,1997,2000,2003,2006,2008,2010,2012,2014,2016],{"class":41,"line":244},[39,1995,1996],{"class":88},"for",[39,1998,1999],{"class":92}," f ",[39,2001,2002],{"class":88},"in",[39,2004,2005],{"class":92}," (",[39,2007,909],{"class":49},[39,2009,152],{"class":92},[39,2011,1119],{"class":49},[39,2013,152],{"class":92},[39,2015,1444],{"class":49},[39,2017,2018],{"class":92},"):\n",[39,2020,2021,2024,2026],{"class":41,"line":284},[39,2022,2023],{"class":92},"    text ",[39,2025,109],{"class":88},[39,2027,2028],{"class":92}," page_text(f)\n",[39,2030,2031,2034,2036,2038,2040,2042,2044,2047,2049,2052,2054,2057,2059,2062,2064,2067,2070,2073,2075,2077],{"class":41,"line":301},[39,2032,2033],{"class":186},"    print",[39,2035,373],{"class":92},[39,2037,1144],{"class":88},[39,2039,1558],{"class":49},[39,2041,1150],{"class":633},[39,2043,1144],{"class":92},[39,2045,2046],{"class":88},":26",[39,2048,1159],{"class":633},[39,2050,2051],{"class":49}," sentence x",[39,2053,1150],{"class":633},[39,2055,2056],{"class":92},"text.count(sentence)",[39,2058,1159],{"class":633},[39,2060,2061],{"class":49},"  note: ",[39,2063,1150],{"class":633},[39,2065,2066],{"class":49},"'North led'",[39,2068,2069],{"class":88}," in",[39,2071,2072],{"class":92}," text",[39,2074,1159],{"class":633},[39,2076,1558],{"class":49},[39,2078,118],{"class":92},[10,2080,2081],{},"In the linked file, the sentence appears only once — from cell D1 — and the box itself is empty in LibreOffice. In the computed file the sentence comes from the box, and in the table file the \"North led with 18,400 in revenue.\" note appears below the five regions. The same check in a test catches a box whose text went missing.",[424,2083,433,2089,433,2092,433,2095,433,2100,433,2107,433,2111,433,2117,433,2121,433,2125,433,2129,433,2133,433,2137,433,2141,433,2144,433,2148,433,2150,433,2153,433,2155,433,2158,433,2162,433,2164,433,2168,433,2170,433,2173,433,2175,433,2178,433,2182,433,2184,433,2187,433,2189,433,2192,433,2194,433,2197,433,2200,433,2202,433,2205,433,2207,433,2210,433,2212,433,2215,433,2219,433,2221,433,2224,433,2226,433,2229,433,2231,433,2234,433,2238,433,2240,433,2243,433,2245,433,2248,433,2250,433,2253,433,2257,433,2259,433,2261,433,2263,433,2266,433,2270,433,2272,433,2276,433,2278],{"viewBox":2084,"role":427,"ariaLabelledBy":2085,"xmlns":431,"style":2088},"195 0 370 280",[2086,2087],"tb-layout-t","tb-layout-d","width:100%;max-width:370px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[435,2090,2091],{"id":2086},"A note placed two rows below the table",[439,2093,2094],{"id":2087},"A sheet with a header row and five region rows. Row 7 is blank. From row 8 a shaded text box spans columns A to C with the sentence North led with 18,400 in revenue.",[443,2096],{"x":2097,"y":446,"width":2098,"height":2099,"fill":449},"195","370","280",[443,2101],{"x":2102,"y":453,"width":2103,"height":2104,"rx":446,"fill":2105,"stroke":1275,"style":2106},"211.3","32.0","24.0","#e7ebef","stroke-width:1px",[443,2108],{"x":2109,"y":453,"width":2110,"height":2104,"rx":446,"fill":2105,"stroke":1275,"style":2106},"243.3","190.1",[471,2112,2116],{"x":2113,"y":2114,"style":2115},"338.3","33.0","font-size:11px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","A",[443,2118],{"x":2119,"y":453,"width":2120,"height":2104,"rx":446,"fill":2105,"stroke":1275,"style":2106},"433.4","71.3",[471,2122,2124],{"x":2123,"y":2114,"style":2115},"469.1","B",[443,2126],{"x":2127,"y":453,"width":2128,"height":2104,"rx":446,"fill":2105,"stroke":1275,"style":2106},"504.7","44.0",[471,2130,2132],{"x":2131,"y":2114,"style":2115},"526.7","C",[443,2134],{"x":2102,"y":2135,"width":2103,"height":2136,"rx":446,"fill":2105,"stroke":1275,"style":2106},"40.0","28.0",[471,2138,1765],{"x":2139,"y":2140,"style":2115},"227.3","59.0",[443,2142],{"x":2109,"y":2135,"width":2110,"height":2136,"rx":446,"fill":456,"stroke":457,"style":2143},"stroke-width:1.5px",[471,2145,2147],{"x":2113,"y":2140,"style":2146},"font-size:10.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Region",[443,2149],{"x":2119,"y":2135,"width":2120,"height":2136,"rx":446,"fill":456,"stroke":457,"style":2143},[471,2151,2152],{"x":2123,"y":2140,"style":2146},"Revenue",[443,2154],{"x":2127,"y":2135,"width":2128,"height":2136,"rx":446,"fill":456,"stroke":457,"style":2143},[443,2156],{"x":2102,"y":2157,"width":2103,"height":2136,"rx":446,"fill":2105,"stroke":1275,"style":2106},"68.0",[471,2159,2161],{"x":2139,"y":2160,"style":2115},"87.0","2",[443,2163],{"x":2109,"y":2157,"width":2110,"height":2136,"rx":446,"fill":449,"stroke":1275,"style":2106},[471,2165,2167],{"x":2113,"y":2160,"style":2166},"font-size:10.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","North",[443,2169],{"x":2119,"y":2157,"width":2120,"height":2136,"rx":446,"fill":449,"stroke":1275,"style":2106},[471,2171,2172],{"x":2123,"y":2160,"style":2166},"18,400",[443,2174],{"x":2127,"y":2157,"width":2128,"height":2136,"rx":446,"fill":449,"stroke":1275,"style":2106},[443,2176],{"x":2102,"y":2177,"width":2103,"height":2136,"rx":446,"fill":2105,"stroke":1275,"style":2106},"96.0",[471,2179,2181],{"x":2139,"y":2180,"style":2115},"115.0","3",[443,2183],{"x":2109,"y":2177,"width":2110,"height":2136,"rx":446,"fill":449,"stroke":1275,"style":2106},[471,2185,2186],{"x":2113,"y":2180,"style":2166},"South",[443,2188],{"x":2119,"y":2177,"width":2120,"height":2136,"rx":446,"fill":449,"stroke":1275,"style":2106},[471,2190,2191],{"x":2123,"y":2180,"style":2166},"12,100",[443,2193],{"x":2127,"y":2177,"width":2128,"height":2136,"rx":446,"fill":449,"stroke":1275,"style":2106},[443,2195],{"x":2102,"y":2196,"width":2103,"height":2136,"rx":446,"fill":2105,"stroke":1275,"style":2106},"124.0",[471,2198,445],{"x":2139,"y":2199,"style":2115},"143.0",[443,2201],{"x":2109,"y":2196,"width":2110,"height":2136,"rx":446,"fill":449,"stroke":1275,"style":2106},[471,2203,2204],{"x":2113,"y":2199,"style":2166},"East",[443,2206],{"x":2119,"y":2196,"width":2120,"height":2136,"rx":446,"fill":449,"stroke":1275,"style":2106},[471,2208,2209],{"x":2123,"y":2199,"style":2166},"9,800",[443,2211],{"x":2127,"y":2196,"width":2128,"height":2136,"rx":446,"fill":449,"stroke":1275,"style":2106},[443,2213],{"x":2102,"y":2214,"width":2103,"height":2136,"rx":446,"fill":2105,"stroke":1275,"style":2106},"152.0",[471,2216,2218],{"x":2139,"y":2217,"style":2115},"171.0","5",[443,2220],{"x":2109,"y":2214,"width":2110,"height":2136,"rx":446,"fill":449,"stroke":1275,"style":2106},[471,2222,2223],{"x":2113,"y":2217,"style":2166},"West",[443,2225],{"x":2119,"y":2214,"width":2120,"height":2136,"rx":446,"fill":449,"stroke":1275,"style":2106},[471,2227,2228],{"x":2123,"y":2217,"style":2166},"15,300",[443,2230],{"x":2127,"y":2214,"width":2128,"height":2136,"rx":446,"fill":449,"stroke":1275,"style":2106},[443,2232],{"x":2102,"y":2233,"width":2103,"height":2136,"rx":446,"fill":2105,"stroke":1275,"style":2106},"180.0",[471,2235,2237],{"x":2139,"y":2236,"style":2115},"199.0","6",[443,2239],{"x":2109,"y":2233,"width":2110,"height":2136,"rx":446,"fill":449,"stroke":1275,"style":2106},[471,2241,2242],{"x":2113,"y":2236,"style":2166},"Central",[443,2244],{"x":2119,"y":2233,"width":2120,"height":2136,"rx":446,"fill":449,"stroke":1275,"style":2106},[471,2246,2247],{"x":2123,"y":2236,"style":2166},"7,200",[443,2249],{"x":2127,"y":2233,"width":2128,"height":2136,"rx":446,"fill":449,"stroke":1275,"style":2106},[443,2251],{"x":2102,"y":2252,"width":2103,"height":2136,"rx":446,"fill":2105,"stroke":1275,"style":2106},"208.0",[471,2254,2256],{"x":2139,"y":2255,"style":2115},"227.0","7",[443,2258],{"x":2109,"y":2252,"width":2110,"height":2136,"rx":446,"fill":449,"stroke":1275,"style":2106},[443,2260],{"x":2119,"y":2252,"width":2120,"height":2136,"rx":446,"fill":449,"stroke":1275,"style":2106},[443,2262],{"x":2127,"y":2252,"width":2128,"height":2136,"rx":446,"fill":449,"stroke":1275,"style":2106},[443,2264],{"x":2102,"y":2265,"width":2103,"height":2136,"rx":446,"fill":2105,"stroke":1275,"style":2106},"236.0",[471,2267,2269],{"x":2139,"y":2268,"style":2115},"255.0","8",[443,2271],{"x":2109,"y":2265,"width":2110,"height":2136,"rx":446,"fill":499,"stroke":500,"style":2143},[471,2273,2275],{"x":2113,"y":2268,"style":2274},"font-size:10.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","text box: North led with 18,400",[443,2277],{"x":2119,"y":2265,"width":2120,"height":2136,"rx":446,"fill":449,"stroke":1275,"style":2106},[443,2279],{"x":2127,"y":2265,"width":2128,"height":2136,"rx":446,"fill":449,"stroke":1275,"style":2106},[25,2281,2283],{"id":2282},"common-pitfalls","Common pitfalls",[2285,2286,2287,2298,2304,2310,2316],"ul",{},[2288,2289,2290,2297],"li",{},[2291,2292,2293,2294,2296],"strong",{},"Expecting ",[14,2295,892],{}," to show in LibreOffice."," The box stays empty there; pass the text instead.",[2288,2299,2300,2303],{},[2291,2301,2302],{},"A fixed anchor below a growing table."," Compute the row from the data length.",[2288,2305,2306,2309],{},[2291,2307,2308],{},"Commentary in a cell."," It gets sorted, filtered and squashed by column widths; float it instead.",[2288,2311,2312,2315],{},[2291,2313,2314],{},"Trying to edit an existing file with XlsxWriter."," It only writes new workbooks.",[2288,2317,2318,2321,2322,2324],{},[2291,2319,2320],{},"Boxes that stretch when rows resize."," Set ",[14,2323,1831],{}," to 2 or 3 to keep the box its own size.",[25,2326,2328],{"id":2327},"conclusion","Conclusion",[10,2330,2331,2333,2334,2336],{},[14,2332,16],{}," puts free-floating commentary on an XlsxWriter sheet, with pixel sizes, fills, borders, gradients, fonts, alignment, rotation and hyperlinks controlled by one option dict. Text linked to a cell with ",[14,2335,892],{}," follows the cell in Excel but appears empty in LibreOffice, so finished reports should compose the sentence in Python. Anchor notes from the data length so they stay below tables, give boxes a description for screen readers, and render the output to check the text is there.",[25,2338,2340],{"id":2339},"frequently-asked-questions","Frequently asked questions",[10,2342,2343,2346],{},[2291,2344,2345],{},"How do I add a text box to an Excel sheet with Python?","\nWith XlsxWriter, call worksheet.insert_textbox with an anchor cell, the text and an options dict for width, height, font, fill, line and alignment. The box floats over the cells.",[10,2348,2349,2352],{},[2291,2350,2351],{},"Can a text box show the value of a cell?","\nYes, with the textlink option such as =Report!$D$1. Excel resolves the link when it opens the file; LibreOffice showed the box empty, so for portable reports compose the text in Python.",[10,2354,2355,2358],{},[2291,2356,2357],{},"How do I put a note below a table of changing length?","\nPass a zero-based row and column to insert_textbox and compute the row from the number of data rows, for example the length of the DataFrame plus two.",[10,2360,2361,2364],{},[2291,2362,2363],{},"Can XlsxWriter draw arrows or other shapes?","\nNo. Its text boxes are rectangles. Use a filled, borderless text box as a callout, formatting on the cell itself to point at a value, or an image for logos and watermarks.",[25,2366,2368],{"id":2367},"related","Related",[2285,2370,2371,2377,2384,2391],{},[2288,2372,2373,2374,2376],{},"Up one level: ",[19,2375,22],{"href":21}," — formatted reports and charts.",[2288,2378,2379,2383],{},[19,2380,2382],{"href":2381},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fwrite-rich-text-in-a-cell-with-xlsxwriter\u002F","Write Rich Text in a Cell with XlsxWriter"," — mixed formatting inside a cell.",[2288,2385,2386,2390],{},[19,2387,2389],{"href":2388},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fwrite-a-formatted-excel-report-with-xlsxwriter\u002F","Write a Formatted Excel Report with XlsxWriter"," — the report a note sits on.",[2288,2392,2393,2397],{},[19,2394,2396],{"href":2395},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Flabel-chart-points-from-cell-values-with-xlsxwriter\u002F","Label Chart Points from Cell Values with XlsxWriter"," — text on a chart instead of the sheet.",[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 .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}html pre.shiki code .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html pre.shiki code .s-wDw, html code.shiki .s-wDw{--shiki-default:#6A737D;--shiki-dark:#BDC4CC}html pre.shiki code .s_Opv, html code.shiki .s_Opv{--shiki-default:#6F42C1;--shiki-dark:#DBB7FF}",{"title":35,"searchDepth":96,"depth":96,"links":2403},[2404,2405,2406,2407,2408,2409,2410,2411,2412,2413,2414,2415],{"id":27,"depth":96,"text":28},{"id":69,"depth":96,"text":70},{"id":576,"depth":96,"text":577},{"id":885,"depth":96,"text":886},{"id":1329,"depth":96,"text":1330},{"id":1684,"depth":96,"text":1685},{"id":1843,"depth":96,"text":1844},{"id":1859,"depth":96,"text":1860},{"id":2282,"depth":96,"text":2283},{"id":2327,"depth":96,"text":2328},{"id":2339,"depth":96,"text":2340},{"id":2367,"depth":96,"text":2368},"2026-10-02","Float commentary, notes and labels over an Excel report with XlsxWriter insert_textbox: size, fill, border and font options, multi-line and rotated text, gradient fills and hyperlinks, text linked to a cell (and why it shows empty in LibreOffice), placing a box below a table of any length, and when a formatted cell is the better choice.","md",[2420,2422,2424,2426],{"q":2345,"a":2421},"With XlsxWriter, call worksheet.insert_textbox with an anchor cell, the text and an options dict for width, height, font, fill, line and alignment. The box floats over the cells.",{"q":2351,"a":2423},"Yes, with the textlink option such as =Report!$D$1. Excel resolves the link when it opens the file; LibreOffice showed the box empty, so for portable reports compose the text in Python.",{"q":2357,"a":2425},"Pass a zero-based row and column to insert_textbox and compute the row from the number of data rows, for example the length of the DataFrame plus two.",{"q":2363,"a":2427},"No. Its text boxes are rectangles. Use a filled, borderless text box as a callout, formatting on the cell itself to point at a value, or an image for logos and watermarks.","add text boxes and shapes to excel with xlsxwriter",null,{"breadcrumb":2431},[2432,2435,2438],{"name":2433,"item":2434},"Home","\u002F",{"name":2436,"item":2437},"Formatting and Charting Excel Reports with Python","\u002Fformatting-and-charting-excel-reports-with-python\u002F",{"name":2439,"item":21},"Building Excel Reports with xlsxwriter","\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fadd-text-boxes-and-shapes-to-excel-with-xlsxwriter",{"title":2442,"description":2443},"Add Text Boxes to an Excel Report with XlsxWriter","Use XlsxWriter insert_textbox to add notes and commentary to Excel: fills, borders, fonts, rotation, gradient and links, cell-linked text with its LibreOffice caveat, and positioning boxes after a table.","add-text-boxes-and-shapes-to-excel-with-xlsxwriter","formatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fadd-text-boxes-and-shapes-to-excel-with-xlsxwriter\u002Findex",[2447,2448],"report-layouts","xlsxwriter","how-to","FeysxVpD-4dHbu-8Y2tVXqje3j_D1Byzh2vUTvkSTXM",[2452,2456],{"title":2453,"path":2454,"stem":2455,"children":-1},"Add Sparklines to an Excel Report with xlsxwriter","\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fadd-sparklines-to-an-excel-report-with-xlsxwriter","formatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fadd-sparklines-to-an-excel-report-with-xlsxwriter\u002Findex",{"title":2457,"path":2458,"stem":2459,"children":-1},"Apply Conditional Formatting with xlsxwriter","\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fapply-conditional-formatting-with-xlsxwriter","formatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fapply-conditional-formatting-with-xlsxwriter\u002Findex",[2461,2463],{"path":2462,"title":2439},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter",{"path":2464,"title":2436},"\u002Fformatting-and-charting-excel-reports-with-python",[],[2467,2471,2474,2477,2480,2483],{"path":2468,"title":2469,"kind":2470},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports","Building Finance and Operations Reports in Excel with Python","guide",{"path":2472,"title":2473,"kind":2449},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fallocate-shared-costs-across-departments","Allocate Shared Costs Across Departments with Python",{"path":2475,"title":2476,"kind":2449},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-bank-reconciliation-report","Build a Bank Reconciliation Report with Python and Excel",{"path":2478,"title":2479,"kind":2449},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-bill-of-materials-cost-rollup","Build a Bill of Materials Cost Rollup",{"path":2481,"title":2482,"kind":2449},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-break-even-analysis-in-excel-with-python","Build a Break-Even Analysis in Excel with Python",{"path":2484,"title":2485,"kind":2486},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-budget-vs-actual-variance-report","Build a Budget vs Actual Variance Report in Excel with Python","compare",1790972107329]