[{"data":1,"prerenderedAt":2258},["ShallowReactive",2],{"doc:\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-charts-in-excel-with-openpyxl\u002Fadd-a-trendline-to-an-excel-chart-with-python":3,"surround:\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-charts-in-excel-with-openpyxl\u002Fadd-a-trendline-to-an-excel-chart-with-python":2224,"ancestors:\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-charts-in-excel-with-openpyxl\u002Fadd-a-trendline-to-an-excel-chart-with-python":2233,"children:\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-charts-in-excel-with-openpyxl\u002Fadd-a-trendline-to-an-excel-chart-with-python":2238,"related:\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-charts-in-excel-with-openpyxl\u002Fadd-a-trendline-to-an-excel-chart-with-python":2239},{"id":4,"title":5,"body":6,"dateModified":2190,"datePublished":2190,"description":2191,"extension":2192,"faq":2193,"keyword":2202,"kind":2203,"meta":2204,"navigation":344,"path":2213,"seo":2214,"slug":2217,"stem":2218,"topics":2219,"type":2222,"__hash__":2223},"docs\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-charts-in-excel-with-openpyxl\u002Fadd-a-trendline-to-an-excel-chart-with-python\u002Findex.md","Add a Trendline to an Excel Chart with Python",{"type":7,"value":8,"toc":2178},"minimark",[9,24,254,259,287,290,676,682,686,705,784,791,907,911,918,1027,1036,1040,1051,1248,1254,1258,1265,1510,1517,1667,1671,1674,2007,2018,2022,2060,2064,2113,2117,2123,2129,2135,2141,2145,2174],[10,11,12,13,18,19,23],"p",{},"A monthly orders chart with a noisy line leaves readers guessing whether things are improving. A trendline answers it: a straight line fitted through the points, optionally extended a few periods ahead, with its equation and R² on the chart. Excel computes trendlines itself when it draws the chart, so a trendline added from Python stays correct as the data changes. This guide, part of ",[14,15,17],"a",{"href":16},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-charts-in-excel-with-openpyxl\u002F","Creating Charts in Excel with openpyxl",", adds and styles trendlines on a line chart, chooses between trend types, and puts the fitted numbers in cells where both people and code can use them. Trendlines on scatter charts are covered in ",[14,20,22],{"href":21},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-charts-in-excel-with-openpyxl\u002Fcreate-a-scatter-chart-in-excel-with-openpyxl\u002F","Create a Scatter Chart in Excel with openpyxl",".",[25,26,34,35,34,39,34,43,34,51,34,60,34,67,34,72,34,76,34,84,34,89,34,93,34,97,34,100,34,104,34,107,34,111,34,114,34,118,34,121,34,127,34,131,34,135,34,139,34,143,34,147,34,151,34,155,34,159,34,163,34,167,34,171,34,177,34,183,34,186,34,189,34,192,34,194,34,197,34,200,34,203,34,206,34,209,34,212,34,215,34,218,34,221,34,224,34,227,34,230,34,233,34,236,34,239,34,242,34,245,34,248,34,251],"svg",{"viewBox":27,"role":28,"ariaLabelledBy":29,"xmlns":32,"style":33},"4 0 748 280","img",[30,31],"tl-chart-t","tl-chart-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:748px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[36,37,38],"title",{"id":30},"Monthly orders with a linear trend",[40,41,42],"desc",{"id":31},"Twelve months of orders rising from 120 to 188 with small ups and downs. The linear trend rises about 6.5 orders a month from 121 in the first month to 192 in the twelfth.",[44,45],"rect",{"x":46,"y":47,"width":48,"height":49,"fill":50},"4","0","748","280","#ffffff",[44,52],{"x":53,"y":54,"width":55,"height":55,"rx":56,"fill":57,"stroke":58,"style":59},"64.0","18.0","14.0","3","#f0f4ff","var(--brand,#5b5cf0)","stroke-width:1.5px",[61,62,66],"text",{"x":63,"y":64,"style":65},"84.0","29.5","font-size:12px;font-weight:600;fill:var(--text,#172033);text-anchor:start","Orders",[44,68],{"x":69,"y":54,"width":55,"height":55,"rx":56,"fill":70,"stroke":71,"style":59},"154.5","#fce9e9","var(--danger,#dc2626)",[61,73,75],{"x":74,"y":64,"style":65},"174.5","Linear trend",[77,78],"line",{"x1":79,"y1":80,"x2":81,"y2":80,"stroke":82,"style":83},"53.6","242.0","736.0","var(--line,#cdd5e6)","stroke-width:1px",[61,85,47],{"x":86,"y":87,"style":88},"30.8","246.0","font-size:11px;font-weight:400;fill:var(--muted,#5b6780);text-anchor:middle",[77,90],{"x1":79,"y1":91,"x2":81,"y2":91,"stroke":82,"style":92},"194.5","stroke-width:1px;stroke-dasharray:5 4",[61,94,96],{"x":86,"y":95,"style":88},"198.5","50",[77,98],{"x1":79,"y1":99,"x2":81,"y2":99,"stroke":82,"style":92},"147.0",[61,101,103],{"x":86,"y":102,"style":88},"151.0","100",[77,105],{"x1":79,"y1":106,"x2":81,"y2":106,"stroke":82,"style":92},"99.5",[61,108,110],{"x":86,"y":109,"style":88},"103.5","150",[77,112],{"x1":79,"y1":113,"x2":81,"y2":113,"stroke":82,"style":92},"52.0",[61,115,117],{"x":86,"y":116,"style":88},"56.0","200",[77,119],{"x1":79,"y1":80,"x2":81,"y2":80,"stroke":120,"style":59},"var(--muted,#5b6780)",[61,122,126],{"x":123,"y":124,"style":125},"82.1","260.0","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","M01",[61,128,130],{"x":129,"y":124,"style":125},"138.9","M02",[61,132,134],{"x":133,"y":124,"style":125},"195.8","M03",[61,136,138],{"x":137,"y":124,"style":125},"252.6","M04",[61,140,142],{"x":141,"y":124,"style":125},"309.5","M05",[61,144,146],{"x":145,"y":124,"style":125},"366.4","M06",[61,148,150],{"x":149,"y":124,"style":125},"423.2","M07",[61,152,154],{"x":153,"y":124,"style":125},"480.1","M08",[61,156,158],{"x":157,"y":124,"style":125},"537.0","M09",[61,160,162],{"x":161,"y":124,"style":125},"593.8","M10",[61,164,166],{"x":165,"y":124,"style":125},"650.7","M11",[61,168,170],{"x":169,"y":124,"style":125},"707.6","M12",[172,173],"path",{"d":174,"fill":175,"stroke":58,"style":176},"M82.1,128.0 L138.9,116.6 L195.8,120.4 L252.6,108.1 L309.5,99.5 L366.4,100.4 L423.2,88.1 L480.1,79.6 L537.0,82.4 L593.8,71.0 L650.7,60.6 L707.6,63.4","none","stroke-width:2.5px;stroke-linejoin:round;stroke-linecap:round",[178,179],"circle",{"cx":123,"cy":180,"r":181,"fill":50,"stroke":58,"style":182},"128.0","4.0","stroke-width:2px",[178,184],{"cx":129,"cy":185,"r":181,"fill":50,"stroke":58,"style":182},"116.6",[178,187],{"cx":133,"cy":188,"r":181,"fill":50,"stroke":58,"style":182},"120.4",[178,190],{"cx":137,"cy":191,"r":181,"fill":50,"stroke":58,"style":182},"108.1",[178,193],{"cx":141,"cy":106,"r":181,"fill":50,"stroke":58,"style":182},[178,195],{"cx":145,"cy":196,"r":181,"fill":50,"stroke":58,"style":182},"100.4",[178,198],{"cx":149,"cy":199,"r":181,"fill":50,"stroke":58,"style":182},"88.1",[178,201],{"cx":153,"cy":202,"r":181,"fill":50,"stroke":58,"style":182},"79.6",[178,204],{"cx":157,"cy":205,"r":181,"fill":50,"stroke":58,"style":182},"82.4",[178,207],{"cx":161,"cy":208,"r":181,"fill":50,"stroke":58,"style":182},"71.0",[178,210],{"cx":165,"cy":211,"r":181,"fill":50,"stroke":58,"style":182},"60.6",[178,213],{"cx":169,"cy":214,"r":181,"fill":50,"stroke":58,"style":182},"63.4",[172,216],{"d":217,"fill":175,"stroke":71,"style":176},"M82.1,127.0 L138.9,120.9 L195.8,114.7 L252.6,108.5 L309.5,102.4 L366.4,96.3 L423.2,90.1 L480.1,83.9 L537.0,77.7 L593.8,71.6 L650.7,65.5 L707.6,59.3",[178,219],{"cx":123,"cy":220,"r":181,"fill":50,"stroke":71,"style":182},"127.0",[178,222],{"cx":129,"cy":223,"r":181,"fill":50,"stroke":71,"style":182},"120.9",[178,225],{"cx":133,"cy":226,"r":181,"fill":50,"stroke":71,"style":182},"114.7",[178,228],{"cx":137,"cy":229,"r":181,"fill":50,"stroke":71,"style":182},"108.5",[178,231],{"cx":141,"cy":232,"r":181,"fill":50,"stroke":71,"style":182},"102.4",[178,234],{"cx":145,"cy":235,"r":181,"fill":50,"stroke":71,"style":182},"96.3",[178,237],{"cx":149,"cy":238,"r":181,"fill":50,"stroke":71,"style":182},"90.1",[178,240],{"cx":153,"cy":241,"r":181,"fill":50,"stroke":71,"style":182},"83.9",[178,243],{"cx":157,"cy":244,"r":181,"fill":50,"stroke":71,"style":182},"77.7",[178,246],{"cx":161,"cy":247,"r":181,"fill":50,"stroke":71,"style":182},"71.6",[178,249],{"cx":165,"cy":250,"r":181,"fill":50,"stroke":71,"style":182},"65.5",[178,252],{"cx":169,"cy":253,"r":181,"fill":50,"stroke":71,"style":182},"59.3",[255,256,258],"h2",{"id":257},"prerequisites","Prerequisites",[260,261,266],"pre",{"className":262,"code":263,"language":264,"meta":265,"style":265},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install openpyxl numpy\n","bash","",[267,268,269],"code",{"__ignoreMap":265},[270,271,273,277,281,284],"span",{"class":77,"line":272},1,[270,274,276],{"class":275},"sMTad","pip",[270,278,280],{"class":279},"srMev"," install",[270,282,283],{"class":279}," openpyxl",[270,285,286],{"class":279}," numpy\n",[10,288,289],{},"Twelve months of orders and a line chart:",[260,291,295],{"className":292,"code":293,"language":294,"meta":265,"style":265},"language-python shiki shiki-themes github-light github-dark-high-contrast","from openpyxl import Workbook\nfrom openpyxl.chart import LineChart, Reference\nfrom openpyxl.chart.trendline import Trendline\n\norders = [120, 132, 128, 141, 150, 149, 162, 171, 168, 180, 191, 188]\nwb = Workbook()\nws = wb.active\nws.title = \"Orders\"\nws.append([\"Month\", \"Orders\"])\nfor i, value in enumerate(orders, start=1):\n    ws.append([f\"M{i:02d}\", value])\n\nchart = LineChart()\nchart.x_axis.delete = False  # Excel hides axes unless this is set\nchart.y_axis.delete = False\nchart.add_data(Reference(ws, min_col=2, min_row=1, max_row=13), titles_from_data=True)\nchart.set_categories(Reference(ws, min_col=1, min_row=2, max_row=13))\nseries = chart.series[0]\nseries.smooth = False\n","python",[267,296,297,313,326,339,346,420,431,442,453,470,500,531,536,547,562,573,620,651,666],{"__ignoreMap":265},[270,298,299,303,307,310],{"class":77,"line":272},[270,300,302],{"class":301},"s-kum","from",[270,304,306],{"class":305},"skGVy"," openpyxl ",[270,308,309],{"class":301},"import",[270,311,312],{"class":305}," Workbook\n",[270,314,316,318,321,323],{"class":77,"line":315},2,[270,317,302],{"class":301},[270,319,320],{"class":305}," openpyxl.chart ",[270,322,309],{"class":301},[270,324,325],{"class":305}," LineChart, Reference\n",[270,327,329,331,334,336],{"class":77,"line":328},3,[270,330,302],{"class":301},[270,332,333],{"class":305}," openpyxl.chart.trendline ",[270,335,309],{"class":301},[270,337,338],{"class":305}," Trendline\n",[270,340,342],{"class":77,"line":341},4,[270,343,345],{"emptyLinePlaceholder":344},true,"\n",[270,347,349,352,355,358,362,365,368,370,373,375,378,380,382,384,387,389,392,394,397,399,402,404,407,409,412,414,417],{"class":77,"line":348},5,[270,350,351],{"class":305},"orders ",[270,353,354],{"class":301},"=",[270,356,357],{"class":305}," [",[270,359,361],{"class":360},"sP0c6","120",[270,363,364],{"class":305},", ",[270,366,367],{"class":360},"132",[270,369,364],{"class":305},[270,371,372],{"class":360},"128",[270,374,364],{"class":305},[270,376,377],{"class":360},"141",[270,379,364],{"class":305},[270,381,110],{"class":360},[270,383,364],{"class":305},[270,385,386],{"class":360},"149",[270,388,364],{"class":305},[270,390,391],{"class":360},"162",[270,393,364],{"class":305},[270,395,396],{"class":360},"171",[270,398,364],{"class":305},[270,400,401],{"class":360},"168",[270,403,364],{"class":305},[270,405,406],{"class":360},"180",[270,408,364],{"class":305},[270,410,411],{"class":360},"191",[270,413,364],{"class":305},[270,415,416],{"class":360},"188",[270,418,419],{"class":305},"]\n",[270,421,423,426,428],{"class":77,"line":422},6,[270,424,425],{"class":305},"wb ",[270,427,354],{"class":301},[270,429,430],{"class":305}," Workbook()\n",[270,432,434,437,439],{"class":77,"line":433},7,[270,435,436],{"class":305},"ws ",[270,438,354],{"class":301},[270,440,441],{"class":305}," wb.active\n",[270,443,445,448,450],{"class":77,"line":444},8,[270,446,447],{"class":305},"ws.title ",[270,449,354],{"class":301},[270,451,452],{"class":279}," \"Orders\"\n",[270,454,456,459,462,464,467],{"class":77,"line":455},9,[270,457,458],{"class":305},"ws.append([",[270,460,461],{"class":279},"\"Month\"",[270,463,364],{"class":305},[270,465,466],{"class":279},"\"Orders\"",[270,468,469],{"class":305},"])\n",[270,471,473,476,479,482,485,488,492,494,497],{"class":77,"line":472},10,[270,474,475],{"class":301},"for",[270,477,478],{"class":305}," i, value ",[270,480,481],{"class":301},"in",[270,483,484],{"class":360}," enumerate",[270,486,487],{"class":305},"(orders, ",[270,489,491],{"class":490},"sa561","start",[270,493,354],{"class":301},[270,495,496],{"class":360},"1",[270,498,499],{"class":305},"):\n",[270,501,503,506,509,512,516,519,522,525,528],{"class":77,"line":502},11,[270,504,505],{"class":305},"    ws.append([",[270,507,508],{"class":301},"f",[270,510,511],{"class":279},"\"M",[270,513,515],{"class":514},"sSjpA","{",[270,517,518],{"class":305},"i",[270,520,521],{"class":301},":02d",[270,523,524],{"class":514},"}",[270,526,527],{"class":279},"\"",[270,529,530],{"class":305},", value])\n",[270,532,534],{"class":77,"line":533},12,[270,535,345],{"emptyLinePlaceholder":344},[270,537,539,542,544],{"class":77,"line":538},13,[270,540,541],{"class":305},"chart ",[270,543,354],{"class":301},[270,545,546],{"class":305}," LineChart()\n",[270,548,550,553,555,558],{"class":77,"line":549},14,[270,551,552],{"class":305},"chart.x_axis.delete ",[270,554,354],{"class":301},[270,556,557],{"class":360}," False",[270,559,561],{"class":560},"s-wDw","  # Excel hides axes unless this is set\n",[270,563,565,568,570],{"class":77,"line":564},15,[270,566,567],{"class":305},"chart.y_axis.delete ",[270,569,354],{"class":301},[270,571,572],{"class":360}," False\n",[270,574,576,579,582,584,587,589,592,594,596,598,601,603,606,609,612,614,617],{"class":77,"line":575},16,[270,577,578],{"class":305},"chart.add_data(Reference(ws, ",[270,580,581],{"class":490},"min_col",[270,583,354],{"class":301},[270,585,586],{"class":360},"2",[270,588,364],{"class":305},[270,590,591],{"class":490},"min_row",[270,593,354],{"class":301},[270,595,496],{"class":360},[270,597,364],{"class":305},[270,599,600],{"class":490},"max_row",[270,602,354],{"class":301},[270,604,605],{"class":360},"13",[270,607,608],{"class":305},"), ",[270,610,611],{"class":490},"titles_from_data",[270,613,354],{"class":301},[270,615,616],{"class":360},"True",[270,618,619],{"class":305},")\n",[270,621,623,626,628,630,632,634,636,638,640,642,644,646,648],{"class":77,"line":622},17,[270,624,625],{"class":305},"chart.set_categories(Reference(ws, ",[270,627,581],{"class":490},[270,629,354],{"class":301},[270,631,496],{"class":360},[270,633,364],{"class":305},[270,635,591],{"class":490},[270,637,354],{"class":301},[270,639,586],{"class":360},[270,641,364],{"class":305},[270,643,600],{"class":490},[270,645,354],{"class":301},[270,647,605],{"class":360},[270,649,650],{"class":305},"))\n",[270,652,654,657,659,662,664],{"class":77,"line":653},18,[270,655,656],{"class":305},"series ",[270,658,354],{"class":301},[270,660,661],{"class":305}," chart.series[",[270,663,47],{"class":360},[270,665,419],{"class":305},[270,667,669,672,674],{"class":77,"line":668},19,[270,670,671],{"class":305},"series.smooth ",[270,673,354],{"class":301},[270,675,572],{"class":360},[10,677,678,681],{},[267,679,680],{},"series.smooth = False"," is worth setting explicitly on every line series: openpyxl leaves the setting out of the file unless you do, and LibreOffice then drew the line smoothed in our test — curves that suggest values between points that were never measured.",[255,683,685],{"id":684},"step-1-a-linear-trendline-with-equation-and-r","Step 1 — A linear trendline with equation and R²",[10,687,688,689,692,693,696,697,700,701,704],{},"Assign a ",[267,690,691],{},"Trendline"," to the series. ",[267,694,695],{},"dispEq"," and ",[267,698,699],{},"dispRSqr"," put the fitted equation and the R² value on the chart; ",[267,702,703],{},"forward"," extends the line a number of periods beyond the data:",[260,706,708],{"className":292,"code":707,"language":294,"meta":265,"style":265},"series.trendline = Trendline(trendlineType=\"linear\", dispEq=True, dispRSqr=True, forward=3)\nchart.title = \"Orders with trend\"\nws.add_chart(chart, \"D2\")\nwb.save(\"trend.xlsx\")\n",[267,709,710,754,764,774],{"__ignoreMap":265},[270,711,712,715,717,720,723,725,728,730,732,734,736,738,740,742,744,746,748,750,752],{"class":77,"line":272},[270,713,714],{"class":305},"series.trendline ",[270,716,354],{"class":301},[270,718,719],{"class":305}," Trendline(",[270,721,722],{"class":490},"trendlineType",[270,724,354],{"class":301},[270,726,727],{"class":279},"\"linear\"",[270,729,364],{"class":305},[270,731,695],{"class":490},[270,733,354],{"class":301},[270,735,616],{"class":360},[270,737,364],{"class":305},[270,739,699],{"class":490},[270,741,354],{"class":301},[270,743,616],{"class":360},[270,745,364],{"class":305},[270,747,703],{"class":490},[270,749,354],{"class":301},[270,751,56],{"class":360},[270,753,619],{"class":305},[270,755,756,759,761],{"class":77,"line":315},[270,757,758],{"class":305},"chart.title ",[270,760,354],{"class":301},[270,762,763],{"class":279}," \"Orders with trend\"\n",[270,765,766,769,772],{"class":77,"line":328},[270,767,768],{"class":305},"ws.add_chart(chart, ",[270,770,771],{"class":279},"\"D2\"",[270,773,619],{"class":305},[270,775,776,779,782],{"class":77,"line":341},[270,777,778],{"class":305},"wb.save(",[270,780,781],{"class":279},"\"trend.xlsx\"",[270,783,619],{"class":305},[10,785,786,787,790],{},"Rendering the workbook shows the equation 6.4825x + 114.53 and R² 0.9707: about six and a half more orders each month, and a line that explains 97% of the month-to-month variation. The three forward periods continue the line past M12. The label shows every decimal Excel computed; openpyxl can attach a number format to it through ",[267,788,789],{},"trendlineLbl",", but LibreOffice ignored it in our test, which is one more reason to put the figures in cells (Step 4).",[25,792,34,798,34,801,34,804,34,808,34,814,34,819,34,825,34,828,34,832,34,836,34,842,34,844,34,848,34,850,34,853,34,856,34,860,34,862,34,866,34,868,34,871,34,874,34,878,34,880,34,884,34,886,34,889,34,892,34,896,34,898,34,902,34,904],{"viewBox":793,"role":28,"ariaLabelledBy":794,"xmlns":32,"style":797},"4 0 752 208",[795,796],"tl-types-t","tl-types-d","width:100%;max-width:752px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[36,799,800],{"id":795},"Choosing a trendline type",[40,802,803],{"id":796},"A linear trend suits steady growth by a similar amount each period. A moving average smooths noise without assuming a shape. A polynomial of order 2 follows one bend, such as growth that slows. An exponential trend suits growth by a similar percentage each period and needs strictly positive values.",[44,805],{"x":46,"y":47,"width":806,"height":807,"fill":50},"752","208",[44,809],{"x":810,"y":811,"width":812,"height":813,"rx":47,"fill":50,"stroke":82,"style":83},"20.0","16.0","156.2","40.0",[44,815],{"x":816,"y":811,"width":817,"height":813,"rx":47,"fill":57,"stroke":58,"style":818},"176.2","281.9","stroke-width:1.2px",[61,820,824],{"x":821,"y":822,"style":823},"317.2","41.0","font-size:13px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Assumes",[44,826],{"x":827,"y":811,"width":817,"height":813,"rx":47,"fill":57,"stroke":58,"style":818},"458.1",[61,829,831],{"x":830,"y":822,"style":823},"599.1","Use for",[44,833],{"x":810,"y":116,"width":812,"height":834,"rx":47,"fill":835,"stroke":82,"style":83},"34.0","#e7ebef",[61,837,841],{"x":838,"y":839,"style":840},"32.0","78.0","font-size:12.5px;font-weight:700;fill:var(--text,#172033);text-anchor:start","linear",[44,843],{"x":816,"y":116,"width":817,"height":834,"rx":47,"fill":50,"stroke":82,"style":83},[61,845,847],{"x":821,"y":846,"style":125},"77.0","same amount per period",[44,849],{"x":827,"y":116,"width":817,"height":834,"rx":47,"fill":50,"stroke":82,"style":83},[61,851,852],{"x":830,"y":846,"style":125},"steady growth",[44,854],{"x":810,"y":855,"width":812,"height":834,"rx":47,"fill":835,"stroke":82,"style":83},"90.0",[61,857,859],{"x":838,"y":858,"style":840},"112.0","movingAvg (period)",[44,861],{"x":816,"y":855,"width":817,"height":834,"rx":47,"fill":50,"stroke":82,"style":83},[61,863,865],{"x":821,"y":864,"style":125},"111.0","no shape",[44,867],{"x":827,"y":855,"width":817,"height":834,"rx":47,"fill":50,"stroke":82,"style":83},[61,869,870],{"x":830,"y":864,"style":125},"smoothing noise",[44,872],{"x":810,"y":873,"width":812,"height":834,"rx":47,"fill":835,"stroke":82,"style":83},"124.0",[61,875,877],{"x":838,"y":876,"style":840},"146.0","poly (order 2)",[44,879],{"x":816,"y":873,"width":817,"height":834,"rx":47,"fill":50,"stroke":82,"style":83},[61,881,883],{"x":821,"y":882,"style":125},"145.0","one bend",[44,885],{"x":827,"y":873,"width":817,"height":834,"rx":47,"fill":50,"stroke":82,"style":83},[61,887,888],{"x":830,"y":882,"style":125},"growth that slows",[44,890],{"x":810,"y":891,"width":812,"height":834,"rx":47,"fill":835,"stroke":82,"style":83},"158.0",[61,893,895],{"x":838,"y":894,"style":840},"180.0","exp",[44,897],{"x":816,"y":891,"width":817,"height":834,"rx":47,"fill":50,"stroke":82,"style":83},[61,899,901],{"x":821,"y":900,"style":125},"179.0","same % per period",[44,903],{"x":827,"y":891,"width":817,"height":834,"rx":47,"fill":50,"stroke":82,"style":83},[61,905,906],{"x":830,"y":900,"style":125},"compounding; values > 0",[255,908,910],{"id":909},"step-2-style-the-trendline","Step 2 — Style the trendline",[10,912,913,914,917],{},"A trendline's default style is a thin line in the series colour, easily mistaken for data. Give it its own colour and a dash through ",[267,915,916],{},"spPr",":",[260,919,921],{"className":292,"code":920,"language":294,"meta":265,"style":265},"from openpyxl.chart.shapes import GraphicalProperties\nfrom openpyxl.drawing.line import LineProperties\n\nseries.graphicalProperties.line.solidFill = \"4338CA\"\nseries.trendline.spPr = GraphicalProperties(ln=LineProperties(solidFill=\"B91C1C\", prstDash=\"dash\", w=19050))\nseries.trendline.name = \"Linear trend\"\nwb.save(\"trend.xlsx\")\n",[267,922,923,935,947,951,961,1009,1019],{"__ignoreMap":265},[270,924,925,927,930,932],{"class":77,"line":272},[270,926,302],{"class":301},[270,928,929],{"class":305}," openpyxl.chart.shapes ",[270,931,309],{"class":301},[270,933,934],{"class":305}," GraphicalProperties\n",[270,936,937,939,942,944],{"class":77,"line":315},[270,938,302],{"class":301},[270,940,941],{"class":305}," openpyxl.drawing.line ",[270,943,309],{"class":301},[270,945,946],{"class":305}," LineProperties\n",[270,948,949],{"class":77,"line":328},[270,950,345],{"emptyLinePlaceholder":344},[270,952,953,956,958],{"class":77,"line":341},[270,954,955],{"class":305},"series.graphicalProperties.line.solidFill ",[270,957,354],{"class":301},[270,959,960],{"class":279}," \"4338CA\"\n",[270,962,963,966,968,971,974,976,979,982,984,987,989,992,994,997,999,1002,1004,1007],{"class":77,"line":348},[270,964,965],{"class":305},"series.trendline.spPr ",[270,967,354],{"class":301},[270,969,970],{"class":305}," GraphicalProperties(",[270,972,973],{"class":490},"ln",[270,975,354],{"class":301},[270,977,978],{"class":305},"LineProperties(",[270,980,981],{"class":490},"solidFill",[270,983,354],{"class":301},[270,985,986],{"class":279},"\"B91C1C\"",[270,988,364],{"class":305},[270,990,991],{"class":490},"prstDash",[270,993,354],{"class":301},[270,995,996],{"class":279},"\"dash\"",[270,998,364],{"class":305},[270,1000,1001],{"class":490},"w",[270,1003,354],{"class":301},[270,1005,1006],{"class":360},"19050",[270,1008,650],{"class":305},[270,1010,1011,1014,1016],{"class":77,"line":422},[270,1012,1013],{"class":305},"series.trendline.name ",[270,1015,354],{"class":301},[270,1017,1018],{"class":279}," \"Linear trend\"\n",[270,1020,1021,1023,1025],{"class":77,"line":433},[270,1022,778],{"class":305},[270,1024,781],{"class":279},[270,1026,619],{"class":305},[10,1028,1029,1031,1032,23],{},[267,1030,1001],{}," is the width in EMUs — 19,050 is 1.5 points. Naming the trendline sets the legend entry; without a name, Excel and LibreOffice show \"Linear (Orders)\". Dashed and coloured differently from the series, the trend reads as an annotation rather than a second measurement. More chart styling is covered in ",[14,1033,1035],{"href":1034},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-charts-in-excel-with-openpyxl\u002Fstyle-chart-colors-and-data-labels-with-openpyxl\u002F","Style Chart Colours and Data Labels with openpyxl",[255,1037,1039],{"id":1038},"step-3-moving-averages-and-curved-trends","Step 3 — Moving averages and curved trends",[10,1041,1042,1043,1046,1047,1050],{},"Other types need one extra argument. A moving average needs a ",[267,1044,1045],{},"period",", a polynomial an ",[267,1048,1049],{},"order","; an exponential trend needs every value to be positive:",[260,1052,1054],{"className":292,"code":1053,"language":294,"meta":265,"style":265},"smooth_chart = LineChart()\nsmooth_chart.x_axis.delete = False\nsmooth_chart.y_axis.delete = False\nsmooth_chart.add_data(Reference(ws, min_col=2, min_row=1, max_row=13), titles_from_data=True)\nsmooth_chart.series[0].smooth = False\nsmooth_chart.series[0].trendline = Trendline(trendlineType=\"movingAvg\", period=3,\n                                             dispEq=False, dispRSqr=False)\ncurve = Trendline(trendlineType=\"poly\", order=2, dispEq=True)\nprint(curve.trendlineType, curve.order)          # poly 2\nws.add_chart(smooth_chart, \"D20\")\nwb.save(\"trend.xlsx\")\n",[267,1055,1056,1065,1074,1083,1120,1134,1165,1185,1219,1230,1240],{"__ignoreMap":265},[270,1057,1058,1061,1063],{"class":77,"line":272},[270,1059,1060],{"class":305},"smooth_chart ",[270,1062,354],{"class":301},[270,1064,546],{"class":305},[270,1066,1067,1070,1072],{"class":77,"line":315},[270,1068,1069],{"class":305},"smooth_chart.x_axis.delete ",[270,1071,354],{"class":301},[270,1073,572],{"class":360},[270,1075,1076,1079,1081],{"class":77,"line":328},[270,1077,1078],{"class":305},"smooth_chart.y_axis.delete ",[270,1080,354],{"class":301},[270,1082,572],{"class":360},[270,1084,1085,1088,1090,1092,1094,1096,1098,1100,1102,1104,1106,1108,1110,1112,1114,1116,1118],{"class":77,"line":341},[270,1086,1087],{"class":305},"smooth_chart.add_data(Reference(ws, ",[270,1089,581],{"class":490},[270,1091,354],{"class":301},[270,1093,586],{"class":360},[270,1095,364],{"class":305},[270,1097,591],{"class":490},[270,1099,354],{"class":301},[270,1101,496],{"class":360},[270,1103,364],{"class":305},[270,1105,600],{"class":490},[270,1107,354],{"class":301},[270,1109,605],{"class":360},[270,1111,608],{"class":305},[270,1113,611],{"class":490},[270,1115,354],{"class":301},[270,1117,616],{"class":360},[270,1119,619],{"class":305},[270,1121,1122,1125,1127,1130,1132],{"class":77,"line":348},[270,1123,1124],{"class":305},"smooth_chart.series[",[270,1126,47],{"class":360},[270,1128,1129],{"class":305},"].smooth ",[270,1131,354],{"class":301},[270,1133,572],{"class":360},[270,1135,1136,1138,1140,1143,1145,1147,1149,1151,1154,1156,1158,1160,1162],{"class":77,"line":422},[270,1137,1124],{"class":305},[270,1139,47],{"class":360},[270,1141,1142],{"class":305},"].trendline ",[270,1144,354],{"class":301},[270,1146,719],{"class":305},[270,1148,722],{"class":490},[270,1150,354],{"class":301},[270,1152,1153],{"class":279},"\"movingAvg\"",[270,1155,364],{"class":305},[270,1157,1045],{"class":490},[270,1159,354],{"class":301},[270,1161,56],{"class":360},[270,1163,1164],{"class":305},",\n",[270,1166,1167,1170,1172,1175,1177,1179,1181,1183],{"class":77,"line":433},[270,1168,1169],{"class":490},"                                             dispEq",[270,1171,354],{"class":301},[270,1173,1174],{"class":360},"False",[270,1176,364],{"class":305},[270,1178,699],{"class":490},[270,1180,354],{"class":301},[270,1182,1174],{"class":360},[270,1184,619],{"class":305},[270,1186,1187,1190,1192,1194,1196,1198,1201,1203,1205,1207,1209,1211,1213,1215,1217],{"class":77,"line":444},[270,1188,1189],{"class":305},"curve ",[270,1191,354],{"class":301},[270,1193,719],{"class":305},[270,1195,722],{"class":490},[270,1197,354],{"class":301},[270,1199,1200],{"class":279},"\"poly\"",[270,1202,364],{"class":305},[270,1204,1049],{"class":490},[270,1206,354],{"class":301},[270,1208,586],{"class":360},[270,1210,364],{"class":305},[270,1212,695],{"class":490},[270,1214,354],{"class":301},[270,1216,616],{"class":360},[270,1218,619],{"class":305},[270,1220,1221,1224,1227],{"class":77,"line":455},[270,1222,1223],{"class":360},"print",[270,1225,1226],{"class":305},"(curve.trendlineType, curve.order)          ",[270,1228,1229],{"class":560},"# poly 2\n",[270,1231,1232,1235,1238],{"class":77,"line":472},[270,1233,1234],{"class":305},"ws.add_chart(smooth_chart, ",[270,1236,1237],{"class":279},"\"D20\"",[270,1239,619],{"class":305},[270,1241,1242,1244,1246],{"class":77,"line":502},[270,1243,778],{"class":305},[270,1245,781],{"class":279},[270,1247,619],{"class":305},[10,1249,1250,1251,1253],{},"A three-period moving average starts at the third point and follows the data more closely than a straight line, which makes it a smoother rather than a model — there is no equation to show, so switch the labels off explicitly. A second-order polynomial bends once and suits growth that is levelling off, but it extrapolates badly: keep ",[267,1252,703],{}," short or off. Pick the type that matches how the business actually behaves; a higher R² from a more flexible curve is not a better explanation.",[255,1255,1257],{"id":1256},"step-4-put-the-fitted-numbers-in-cells","Step 4 — Put the fitted numbers in cells",[10,1259,1260,1261,917],{},"The equation on a chart cannot be read by code, and people cannot copy it into a calculation. Write the same statistics as formulas next to the data, and store their values — computed with numpy — so every reader sees them, as explained in ",[14,1262,1264],{"href":1263},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fstore-formula-results-with-xlsxwriter\u002F","Store Formula Results with xlsxwriter So Every Viewer Shows Values",[260,1266,1268],{"className":292,"code":1267,"language":294,"meta":265,"style":265},"import numpy as np\n\nx = np.arange(1, len(orders) + 1)\nslope, intercept = np.polyfit(x, orders, 1)\nr_squared = np.corrcoef(x, orders)[0, 1] ** 2\nforecast_15 = slope * 15 + intercept\nprint(round(slope, 4), round(intercept, 2), round(r_squared, 4), round(forecast_15, 1))\n# 6.4825 114.53 0.9707 211.8\n\nws[\"D1\"], ws[\"E1\"] = \"Trend per month\", \"=SLOPE(B2:B13,ROW(B2:B13)-1)\"\nws[\"D2\"], ws[\"E2\"] = \"Intercept\", \"=INTERCEPT(B2:B13,ROW(B2:B13)-1)\"\nws[\"D3\"], ws[\"E3\"] = \"R squared\", \"=RSQ(B2:B13,ROW(B2:B13)-1)\"\nwb.save(\"trend.xlsx\")\n",[267,1269,1270,1283,1287,1315,1329,1354,1376,1420,1425,1429,1455,1478,1502],{"__ignoreMap":265},[270,1271,1272,1274,1277,1280],{"class":77,"line":272},[270,1273,309],{"class":301},[270,1275,1276],{"class":305}," numpy ",[270,1278,1279],{"class":301},"as",[270,1281,1282],{"class":305}," np\n",[270,1284,1285],{"class":77,"line":315},[270,1286,345],{"emptyLinePlaceholder":344},[270,1288,1289,1292,1294,1297,1299,1301,1304,1307,1310,1313],{"class":77,"line":328},[270,1290,1291],{"class":305},"x ",[270,1293,354],{"class":301},[270,1295,1296],{"class":305}," np.arange(",[270,1298,496],{"class":360},[270,1300,364],{"class":305},[270,1302,1303],{"class":360},"len",[270,1305,1306],{"class":305},"(orders) ",[270,1308,1309],{"class":301},"+",[270,1311,1312],{"class":360}," 1",[270,1314,619],{"class":305},[270,1316,1317,1320,1322,1325,1327],{"class":77,"line":341},[270,1318,1319],{"class":305},"slope, intercept ",[270,1321,354],{"class":301},[270,1323,1324],{"class":305}," np.polyfit(x, orders, ",[270,1326,496],{"class":360},[270,1328,619],{"class":305},[270,1330,1331,1334,1336,1339,1341,1343,1345,1348,1351],{"class":77,"line":348},[270,1332,1333],{"class":305},"r_squared ",[270,1335,354],{"class":301},[270,1337,1338],{"class":305}," np.corrcoef(x, orders)[",[270,1340,47],{"class":360},[270,1342,364],{"class":305},[270,1344,496],{"class":360},[270,1346,1347],{"class":305},"] ",[270,1349,1350],{"class":301},"**",[270,1352,1353],{"class":360}," 2\n",[270,1355,1356,1359,1361,1364,1367,1370,1373],{"class":77,"line":422},[270,1357,1358],{"class":305},"forecast_15 ",[270,1360,354],{"class":301},[270,1362,1363],{"class":305}," slope ",[270,1365,1366],{"class":301},"*",[270,1368,1369],{"class":360}," 15",[270,1371,1372],{"class":301}," +",[270,1374,1375],{"class":305}," intercept\n",[270,1377,1378,1380,1383,1386,1389,1391,1393,1395,1398,1400,1402,1404,1407,1409,1411,1413,1416,1418],{"class":77,"line":433},[270,1379,1223],{"class":360},[270,1381,1382],{"class":305},"(",[270,1384,1385],{"class":360},"round",[270,1387,1388],{"class":305},"(slope, ",[270,1390,46],{"class":360},[270,1392,608],{"class":305},[270,1394,1385],{"class":360},[270,1396,1397],{"class":305},"(intercept, ",[270,1399,586],{"class":360},[270,1401,608],{"class":305},[270,1403,1385],{"class":360},[270,1405,1406],{"class":305},"(r_squared, ",[270,1408,46],{"class":360},[270,1410,608],{"class":305},[270,1412,1385],{"class":360},[270,1414,1415],{"class":305},"(forecast_15, ",[270,1417,496],{"class":360},[270,1419,650],{"class":305},[270,1421,1422],{"class":77,"line":444},[270,1423,1424],{"class":560},"# 6.4825 114.53 0.9707 211.8\n",[270,1426,1427],{"class":77,"line":455},[270,1428,345],{"emptyLinePlaceholder":344},[270,1430,1431,1434,1437,1440,1443,1445,1447,1450,1452],{"class":77,"line":472},[270,1432,1433],{"class":305},"ws[",[270,1435,1436],{"class":279},"\"D1\"",[270,1438,1439],{"class":305},"], ws[",[270,1441,1442],{"class":279},"\"E1\"",[270,1444,1347],{"class":305},[270,1446,354],{"class":301},[270,1448,1449],{"class":279}," \"Trend per month\"",[270,1451,364],{"class":305},[270,1453,1454],{"class":279},"\"=SLOPE(B2:B13,ROW(B2:B13)-1)\"\n",[270,1456,1457,1459,1461,1463,1466,1468,1470,1473,1475],{"class":77,"line":502},[270,1458,1433],{"class":305},[270,1460,771],{"class":279},[270,1462,1439],{"class":305},[270,1464,1465],{"class":279},"\"E2\"",[270,1467,1347],{"class":305},[270,1469,354],{"class":301},[270,1471,1472],{"class":279}," \"Intercept\"",[270,1474,364],{"class":305},[270,1476,1477],{"class":279},"\"=INTERCEPT(B2:B13,ROW(B2:B13)-1)\"\n",[270,1479,1480,1482,1485,1487,1490,1492,1494,1497,1499],{"class":77,"line":533},[270,1481,1433],{"class":305},[270,1483,1484],{"class":279},"\"D3\"",[270,1486,1439],{"class":305},[270,1488,1489],{"class":279},"\"E3\"",[270,1491,1347],{"class":305},[270,1493,354],{"class":301},[270,1495,1496],{"class":279}," \"R squared\"",[270,1498,364],{"class":305},[270,1500,1501],{"class":279},"\"=RSQ(B2:B13,ROW(B2:B13)-1)\"\n",[270,1503,1504,1506,1508],{"class":77,"line":538},[270,1505,778],{"class":305},[270,1507,781],{"class":279},[270,1509,619],{"class":305},[10,1511,1512,1513,1516],{},"numpy's fit over x = 1…12 matches the chart's equation exactly, because Excel numbers the points of a category chart 1, 2, 3 and so on. ",[267,1514,1515],{},"ROW(B2:B13)-1"," produces the same 1…12 inside the formulas; recalculating the saved file in LibreOffice gives 6.4825, 114.53 and 0.9707, the same figures as the chart. The forecast for month 15 — the end of the three forward periods — is about 212 orders. openpyxl stores formulas without results; with openpyxl the cached values are not written, so for readers that do not recalculate, write the numbers themselves in an adjacent column or build the workbook with XlsxWriter.",[25,1518,34,1523,34,1526,34,1529,34,1532,34,1537,34,1546,34,1552,34,1556,34,1561,34,1566,34,1569,34,1575,34,1578,34,1581,34,1585,34,1588,34,1593,34,1600,34,1605,34,1608,34,1612,34,1615,34,1620,34,1627,34,1632,34,1635,34,1638,34,1641,34,1646,34,1653,34,1659,34,1663],{"viewBox":1519,"role":28,"ariaLabelledBy":1520,"xmlns":32,"style":797},"4 0 752 142",[1521,1522],"tl-flow-t","tl-flow-d",[36,1524,1525],{"id":1521},"Trendline on the chart, numbers in the sheet",[40,1527,1528],{"id":1522},"Build the line chart with smoothing off, attach a trendline of the right type with forward periods, style it as a dashed annotation, then compute the same fit in Python and write slope, intercept and R squared into cells so the trend can be quoted and checked.",[44,1530],{"x":46,"y":47,"width":806,"height":1531,"fill":50},"142",[44,1533],{"x":810,"y":811,"width":1534,"height":1535,"rx":1536,"fill":57,"stroke":58,"style":182},"115.2","110.5","12",[1538,1539,1541],"g",{"transform":1540},"translate(65.6,37.8) scale(1.000)",[172,1542],{"d":1543,"fill":175,"stroke":1544,"style":1545},"M4 20h16 M4 20V4 M6 16l4-5 4 3 6-7","var(--brand-strong,#4338ca)","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[61,1547,1551],{"x":1548,"y":1549,"style":1550},"77.6","84.2","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Line chart",[61,1553,1555],{"x":1548,"y":1554,"style":125},"103.8","smooth = False",[77,1557],{"x1":1558,"y1":1559,"x2":1560,"y2":1559,"stroke":58,"style":182},"140.2","71.2","162.2",[1562,1563],"polygon",{"points":1564,"fill":1565},"166.2,71.2 157.2,76.2 157.2,66.2","#5b5cf0",[44,1567],{"x":1568,"y":811,"width":1534,"height":1535,"rx":1536,"fill":57,"stroke":58,"style":182},"171.2",[1538,1570,1572],{"transform":1571},"translate(216.8,37.8) scale(1.000)",[172,1573],{"d":1574,"fill":175,"stroke":1544,"style":1545},"M4 20h16 M7 17v-5 M12 17V7 M17 17v-8",[61,1576,691],{"x":1577,"y":1549,"style":1550},"228.8",[61,1579,1580],{"x":1577,"y":1554,"style":125},"type, forward",[77,1582],{"x1":1583,"y1":1559,"x2":1584,"y2":1559,"stroke":58,"style":182},"291.4","313.4",[1562,1586],{"points":1587,"fill":1565},"317.4,71.2 308.4,76.2 308.4,66.2",[44,1589],{"x":1590,"y":811,"width":1534,"height":1535,"rx":1536,"fill":1591,"stroke":1592,"style":182},"322.4","#fee8f2","var(--accent,#f43f8f)",[1538,1594,1596],{"transform":1595},"translate(368.0,37.8) scale(1.000)",[172,1597],{"d":1598,"fill":175,"stroke":1599,"style":1545},"M12 9a3 3 0 1 0 .01 0z M12 2.5v3 M12 18.5v3 M2.5 12h3 M18.5 12h3 M5.3 5.3l2.1 2.1 M16.6 16.6l2.1 2.1 M5.3 18.7l2.1-2.1 M16.6 7.4l2.1-2.1","var(--accent-ink,#be185d)",[61,1601,1604],{"x":1602,"y":1549,"style":1603},"380.0","font-size:13.5px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","Style",[61,1606,1607],{"x":1602,"y":1554,"style":125},"dashed red",[77,1609],{"x1":1610,"y1":1559,"x2":1611,"y2":1559,"stroke":58,"style":182},"442.6","464.6",[1562,1613],{"points":1614,"fill":1565},"468.6,71.2 459.6,76.2 459.6,66.2",[44,1616],{"x":1617,"y":811,"width":1534,"height":1535,"rx":1536,"fill":1618,"stroke":1619,"style":182},"473.6","#d9f4f1","var(--teal,#0f9488)",[1538,1621,1623],{"transform":1622},"translate(519.2,37.8) scale(1.000)",[172,1624],{"d":1625,"fill":175,"stroke":1626,"style":1545},"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","var(--teal-ink,#0b6157)",[61,1628,1631],{"x":1629,"y":1549,"style":1630},"531.2","font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Fit in Python",[61,1633,1634],{"x":1629,"y":1554,"style":125},"numpy.polyfit",[77,1636],{"x1":161,"y1":1559,"x2":1637,"y2":1559,"stroke":58,"style":182},"615.8",[1562,1639],{"points":1640,"fill":1565},"619.8,71.2 610.8,76.2 610.8,66.2",[44,1642],{"x":1643,"y":811,"width":1534,"height":1535,"rx":1536,"fill":1644,"stroke":1645,"style":182},"624.8","#fdefd8","var(--gold,#b4740a)",[1538,1647,1649],{"transform":1648},"translate(670.4,29.0) scale(1.000)",[172,1650],{"d":1651,"fill":175,"stroke":1652,"style":1545},"M5 9h14 M4 15h14 M10 4l-2 16 M16 4l-2 16","var(--gold-ink,#7a4e06)",[61,1654,1658],{"x":1655,"y":1656,"style":1657},"682.4","75.5","font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","Numbers in",[61,1660,1662],{"x":1655,"y":1661,"style":1657},"93.0","cells",[61,1664,1666],{"x":1655,"y":1665,"style":125},"112.5","SLOPE, RSQ",[255,1668,1670],{"id":1669},"the-same-chart-with-xlsxwriter","The same chart with XlsxWriter",[10,1672,1673],{},"If the report is written with XlsxWriter rather than openpyxl, the trendline is an option of the series, with the same choices under slightly different names:",[260,1675,1677],{"className":292,"code":1676,"language":294,"meta":265,"style":265},"import xlsxwriter\n\nbook = xlsxwriter.Workbook(\"trend_xw.xlsx\")\nsheet = book.add_worksheet(\"Orders\")\nsheet.write_row(\"A1\", [\"Month\", \"Orders\"])\nfor i, value in enumerate(orders, start=1):\n    sheet.write_row(i, 0, [f\"M{i:02d}\", value])\nxw_chart = book.add_chart({\"type\": \"line\"})\nxw_chart.add_series({\n    \"name\": \"Orders\", \"categories\": [\"Orders\", 1, 0, 12, 0], \"values\": [\"Orders\", 1, 1, 12, 1],\n    \"smooth\": False,\n    \"trendline\": {\"type\": \"linear\", \"forward\": 3, \"display_equation\": True,\n                  \"display_r_squared\": True, \"name\": \"Linear trend\",\n                  \"line\": {\"color\": \"#B91C1C\", \"dash_type\": \"dash\", \"width\": 1.5}},\n})\nsheet.insert_chart(\"D2\", xw_chart)\nbook.close()\nprint(\"written\")\n",[267,1678,1679,1686,1690,1705,1719,1738,1758,1783,1805,1810,1874,1885,1919,1940,1977,1981,1991,1996],{"__ignoreMap":265},[270,1680,1681,1683],{"class":77,"line":272},[270,1682,309],{"class":301},[270,1684,1685],{"class":305}," xlsxwriter\n",[270,1687,1688],{"class":77,"line":315},[270,1689,345],{"emptyLinePlaceholder":344},[270,1691,1692,1695,1697,1700,1703],{"class":77,"line":328},[270,1693,1694],{"class":305},"book ",[270,1696,354],{"class":301},[270,1698,1699],{"class":305}," xlsxwriter.Workbook(",[270,1701,1702],{"class":279},"\"trend_xw.xlsx\"",[270,1704,619],{"class":305},[270,1706,1707,1710,1712,1715,1717],{"class":77,"line":341},[270,1708,1709],{"class":305},"sheet ",[270,1711,354],{"class":301},[270,1713,1714],{"class":305}," book.add_worksheet(",[270,1716,466],{"class":279},[270,1718,619],{"class":305},[270,1720,1721,1724,1727,1730,1732,1734,1736],{"class":77,"line":348},[270,1722,1723],{"class":305},"sheet.write_row(",[270,1725,1726],{"class":279},"\"A1\"",[270,1728,1729],{"class":305},", [",[270,1731,461],{"class":279},[270,1733,364],{"class":305},[270,1735,466],{"class":279},[270,1737,469],{"class":305},[270,1739,1740,1742,1744,1746,1748,1750,1752,1754,1756],{"class":77,"line":422},[270,1741,475],{"class":301},[270,1743,478],{"class":305},[270,1745,481],{"class":301},[270,1747,484],{"class":360},[270,1749,487],{"class":305},[270,1751,491],{"class":490},[270,1753,354],{"class":301},[270,1755,496],{"class":360},[270,1757,499],{"class":305},[270,1759,1760,1763,1765,1767,1769,1771,1773,1775,1777,1779,1781],{"class":77,"line":433},[270,1761,1762],{"class":305},"    sheet.write_row(i, ",[270,1764,47],{"class":360},[270,1766,1729],{"class":305},[270,1768,508],{"class":301},[270,1770,511],{"class":279},[270,1772,515],{"class":514},[270,1774,518],{"class":305},[270,1776,521],{"class":301},[270,1778,524],{"class":514},[270,1780,527],{"class":279},[270,1782,530],{"class":305},[270,1784,1785,1788,1790,1793,1796,1799,1802],{"class":77,"line":444},[270,1786,1787],{"class":305},"xw_chart ",[270,1789,354],{"class":301},[270,1791,1792],{"class":305}," book.add_chart({",[270,1794,1795],{"class":279},"\"type\"",[270,1797,1798],{"class":305},": ",[270,1800,1801],{"class":279},"\"line\"",[270,1803,1804],{"class":305},"})\n",[270,1806,1807],{"class":77,"line":455},[270,1808,1809],{"class":305},"xw_chart.add_series({\n",[270,1811,1812,1815,1817,1819,1821,1824,1827,1829,1831,1833,1835,1837,1839,1841,1843,1845,1848,1851,1853,1855,1857,1859,1861,1863,1865,1867,1869,1871],{"class":77,"line":472},[270,1813,1814],{"class":279},"    \"name\"",[270,1816,1798],{"class":305},[270,1818,466],{"class":279},[270,1820,364],{"class":305},[270,1822,1823],{"class":279},"\"categories\"",[270,1825,1826],{"class":305},": [",[270,1828,466],{"class":279},[270,1830,364],{"class":305},[270,1832,496],{"class":360},[270,1834,364],{"class":305},[270,1836,47],{"class":360},[270,1838,364],{"class":305},[270,1840,1536],{"class":360},[270,1842,364],{"class":305},[270,1844,47],{"class":360},[270,1846,1847],{"class":305},"], ",[270,1849,1850],{"class":279},"\"values\"",[270,1852,1826],{"class":305},[270,1854,466],{"class":279},[270,1856,364],{"class":305},[270,1858,496],{"class":360},[270,1860,364],{"class":305},[270,1862,496],{"class":360},[270,1864,364],{"class":305},[270,1866,1536],{"class":360},[270,1868,364],{"class":305},[270,1870,496],{"class":360},[270,1872,1873],{"class":305},"],\n",[270,1875,1876,1879,1881,1883],{"class":77,"line":502},[270,1877,1878],{"class":279},"    \"smooth\"",[270,1880,1798],{"class":305},[270,1882,1174],{"class":360},[270,1884,1164],{"class":305},[270,1886,1887,1890,1893,1895,1897,1899,1901,1904,1906,1908,1910,1913,1915,1917],{"class":77,"line":533},[270,1888,1889],{"class":279},"    \"trendline\"",[270,1891,1892],{"class":305},": {",[270,1894,1795],{"class":279},[270,1896,1798],{"class":305},[270,1898,727],{"class":279},[270,1900,364],{"class":305},[270,1902,1903],{"class":279},"\"forward\"",[270,1905,1798],{"class":305},[270,1907,56],{"class":360},[270,1909,364],{"class":305},[270,1911,1912],{"class":279},"\"display_equation\"",[270,1914,1798],{"class":305},[270,1916,616],{"class":360},[270,1918,1164],{"class":305},[270,1920,1921,1924,1926,1928,1930,1933,1935,1938],{"class":77,"line":538},[270,1922,1923],{"class":279},"                  \"display_r_squared\"",[270,1925,1798],{"class":305},[270,1927,616],{"class":360},[270,1929,364],{"class":305},[270,1931,1932],{"class":279},"\"name\"",[270,1934,1798],{"class":305},[270,1936,1937],{"class":279},"\"Linear trend\"",[270,1939,1164],{"class":305},[270,1941,1942,1945,1947,1950,1952,1955,1957,1960,1962,1964,1966,1969,1971,1974],{"class":77,"line":549},[270,1943,1944],{"class":279},"                  \"line\"",[270,1946,1892],{"class":305},[270,1948,1949],{"class":279},"\"color\"",[270,1951,1798],{"class":305},[270,1953,1954],{"class":279},"\"#B91C1C\"",[270,1956,364],{"class":305},[270,1958,1959],{"class":279},"\"dash_type\"",[270,1961,1798],{"class":305},[270,1963,996],{"class":279},[270,1965,364],{"class":305},[270,1967,1968],{"class":279},"\"width\"",[270,1970,1798],{"class":305},[270,1972,1973],{"class":360},"1.5",[270,1975,1976],{"class":305},"}},\n",[270,1978,1979],{"class":77,"line":564},[270,1980,1804],{"class":305},[270,1982,1983,1986,1988],{"class":77,"line":575},[270,1984,1985],{"class":305},"sheet.insert_chart(",[270,1987,771],{"class":279},[270,1989,1990],{"class":305},", xw_chart)\n",[270,1992,1993],{"class":77,"line":622},[270,1994,1995],{"class":305},"book.close()\n",[270,1997,1998,2000,2002,2005],{"class":77,"line":653},[270,1999,1223],{"class":360},[270,2001,1382],{"class":305},[270,2003,2004],{"class":279},"\"written\"",[270,2006,619],{"class":305},[10,2008,2009,2010,2013,2014,2017],{},"XlsxWriter takes colours with a ",[267,2011,2012],{},"#"," and widths in points, and a moving average is ",[267,2015,2016],{},"{\"type\": \"moving_average\", \"period\": 3}",". Because XlsxWriter builds new files only, use it when the whole report is generated; use openpyxl when adding a chart to an existing workbook.",[255,2019,2021],{"id":2020},"common-pitfalls","Common pitfalls",[2023,2024,2025,2033,2039,2045,2054],"ul",{},[2026,2027,2028,2032],"li",{},[2029,2030,2031],"strong",{},"Trendlines on stacked or percent charts."," Excel does not allow them on stacked series; attach the trend to an unstacked line series instead.",[2026,2034,2035,2038],{},[2029,2036,2037],{},"Exponential fits with zeros."," An exponential trend cannot be fitted to data containing zero or negative values — Excel does not offer it for such data. Use linear or a moving average.",[2026,2040,2041,2044],{},[2029,2042,2043],{},"Reading R² as proof."," A high R² on a time series mostly says the data trends; it does not say why, or that the trend will continue. Present the trend as a description of the past.",[2026,2046,2047,2050,2051,2053],{},[2029,2048,2049],{},"Forecasting too far."," A trend fitted on twelve points says little about month thirty. Keep ",[267,2052,703],{}," to a few periods and say it is an extrapolation.",[2026,2055,2056,2059],{},[2029,2057,2058],{},"Dates as categories."," If the categories are real dates, Excel may use the date serial numbers as x values, which changes the equation's intercept. Reproduce that in Python, or use period numbers.",[255,2061,2063],{"id":2062},"conclusion","Conclusion",[10,2065,2066,2067,2070,2071,2073,2074,2077,2078,2080,2081,2084,2085,2087,2088,2090,2091,696,2093,2095,2096,2098,2099,2102,2103,364,2106,696,2109,2112],{},"Add a trendline by assigning ",[267,2068,2069],{},"Trendline(trendlineType=…)"," to a chart series: ",[267,2072,841],{}," for steady change, ",[267,2075,2076],{},"movingAvg"," with a ",[267,2079,1045],{}," for smoothing, ",[267,2082,2083],{},"poly"," with an ",[267,2086,1049],{}," for one bend, ",[267,2089,895],{}," for compounding growth. Show the equation and R² with ",[267,2092,695],{},[267,2094,699],{},", extend with ",[267,2097,703],{},", style it as a dashed annotation, and set ",[267,2100,2101],{},"smooth=False"," on the series. Put the same fit into cells with ",[267,2104,2105],{},"SLOPE",[267,2107,2108],{},"INTERCEPT",[267,2110,2111],{},"RSQ"," so the trend can be quoted, checked and used.",[255,2114,2116],{"id":2115},"frequently-asked-questions","Frequently asked questions",[10,2118,2119,2122],{},[2029,2120,2121],{},"How do I add a trendline to an openpyxl chart?","\nAssign a Trendline to the series, for example series.trendline = Trendline(trendlineType=\"linear\", dispEq=True, dispRSqr=True). Excel fits the line itself when the chart is drawn, so it follows the data if values change.",[10,2124,2125,2128],{},[2029,2126,2127],{},"How do I extend a trendline into the future?","\nSet forward to the number of periods to project, such as forward=3. The line continues past the last data point; on a line chart with category labels the extra periods are drawn without labels.",[10,2130,2131,2134],{},[2029,2132,2133],{},"Which x values does Excel use for a trendline on a line chart?","\nOn a line or column chart with text categories, Excel uses 1, 2, 3 and so on for the points. The equation therefore describes the value per period, which you can reproduce with numpy.polyfit over range(1, n + 1).",[10,2136,2137,2140],{},[2029,2138,2139],{},"Can I read the trendline equation from Python?","\nNot from the chart; Excel calculates it only when drawing. Compute the same fit in Python, or write SLOPE, INTERCEPT and RSQ formulas into cells so the figures are visible and usable in the sheet.",[255,2142,2144],{"id":2143},"related","Related",[2023,2146,2147,2153,2160,2167],{},[2026,2148,2149,2150,2152],{},"Up one level: ",[14,2151,17],{"href":16}," — charts written from Python.",[2026,2154,2155,2159],{},[14,2156,2158],{"href":2157},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-charts-in-excel-with-openpyxl\u002Fadd-line-chart-to-excel-report-with-python\u002F","Add a Line Chart to an Excel Report with Python"," — the chart the trend sits on.",[2026,2161,2162,2166],{},[14,2163,2165],{"href":2164},"\u002Fadvanced-data-transformation-and-cleaning\u002Fexcel-formula-equivalents-in-pandas\u002Frunning-totals-and-year-over-year-growth-in-pandas\u002F","Running Totals and Year-over-Year Growth in pandas"," — growth figures to go with the trend.",[2026,2168,2169,2173],{},[14,2170,2172],{"href":2171},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-charts-in-excel-with-openpyxl\u002Fcreate-a-stacked-column-chart-with-openpyxl\u002F","Create a Stacked Column Chart with openpyxl"," — where trendlines do not apply.",[2175,2176,2177],"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-wDw, html code.shiki .s-wDw{--shiki-default:#6A737D;--shiki-dark:#BDC4CC}",{"title":265,"searchDepth":315,"depth":315,"links":2179},[2180,2181,2182,2183,2184,2185,2186,2187,2188,2189],{"id":257,"depth":315,"text":258},{"id":684,"depth":315,"text":685},{"id":909,"depth":315,"text":910},{"id":1038,"depth":315,"text":1039},{"id":1256,"depth":315,"text":1257},{"id":1669,"depth":315,"text":1670},{"id":2020,"depth":315,"text":2021},{"id":2062,"depth":315,"text":2063},{"id":2115,"depth":315,"text":2116},{"id":2143,"depth":315,"text":2144},"2026-09-23","Add linear, moving-average, polynomial and exponential trendlines to Excel line and column charts with openpyxl — forecast periods ahead, show the equation and R², style the line, and put the same fitted numbers into cells with SLOPE, INTERCEPT and RSQ so the trend can be read by people and by code.","md",[2194,2196,2198,2200],{"q":2121,"a":2195},"Assign a Trendline to the series, for example series.trendline = Trendline(trendlineType=\"linear\", dispEq=True, dispRSqr=True). Excel fits the line itself when the chart is drawn, so it follows the data if values change.",{"q":2127,"a":2197},"Set forward to the number of periods to project, such as forward=3. The line continues past the last data point; on a line chart with category labels the extra periods are drawn without labels.",{"q":2133,"a":2199},"On a line or column chart with text categories, Excel uses 1, 2, 3 and so on for the points. The equation therefore describes the value per period, which you can reproduce with numpy.polyfit over range(1, n + 1).",{"q":2139,"a":2201},"Not from the chart; Excel calculates it only when drawing. Compute the same fit in Python, or write SLOPE, INTERCEPT and RSQ formulas into cells so the figures are visible and usable in the sheet.","add a trendline to an excel chart with python",null,{"breadcrumb":2205},[2206,2209,2212],{"name":2207,"item":2208},"Home","\u002F",{"name":2210,"item":2211},"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\u002Fcreating-charts-in-excel-with-openpyxl\u002Fadd-a-trendline-to-an-excel-chart-with-python",{"title":2215,"description":2216},"Add a Trendline to an Excel Chart with Python (openpyxl)","Excel chart trendlines from Python — openpyxl Trendline types, forward forecasting, dispEq and dispRSqr, dashed styling, moving averages, smooth=False for line series, matching numpy.polyfit, and SLOPE, INTERCEPT and RSQ in cells.","add-a-trendline-to-an-excel-chart-with-python","formatting-and-charting-excel-reports-with-python\u002Fcreating-charts-in-excel-with-openpyxl\u002Fadd-a-trendline-to-an-excel-chart-with-python\u002Findex",[2220,2221],"charts-and-images","openpyxl","how-to","HucCjlgZWOOAH4FeCVSjui8745_wiWL-5lEMTd7_xfE",[2225,2229],{"title":2226,"path":2227,"stem":2228,"children":-1},"Add a Data Table Below an Excel Chart","\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-charts-in-excel-with-openpyxl\u002Fadd-a-data-table-below-an-excel-chart","formatting-and-charting-excel-reports-with-python\u002Fcreating-charts-in-excel-with-openpyxl\u002Fadd-a-data-table-below-an-excel-chart\u002Findex",{"title":2230,"path":2231,"stem":2232,"children":-1},"Add Error Bars to an Excel Chart with openpyxl","\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-charts-in-excel-with-openpyxl\u002Fadd-error-bars-to-an-excel-chart-with-openpyxl","formatting-and-charting-excel-reports-with-python\u002Fcreating-charts-in-excel-with-openpyxl\u002Fadd-error-bars-to-an-excel-chart-with-openpyxl\u002Findex",[2234,2236],{"path":2235,"title":17},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-charts-in-excel-with-openpyxl",{"path":2237,"title":2210},"\u002Fformatting-and-charting-excel-reports-with-python",[],[2240,2243,2246,2249,2252,2255],{"path":2241,"title":2242,"kind":2222},"\u002Fautomating-reporting-workflows\u002Fbuilding-multi-sheet-excel-dashboards\u002Fbuild-a-dashboard-sheet-with-charts-from-multiple-tabs","Build a Dashboard Sheet with Charts from Multiple Tabs",{"path":2244,"title":2245,"kind":2222},"\u002Fautomating-reporting-workflows\u002Fbuilding-multi-sheet-excel-dashboards\u002Fbuild-a-rolling-12-month-chart-on-an-excel-dashboard","Build a Rolling 12-Month Chart on an Excel Dashboard",{"path":2247,"title":2248,"kind":2222},"\u002Fautomating-reporting-workflows\u002Fgenerating-excel-reports-from-templates\u002Fkeep-charts-and-images-when-filling-an-excel-template","Keep Charts and Images When Filling an Excel Template",{"path":2250,"title":2251,"kind":2222},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fadd-a-chart-to-an-excel-file-with-xlsxwriter","Add a Chart to an Excel File with xlsxwriter",{"path":2253,"title":2254,"kind":2222},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fadd-sparklines-to-an-excel-report-with-xlsxwriter","Add Sparklines to an Excel Report with xlsxwriter",{"path":2256,"title":2257,"kind":2222},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fbuild-a-waterfall-chart-in-excel-with-python","Build a Waterfall Chart in Excel with Python",1790972108860]