[{"data":1,"prerenderedAt":2478},["ShallowReactive",2],{"doc:\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fapply-a-colour-scale-per-row-or-per-column-with-openpyxl":3,"surround:\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fapply-a-colour-scale-per-row-or-per-column-with-openpyxl":2449,"ancestors:\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fapply-a-colour-scale-per-row-or-per-column-with-openpyxl":2458,"children:\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fapply-a-colour-scale-per-row-or-per-column-with-openpyxl":2463,"related:\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fapply-a-colour-scale-per-row-or-per-column-with-openpyxl":2464},{"id":4,"title":5,"body":6,"dateModified":2416,"datePublished":2416,"description":2417,"extension":2418,"faq":2419,"keyword":2428,"kind":2429,"meta":2430,"navigation":148,"path":2439,"seo":2440,"slug":2442,"stem":2443,"topics":2444,"type":2447,"__hash__":2448},"docs\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fapply-a-colour-scale-per-row-or-per-column-with-openpyxl\u002Findex.md","Apply a Colour Scale per Row or per Column with openpyxl",{"type":7,"value":8,"toc":2404},"minimark",[9,28,33,65,76,80,735,738,742,745,888,891,1001,1005,1012,1386,1393,1532,1796,1800,2269,2276,2280,2291,2295,2330,2334,2341,2345,2351,2357,2363,2369,2373,2400],[10,11,12,13,17,18,21,22,27],"p",{},"A colour scale is one of the quickest ways to make a table of numbers readable: low values red, high values green, everything in between shaded. Applied to a whole table, though, it compares every cell with every other cell. In a table of monthly sales by product, the best-selling product's months are all green and every smaller product's months are all red, so the chart tells you which products are big — which you knew — and hides what you wanted to see: each product's good and bad months. The fix is to give each ",[14,15,16],"em",{},"row"," its own colour scale, or each ",[14,19,20],{},"column",", depending on which comparison matters. This page shows the problem on a real table, applies per-row and per-column scales with openpyxl, compares min-max anchoring with percentiles, keeps the rule count under control on larger tables, and renders the result to check it. It belongs to ",[23,24,26],"a",{"href":25},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002F","Applying Conditional Formatting with openpyxl",".",[29,30,32],"h2",{"id":31},"prerequisites","Prerequisites",[34,35,40],"pre",{"className":36,"code":37,"language":38,"meta":39,"style":39},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install openpyxl pandas pillow\n","bash","",[41,42,43],"code",{"__ignoreMap":39},[44,45,48,52,56,59,62],"span",{"class":46,"line":47},"line",1,[44,49,51],{"class":50},"sMTad","pip",[44,53,55],{"class":54},"srMev"," install",[44,57,58],{"class":54}," openpyxl",[44,60,61],{"class":54}," pandas",[44,63,64],{"class":54}," pillow\n",[10,66,67,68,71,72,75],{},"LibreOffice (",[41,69,70],{},"soffice",") and ",[41,73,74],{},"pdftoppm"," render the sheets for the visual check. The data is twelve months of sales for five products whose sizes differ by a factor of more than fifty.",[29,77,79],{"id":78},"step-1-the-table-and-one-scale-over-everything","Step 1 — The table, and one scale over everything",[34,81,85],{"className":82,"code":83,"language":84,"meta":39,"style":39},"language-python shiki shiki-themes github-light github-dark-high-contrast","import numpy as np\nimport pandas as pd\nfrom openpyxl import Workbook\nfrom openpyxl.formatting.rule import ColorScaleRule\n\nmonths = pd.period_range(\"2025-10\", \"2026-09\", freq=\"M\").strftime(\"%b\")\nrng = np.random.default_rng(4)\nbase = {\"Bolts\": 52000, \"Nuts\": 18000, \"Washers\": 6500, \"Rivets\": 2400, \"Brackets\": 900}\nseason = 1 + 0.25 * np.sin(np.arange(12) \u002F 12 * 2 * np.pi)\nsales = pd.DataFrame({p: (b * season * rng.uniform(0.85, 1.15, 12)).round(-1) for p, b in base.items()}, index=months).T\n\ndef write_table(ws, df):\n    ws.append([\"Product\", *df.columns])\n    for name, row in df.iterrows():\n        ws.append([name, *row.tolist()])\n    for row in ws.iter_rows(min_row=2, min_col=2):\n        for c in row:\n            c.number_format = \"#,##0\"\n    ws.column_dimensions[\"A\"].width = 11\n    ws.page_setup.orientation = \"landscape\"                 # one printed page per sheet for the check\n    ws.sheet_properties.pageSetUpPr.fitToPage = True\n    ws.page_setup.fitToWidth, ws.page_setup.fitToHeight = 1, 1\n\nRED_YELLOW_GREEN = dict(start_type=\"min\", start_color=\"F8696B\", mid_type=\"percentile\", mid_value=50,\n                        mid_color=\"FFEB84\", end_type=\"max\", end_color=\"63BE7B\")\nwb = Workbook()\nwhole = wb.active\nwhole.title = \"One scale\"\nwrite_table(whole, sales)\nwhole.conditional_formatting.add(\"B2:M6\", ColorScaleRule(**RED_YELLOW_GREEN))\nprint(sales.iloc[:, :4].astype(int).to_string())\n","python",[41,86,87,103,116,130,143,150,197,214,277,322,387,392,405,421,435,446,479,493,504,521,536,547,562,567,623,656,667,678,689,695,715],{"__ignoreMap":39},[44,88,89,93,97,100],{"class":46,"line":47},[44,90,92],{"class":91},"s-kum","import",[44,94,96],{"class":95},"skGVy"," numpy ",[44,98,99],{"class":91},"as",[44,101,102],{"class":95}," np\n",[44,104,106,108,111,113],{"class":46,"line":105},2,[44,107,92],{"class":91},[44,109,110],{"class":95}," pandas ",[44,112,99],{"class":91},[44,114,115],{"class":95}," pd\n",[44,117,119,122,125,127],{"class":46,"line":118},3,[44,120,121],{"class":91},"from",[44,123,124],{"class":95}," openpyxl ",[44,126,92],{"class":91},[44,128,129],{"class":95}," Workbook\n",[44,131,133,135,138,140],{"class":46,"line":132},4,[44,134,121],{"class":91},[44,136,137],{"class":95}," openpyxl.formatting.rule ",[44,139,92],{"class":91},[44,141,142],{"class":95}," ColorScaleRule\n",[44,144,146],{"class":46,"line":145},5,[44,147,149],{"emptyLinePlaceholder":148},true,"\n",[44,151,153,156,159,162,165,168,171,173,177,179,182,185,188,192,194],{"class":46,"line":152},6,[44,154,155],{"class":95},"months ",[44,157,158],{"class":91},"=",[44,160,161],{"class":95}," pd.period_range(",[44,163,164],{"class":54},"\"2025-10\"",[44,166,167],{"class":95},", ",[44,169,170],{"class":54},"\"2026-09\"",[44,172,167],{"class":95},[44,174,176],{"class":175},"sa561","freq",[44,178,158],{"class":91},[44,180,181],{"class":54},"\"M\"",[44,183,184],{"class":95},").strftime(",[44,186,187],{"class":54},"\"",[44,189,191],{"class":190},"sSjpA","%b",[44,193,187],{"class":54},[44,195,196],{"class":95},")\n",[44,198,200,203,205,208,212],{"class":46,"line":199},7,[44,201,202],{"class":95},"rng ",[44,204,158],{"class":91},[44,206,207],{"class":95}," np.random.default_rng(",[44,209,211],{"class":210},"sP0c6","4",[44,213,196],{"class":95},[44,215,217,220,222,225,228,231,234,236,239,241,244,246,249,251,254,256,259,261,264,266,269,271,274],{"class":46,"line":216},8,[44,218,219],{"class":95},"base ",[44,221,158],{"class":91},[44,223,224],{"class":95}," {",[44,226,227],{"class":54},"\"Bolts\"",[44,229,230],{"class":95},": ",[44,232,233],{"class":210},"52000",[44,235,167],{"class":95},[44,237,238],{"class":54},"\"Nuts\"",[44,240,230],{"class":95},[44,242,243],{"class":210},"18000",[44,245,167],{"class":95},[44,247,248],{"class":54},"\"Washers\"",[44,250,230],{"class":95},[44,252,253],{"class":210},"6500",[44,255,167],{"class":95},[44,257,258],{"class":54},"\"Rivets\"",[44,260,230],{"class":95},[44,262,263],{"class":210},"2400",[44,265,167],{"class":95},[44,267,268],{"class":54},"\"Brackets\"",[44,270,230],{"class":95},[44,272,273],{"class":210},"900",[44,275,276],{"class":95},"}\n",[44,278,280,283,285,288,291,294,297,300,303,306,309,312,314,317,319],{"class":46,"line":279},9,[44,281,282],{"class":95},"season ",[44,284,158],{"class":91},[44,286,287],{"class":210}," 1",[44,289,290],{"class":91}," +",[44,292,293],{"class":210}," 0.25",[44,295,296],{"class":91}," *",[44,298,299],{"class":95}," np.sin(np.arange(",[44,301,302],{"class":210},"12",[44,304,305],{"class":95},") ",[44,307,308],{"class":91},"\u002F",[44,310,311],{"class":210}," 12",[44,313,296],{"class":91},[44,315,316],{"class":210}," 2",[44,318,296],{"class":91},[44,320,321],{"class":95}," np.pi)\n",[44,323,325,328,330,333,336,339,341,344,347,349,352,354,356,359,362,365,367,370,373,376,379,382,384],{"class":46,"line":324},10,[44,326,327],{"class":95},"sales ",[44,329,158],{"class":91},[44,331,332],{"class":95}," pd.DataFrame({p: (b ",[44,334,335],{"class":91},"*",[44,337,338],{"class":95}," season ",[44,340,335],{"class":91},[44,342,343],{"class":95}," rng.uniform(",[44,345,346],{"class":210},"0.85",[44,348,167],{"class":95},[44,350,351],{"class":210},"1.15",[44,353,167],{"class":95},[44,355,302],{"class":210},[44,357,358],{"class":95},")).round(",[44,360,361],{"class":91},"-",[44,363,364],{"class":210},"1",[44,366,305],{"class":95},[44,368,369],{"class":91},"for",[44,371,372],{"class":95}," p, b ",[44,374,375],{"class":91},"in",[44,377,378],{"class":95}," base.items()}, ",[44,380,381],{"class":175},"index",[44,383,158],{"class":91},[44,385,386],{"class":95},"months).T\n",[44,388,390],{"class":46,"line":389},11,[44,391,149],{"emptyLinePlaceholder":148},[44,393,395,398,402],{"class":46,"line":394},12,[44,396,397],{"class":91},"def",[44,399,401],{"class":400},"s_Opv"," write_table",[44,403,404],{"class":95},"(ws, df):\n",[44,406,408,411,414,416,418],{"class":46,"line":407},13,[44,409,410],{"class":95},"    ws.append([",[44,412,413],{"class":54},"\"Product\"",[44,415,167],{"class":95},[44,417,335],{"class":91},[44,419,420],{"class":95},"df.columns])\n",[44,422,424,427,430,432],{"class":46,"line":423},14,[44,425,426],{"class":91},"    for",[44,428,429],{"class":95}," name, row ",[44,431,375],{"class":91},[44,433,434],{"class":95}," df.iterrows():\n",[44,436,438,441,443],{"class":46,"line":437},15,[44,439,440],{"class":95},"        ws.append([name, ",[44,442,335],{"class":91},[44,444,445],{"class":95},"row.tolist()])\n",[44,447,449,451,454,456,459,462,464,467,469,472,474,476],{"class":46,"line":448},16,[44,450,426],{"class":91},[44,452,453],{"class":95}," row ",[44,455,375],{"class":91},[44,457,458],{"class":95}," ws.iter_rows(",[44,460,461],{"class":175},"min_row",[44,463,158],{"class":91},[44,465,466],{"class":210},"2",[44,468,167],{"class":95},[44,470,471],{"class":175},"min_col",[44,473,158],{"class":91},[44,475,466],{"class":210},[44,477,478],{"class":95},"):\n",[44,480,482,485,488,490],{"class":46,"line":481},17,[44,483,484],{"class":91},"        for",[44,486,487],{"class":95}," c ",[44,489,375],{"class":91},[44,491,492],{"class":95}," row:\n",[44,494,496,499,501],{"class":46,"line":495},18,[44,497,498],{"class":95},"            c.number_format ",[44,500,158],{"class":91},[44,502,503],{"class":54}," \"#,##0\"\n",[44,505,507,510,513,516,518],{"class":46,"line":506},19,[44,508,509],{"class":95},"    ws.column_dimensions[",[44,511,512],{"class":54},"\"A\"",[44,514,515],{"class":95},"].width ",[44,517,158],{"class":91},[44,519,520],{"class":210}," 11\n",[44,522,524,527,529,532],{"class":46,"line":523},20,[44,525,526],{"class":95},"    ws.page_setup.orientation ",[44,528,158],{"class":91},[44,530,531],{"class":54}," \"landscape\"",[44,533,535],{"class":534},"s-wDw","                 # one printed page per sheet for the check\n",[44,537,539,542,544],{"class":46,"line":538},21,[44,540,541],{"class":95},"    ws.sheet_properties.pageSetUpPr.fitToPage ",[44,543,158],{"class":91},[44,545,546],{"class":210}," True\n",[44,548,550,553,555,557,559],{"class":46,"line":549},22,[44,551,552],{"class":95},"    ws.page_setup.fitToWidth, ws.page_setup.fitToHeight ",[44,554,158],{"class":91},[44,556,287],{"class":210},[44,558,167],{"class":95},[44,560,561],{"class":210},"1\n",[44,563,565],{"class":46,"line":564},23,[44,566,149],{"emptyLinePlaceholder":148},[44,568,570,573,576,579,582,585,587,590,592,595,597,600,602,605,607,610,612,615,617,620],{"class":46,"line":569},24,[44,571,572],{"class":210},"RED_YELLOW_GREEN",[44,574,575],{"class":91}," =",[44,577,578],{"class":210}," dict",[44,580,581],{"class":95},"(",[44,583,584],{"class":175},"start_type",[44,586,158],{"class":91},[44,588,589],{"class":54},"\"min\"",[44,591,167],{"class":95},[44,593,594],{"class":175},"start_color",[44,596,158],{"class":91},[44,598,599],{"class":54},"\"F8696B\"",[44,601,167],{"class":95},[44,603,604],{"class":175},"mid_type",[44,606,158],{"class":91},[44,608,609],{"class":54},"\"percentile\"",[44,611,167],{"class":95},[44,613,614],{"class":175},"mid_value",[44,616,158],{"class":91},[44,618,619],{"class":210},"50",[44,621,622],{"class":95},",\n",[44,624,626,629,631,634,636,639,641,644,646,649,651,654],{"class":46,"line":625},25,[44,627,628],{"class":175},"                        mid_color",[44,630,158],{"class":91},[44,632,633],{"class":54},"\"FFEB84\"",[44,635,167],{"class":95},[44,637,638],{"class":175},"end_type",[44,640,158],{"class":91},[44,642,643],{"class":54},"\"max\"",[44,645,167],{"class":95},[44,647,648],{"class":175},"end_color",[44,650,158],{"class":91},[44,652,653],{"class":54},"\"63BE7B\"",[44,655,196],{"class":95},[44,657,659,662,664],{"class":46,"line":658},26,[44,660,661],{"class":95},"wb ",[44,663,158],{"class":91},[44,665,666],{"class":95}," Workbook()\n",[44,668,670,673,675],{"class":46,"line":669},27,[44,671,672],{"class":95},"whole ",[44,674,158],{"class":91},[44,676,677],{"class":95}," wb.active\n",[44,679,681,684,686],{"class":46,"line":680},28,[44,682,683],{"class":95},"whole.title ",[44,685,158],{"class":91},[44,687,688],{"class":54}," \"One scale\"\n",[44,690,692],{"class":46,"line":691},29,[44,693,694],{"class":95},"write_table(whole, sales)\n",[44,696,698,701,704,707,710,712],{"class":46,"line":697},30,[44,699,700],{"class":95},"whole.conditional_formatting.add(",[44,702,703],{"class":54},"\"B2:M6\"",[44,705,706],{"class":95},", ColorScaleRule(",[44,708,709],{"class":91},"**",[44,711,572],{"class":210},[44,713,714],{"class":95},"))\n",[44,716,718,721,724,726,729,732],{"class":46,"line":717},31,[44,719,720],{"class":210},"print",[44,722,723],{"class":95},"(sales.iloc[:, :",[44,725,211],{"class":210},[44,727,728],{"class":95},"].astype(",[44,730,731],{"class":210},"int",[44,733,734],{"class":95},").to_string())\n",[10,736,737],{},"With one rule over B2:M6, the bottom of the scale is the smallest number in the whole table — a Brackets month of a few hundred — and the top is the best Bolts month. Every Bolts cell lands near green, and Rivets and Brackets are red all year, however their months compare with each other. The colour encodes product size, not performance — the rendered sheet in Step 4 shows Bolts in green and the two smallest products in solid red across all twelve months.",[29,739,741],{"id":740},"step-2-one-scale-per-row","Step 2 — One scale per row",[10,743,744],{},"Give every row its own rule, so each product is compared only with its own months:",[34,746,748],{"className":82,"code":747,"language":84,"meta":39,"style":39},"per_row = wb.create_sheet(\"Per row\")\nwrite_table(per_row, sales)\nlast_col = per_row.cell(1, per_row.max_column).column_letter\nfor r in range(2, per_row.max_row + 1):\n    per_row.conditional_formatting.add(f\"B{r}:{last_col}{r}\", ColorScaleRule(**RED_YELLOW_GREEN))\nprint(\"rules on 'Per row':\", sum(len(cf.rules) for cf in per_row.conditional_formatting))\n",[41,749,750,765,770,785,811,856],{"__ignoreMap":39},[44,751,752,755,757,760,763],{"class":46,"line":47},[44,753,754],{"class":95},"per_row ",[44,756,158],{"class":91},[44,758,759],{"class":95}," wb.create_sheet(",[44,761,762],{"class":54},"\"Per row\"",[44,764,196],{"class":95},[44,766,767],{"class":46,"line":105},[44,768,769],{"class":95},"write_table(per_row, sales)\n",[44,771,772,775,777,780,782],{"class":46,"line":118},[44,773,774],{"class":95},"last_col ",[44,776,158],{"class":91},[44,778,779],{"class":95}," per_row.cell(",[44,781,364],{"class":210},[44,783,784],{"class":95},", per_row.max_column).column_letter\n",[44,786,787,789,792,794,797,799,801,804,807,809],{"class":46,"line":132},[44,788,369],{"class":91},[44,790,791],{"class":95}," r ",[44,793,375],{"class":91},[44,795,796],{"class":210}," range",[44,798,581],{"class":95},[44,800,466],{"class":210},[44,802,803],{"class":95},", per_row.max_row ",[44,805,806],{"class":91},"+",[44,808,287],{"class":210},[44,810,478],{"class":95},[44,812,813,816,819,822,825,828,831,834,836,839,842,844,846,848,850,852,854],{"class":46,"line":145},[44,814,815],{"class":95},"    per_row.conditional_formatting.add(",[44,817,818],{"class":91},"f",[44,820,821],{"class":54},"\"B",[44,823,824],{"class":190},"{",[44,826,827],{"class":95},"r",[44,829,830],{"class":190},"}",[44,832,833],{"class":54},":",[44,835,824],{"class":190},[44,837,838],{"class":95},"last_col",[44,840,841],{"class":190},"}{",[44,843,827],{"class":95},[44,845,830],{"class":190},[44,847,187],{"class":54},[44,849,706],{"class":95},[44,851,709],{"class":91},[44,853,572],{"class":210},[44,855,714],{"class":95},[44,857,858,860,862,865,867,870,872,875,878,880,883,885],{"class":46,"line":152},[44,859,720],{"class":210},[44,861,581],{"class":95},[44,863,864],{"class":54},"\"rules on 'Per row':\"",[44,866,167],{"class":95},[44,868,869],{"class":210},"sum",[44,871,581],{"class":95},[44,873,874],{"class":210},"len",[44,876,877],{"class":95},"(cf.rules) ",[44,879,369],{"class":91},[44,881,882],{"class":95}," cf ",[44,884,375],{"class":91},[44,886,887],{"class":95}," per_row.conditional_formatting))\n",[10,889,890],{},"Now each row runs from red in its own weakest month to green in its strongest, and the seasonal pattern — strongest from December to February, weakest from May to August — shows up across all five products, including the small ones that were solid red before. The rules are identical apart from their range; openpyxl stores each as a separate entry, so five rows mean five rules.",[892,893,901,902,901,906,901,910,901,917,901,927,901,938,901,945,901,951,901,956,901,960,901,964,901,968,901,973,901,980,901,985,901,989,901,992,901,995,901,998],"svg",{"viewBox":894,"role":895,"ariaLabelledBy":896,"xmlns":899,"style":900},"4 0 752 233","img",[897,898],"cs-row-t","cs-row-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  ",[903,904,905],"title",{"id":897},"One scale for the table or one per row",[907,908,909],"desc",{"id":898},"A single colour scale over the whole table compares every cell with every other, so large products are green and small products red all year. A colour scale per row compares each product only with its own months, so each row shows its best and worst months.",[911,912],"rect",{"x":211,"y":913,"width":914,"height":915,"fill":916},"0","752","233","#ffffff",[911,918],{"x":919,"y":920,"width":921,"height":922,"rx":923,"fill":924,"stroke":925,"style":926},"20.0","16.0","351.0","201.0","14","#fdefd8","var(--gold,#b4740a)","stroke-width:2px",[928,929,931],"g",{"transform":930},"translate(182.5,29.0) scale(1.083)",[932,933],"path",{"d":934,"fill":935,"stroke":936,"style":937},"M3 5h18v14H3z M3 10h18 M3 15h18 M9 5v14","none","var(--gold-ink,#7a4e06)","stroke-width:1.66px;stroke-linecap:round;stroke-linejoin:round",[939,940,944],"text",{"x":941,"y":942,"style":943},"195.5","78.0","font-size:14px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","One scale over B2:M6",[46,946],{"x1":947,"y1":948,"x2":949,"y2":948,"stroke":925,"style":950},"36.0","91.0","355.0","stroke-width:1px",[939,952,955],{"x":941,"y":953,"style":954},"111.0","font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","min and max of whole table",[939,957,959],{"x":941,"y":958,"style":954},"137.0","big products all green",[939,961,963],{"x":941,"y":962,"style":954},"163.0","small products all red",[939,965,967],{"x":941,"y":966,"style":954},"189.0","shows size not pattern",[911,969],{"x":970,"y":920,"width":921,"height":922,"rx":923,"fill":971,"stroke":972,"style":926},"389.0","#d9f4f1","var(--teal,#0f9488)",[928,974,976],{"transform":975},"translate(551.5,29.0) scale(1.083)",[932,977],{"d":978,"fill":935,"stroke":979,"style":937},"M4 20h16 M7 17v-5 M12 17V7 M17 17v-8","var(--teal-ink,#0b6157)",[939,981,984],{"x":982,"y":942,"style":983},"564.5","font-size:14px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","One scale per row",[46,986],{"x1":987,"y1":948,"x2":988,"y2":948,"stroke":972,"style":950},"405.0","724.0",[939,990,991],{"x":982,"y":953,"style":954},"min and max of each row",[939,993,994],{"x":982,"y":958,"style":954},"every row has red and green",[939,996,997],{"x":982,"y":962,"style":954},"seasonality visible",[939,999,1000],{"x":982,"y":966,"style":954},"5 rows → 5 rules",[29,1002,1004],{"id":1003},"step-3-per-column-and-percentiles-instead-of-min-and-max","Step 3 — Per column, and percentiles instead of min and max",[10,1006,1007,1008,1011],{},"When the comparison that matters is ",[14,1009,1010],{},"between products within a month",", scale each column instead:",[34,1013,1015],{"className":82,"code":1014,"language":84,"meta":39,"style":39},"per_col = wb.create_sheet(\"Per column\")\nwrite_table(per_col, sales.div(sales.sum()))           # share of each month's sales\nfor c in range(2, per_col.max_column + 1):\n    letter = per_col.cell(1, c).column_letter\n    per_col.conditional_formatting.add(f\"{letter}2:{letter}{per_col.max_row}\", ColorScaleRule(**RED_YELLOW_GREEN))\nfor row in per_col.iter_rows(min_row=2, min_col=2):\n    for cell in row:\n        cell.number_format = \"0.0%\"\n\nPERCENTILE = dict(start_type=\"percentile\", start_value=10, start_color=\"F8696B\", mid_type=\"percentile\", mid_value=50,\n                  mid_color=\"FFEB84\", end_type=\"percentile\", end_value=90, end_color=\"63BE7B\")\nrobust = wb.create_sheet(\"Per row, percentiles\")\nwrite_table(robust, sales.assign(**{\"Dec\": sales[\"Dec\"].where(sales.index != \"Nuts\", sales.loc[\"Nuts\", \"Dec\"] * 4)}))\nfor r in range(2, robust.max_row + 1):\n    robust.conditional_formatting.add(f\"B{r}:M{r}\", ColorScaleRule(**PERCENTILE))\nwb.save(\"colour_scales.xlsx\")\n",[41,1016,1017,1031,1039,1062,1077,1117,1144,1155,1165,1169,1222,1259,1273,1319,1342,1376],{"__ignoreMap":39},[44,1018,1019,1022,1024,1026,1029],{"class":46,"line":47},[44,1020,1021],{"class":95},"per_col ",[44,1023,158],{"class":91},[44,1025,759],{"class":95},[44,1027,1028],{"class":54},"\"Per column\"",[44,1030,196],{"class":95},[44,1032,1033,1036],{"class":46,"line":105},[44,1034,1035],{"class":95},"write_table(per_col, sales.div(sales.sum()))           ",[44,1037,1038],{"class":534},"# share of each month's sales\n",[44,1040,1041,1043,1045,1047,1049,1051,1053,1056,1058,1060],{"class":46,"line":118},[44,1042,369],{"class":91},[44,1044,487],{"class":95},[44,1046,375],{"class":91},[44,1048,796],{"class":210},[44,1050,581],{"class":95},[44,1052,466],{"class":210},[44,1054,1055],{"class":95},", per_col.max_column ",[44,1057,806],{"class":91},[44,1059,287],{"class":210},[44,1061,478],{"class":95},[44,1063,1064,1067,1069,1072,1074],{"class":46,"line":132},[44,1065,1066],{"class":95},"    letter ",[44,1068,158],{"class":91},[44,1070,1071],{"class":95}," per_col.cell(",[44,1073,364],{"class":210},[44,1075,1076],{"class":95},", c).column_letter\n",[44,1078,1079,1082,1084,1086,1088,1091,1093,1096,1098,1100,1102,1105,1107,1109,1111,1113,1115],{"class":46,"line":145},[44,1080,1081],{"class":95},"    per_col.conditional_formatting.add(",[44,1083,818],{"class":91},[44,1085,187],{"class":54},[44,1087,824],{"class":190},[44,1089,1090],{"class":95},"letter",[44,1092,830],{"class":190},[44,1094,1095],{"class":54},"2:",[44,1097,824],{"class":190},[44,1099,1090],{"class":95},[44,1101,841],{"class":190},[44,1103,1104],{"class":95},"per_col.max_row",[44,1106,830],{"class":190},[44,1108,187],{"class":54},[44,1110,706],{"class":95},[44,1112,709],{"class":91},[44,1114,572],{"class":210},[44,1116,714],{"class":95},[44,1118,1119,1121,1123,1125,1128,1130,1132,1134,1136,1138,1140,1142],{"class":46,"line":152},[44,1120,369],{"class":91},[44,1122,453],{"class":95},[44,1124,375],{"class":91},[44,1126,1127],{"class":95}," per_col.iter_rows(",[44,1129,461],{"class":175},[44,1131,158],{"class":91},[44,1133,466],{"class":210},[44,1135,167],{"class":95},[44,1137,471],{"class":175},[44,1139,158],{"class":91},[44,1141,466],{"class":210},[44,1143,478],{"class":95},[44,1145,1146,1148,1151,1153],{"class":46,"line":199},[44,1147,426],{"class":91},[44,1149,1150],{"class":95}," cell ",[44,1152,375],{"class":91},[44,1154,492],{"class":95},[44,1156,1157,1160,1162],{"class":46,"line":216},[44,1158,1159],{"class":95},"        cell.number_format ",[44,1161,158],{"class":91},[44,1163,1164],{"class":54}," \"0.0%\"\n",[44,1166,1167],{"class":46,"line":279},[44,1168,149],{"emptyLinePlaceholder":148},[44,1170,1171,1174,1176,1178,1180,1182,1184,1186,1188,1191,1193,1196,1198,1200,1202,1204,1206,1208,1210,1212,1214,1216,1218,1220],{"class":46,"line":324},[44,1172,1173],{"class":210},"PERCENTILE",[44,1175,575],{"class":91},[44,1177,578],{"class":210},[44,1179,581],{"class":95},[44,1181,584],{"class":175},[44,1183,158],{"class":91},[44,1185,609],{"class":54},[44,1187,167],{"class":95},[44,1189,1190],{"class":175},"start_value",[44,1192,158],{"class":91},[44,1194,1195],{"class":210},"10",[44,1197,167],{"class":95},[44,1199,594],{"class":175},[44,1201,158],{"class":91},[44,1203,599],{"class":54},[44,1205,167],{"class":95},[44,1207,604],{"class":175},[44,1209,158],{"class":91},[44,1211,609],{"class":54},[44,1213,167],{"class":95},[44,1215,614],{"class":175},[44,1217,158],{"class":91},[44,1219,619],{"class":210},[44,1221,622],{"class":95},[44,1223,1224,1227,1229,1231,1233,1235,1237,1239,1241,1244,1246,1249,1251,1253,1255,1257],{"class":46,"line":389},[44,1225,1226],{"class":175},"                  mid_color",[44,1228,158],{"class":91},[44,1230,633],{"class":54},[44,1232,167],{"class":95},[44,1234,638],{"class":175},[44,1236,158],{"class":91},[44,1238,609],{"class":54},[44,1240,167],{"class":95},[44,1242,1243],{"class":175},"end_value",[44,1245,158],{"class":91},[44,1247,1248],{"class":210},"90",[44,1250,167],{"class":95},[44,1252,648],{"class":175},[44,1254,158],{"class":91},[44,1256,653],{"class":54},[44,1258,196],{"class":95},[44,1260,1261,1264,1266,1268,1271],{"class":46,"line":394},[44,1262,1263],{"class":95},"robust ",[44,1265,158],{"class":91},[44,1267,759],{"class":95},[44,1269,1270],{"class":54},"\"Per row, percentiles\"",[44,1272,196],{"class":95},[44,1274,1275,1278,1280,1282,1285,1288,1290,1293,1296,1299,1302,1304,1306,1308,1311,1313,1316],{"class":46,"line":407},[44,1276,1277],{"class":95},"write_table(robust, sales.assign(",[44,1279,709],{"class":91},[44,1281,824],{"class":95},[44,1283,1284],{"class":54},"\"Dec\"",[44,1286,1287],{"class":95},": sales[",[44,1289,1284],{"class":54},[44,1291,1292],{"class":95},"].where(sales.index ",[44,1294,1295],{"class":91},"!=",[44,1297,1298],{"class":54}," \"Nuts\"",[44,1300,1301],{"class":95},", sales.loc[",[44,1303,238],{"class":54},[44,1305,167],{"class":95},[44,1307,1284],{"class":54},[44,1309,1310],{"class":95},"] ",[44,1312,335],{"class":91},[44,1314,1315],{"class":210}," 4",[44,1317,1318],{"class":95},")}))\n",[44,1320,1321,1323,1325,1327,1329,1331,1333,1336,1338,1340],{"class":46,"line":423},[44,1322,369],{"class":91},[44,1324,791],{"class":95},[44,1326,375],{"class":91},[44,1328,796],{"class":210},[44,1330,581],{"class":95},[44,1332,466],{"class":210},[44,1334,1335],{"class":95},", robust.max_row ",[44,1337,806],{"class":91},[44,1339,287],{"class":210},[44,1341,478],{"class":95},[44,1343,1344,1347,1349,1351,1353,1355,1357,1360,1362,1364,1366,1368,1370,1372,1374],{"class":46,"line":437},[44,1345,1346],{"class":95},"    robust.conditional_formatting.add(",[44,1348,818],{"class":91},[44,1350,821],{"class":54},[44,1352,824],{"class":190},[44,1354,827],{"class":95},[44,1356,830],{"class":190},[44,1358,1359],{"class":54},":M",[44,1361,824],{"class":190},[44,1363,827],{"class":95},[44,1365,830],{"class":190},[44,1367,187],{"class":54},[44,1369,706],{"class":95},[44,1371,709],{"class":91},[44,1373,1173],{"class":210},[44,1375,714],{"class":95},[44,1377,1378,1381,1384],{"class":46,"line":448},[44,1379,1380],{"class":95},"wb.save(",[44,1382,1383],{"class":54},"\"colour_scales.xlsx\"",[44,1385,196],{"class":95},[10,1387,1388,1389,27],{},"Column scales compare items within each month — here each product's share of the month, so the colour shows which products gained or lost share. The last sheet shows a second refinement: anchoring the ends at the 10th and 90th percentiles rather than the minimum and maximum. One exceptional value — a Nuts order four times the usual size in December — would otherwise take the whole green end for itself and push every other Nuts month towards red; with percentile anchors, the outlier is simply green and the other months keep their shading. Use min and max when the extremes are the point, percentiles when one-off spikes should not dominate. Colour scales in general are introduced in ",[23,1390,1392],{"href":1391},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fadd-data-bars-and-colour-scales-with-openpyxl\u002F","Add Data Bars and Colour Scales with openpyxl",[892,1394,901,1399,901,1402,901,1405,901,1408,901,1415,901,1423,901,1428,901,1432,901,1436,901,1439,901,1444,901,1452,901,1457,901,1462,901,1468,901,1473,901,1478,901,1480,901,1483,901,1487,901,1490,901,1493,901,1498,901,1501,901,1504,901,1506,901,1509,901,1513,901,1516,901,1519,901,1525,901,1529],{"viewBox":1395,"role":895,"ariaLabelledBy":1396,"xmlns":899,"style":900},"4 0 752 272",[1397,1398],"cs-which-t","cs-which-d",[903,1400,1401],{"id":1397},"Which way to scale",[907,1403,1404],{"id":1398},"To compare each item with itself over time, add one colour scale per row. To compare items with each other within a period, add one scale per column. Use percentile anchors when single outliers would otherwise take the end of the scale.",[911,1406],{"x":211,"y":913,"width":914,"height":1407,"fill":916},"272",[911,1409],{"x":1410,"y":920,"width":1411,"height":1412,"rx":302,"fill":1413,"stroke":1414,"style":926},"233.3","293.4","75.5","#f0f4ff","var(--brand,#5b5cf0)",[928,1416,1418],{"transform":1417},"translate(368.0,29.0) scale(1.000)",[932,1419],{"d":1420,"fill":935,"stroke":1421,"style":1422},"M11 4a7 7 0 1 0 .01 0z M16 16l5 5","var(--brand-strong,#4338ca)","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[939,1424,1427],{"x":1425,"y":1412,"style":1426},"380.0","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","What should the colour compare?",[46,1429],{"x1":1425,"y1":1430,"x2":1425,"y2":1431,"stroke":1414,"style":926},"91.5","111.5",[46,1433],{"x1":1434,"y1":1431,"x2":1435,"y2":1431,"stroke":1414,"style":926},"134.7","625.3",[46,1437],{"x1":1434,"y1":1431,"x2":1434,"y2":1438,"stroke":1414,"style":926},"157.5",[1440,1441],"polygon",{"points":1442,"fill":1443},"134.7,161.5 129.7,152.5 139.7,152.5","#5b5cf0",[911,1445],{"x":1446,"y":1447,"width":1448,"height":1449,"rx":1195,"fill":916,"stroke":1450,"style":1451},"74.8","121.5","119.7","21.0","var(--line,#cdd5e6)","stroke-width:1.2px",[939,1453,1456],{"x":1434,"y":1454,"style":1455},"136.0","font-size:11.5px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","an item over time",[911,1458],{"x":919,"y":1459,"width":1460,"height":1461,"rx":302,"fill":971,"stroke":972,"style":926},"163.5","229.3","93.0",[928,1463,1465],{"transform":1464},"translate(122.7,176.5) scale(1.000)",[932,1466],{"d":1467,"fill":935,"stroke":979,"style":1422},"M4 20h16 M4 20V4 M6 16l4-5 4 3 6-7",[939,1469,1472],{"x":1434,"y":1470,"style":1471},"223.0","font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","one scale per row",[939,1474,1477],{"x":1434,"y":1475,"style":1476},"242.5","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","own best and worst",[46,1479],{"x1":1425,"y1":1431,"x2":1425,"y2":1438,"stroke":1414,"style":926},[1440,1481],{"points":1482,"fill":1443},"380.0,161.5 375.0,152.5 385.0,152.5",[911,1484],{"x":1485,"y":1447,"width":1486,"height":1449,"rx":1195,"fill":916,"stroke":1450,"style":1451},"309.7","140.5",[939,1488,1489],{"x":1425,"y":1454,"style":1455},"items within a period",[911,1491],{"x":1492,"y":1459,"width":1460,"height":1461,"rx":302,"fill":1413,"stroke":1414,"style":926},"265.3",[928,1494,1496],{"transform":1495},"translate(368.0,176.5) scale(1.000)",[932,1497],{"d":978,"fill":935,"stroke":1421,"style":1422},[939,1499,1500],{"x":1425,"y":1470,"style":1426},"one scale per column",[939,1502,1503],{"x":1425,"y":1475,"style":1476},"share or rank",[46,1505],{"x1":1435,"y1":1431,"x2":1435,"y2":1438,"stroke":1414,"style":926},[1440,1507],{"points":1508,"fill":1443},"625.3,161.5 620.3,152.5 630.3,152.5",[911,1510],{"x":1511,"y":1447,"width":1512,"height":1449,"rx":1195,"fill":916,"stroke":1450,"style":1451},"570.9","108.8",[939,1514,1515],{"x":1435,"y":1454,"style":1455},"spikes distort it",[911,1517],{"x":1518,"y":1459,"width":1460,"height":1461,"rx":302,"fill":924,"stroke":925,"style":926},"510.7",[928,1520,1522],{"transform":1521},"translate(613.3,176.5) scale(1.000)",[932,1523],{"d":1524,"fill":935,"stroke":936,"style":1422},"M3 5h18l-7 8v6l-4 2v-8z",[939,1526,1528],{"x":1435,"y":1470,"style":1527},"font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","percentile anchors",[939,1530,1531],{"x":1435,"y":1475,"style":1476},"10th \u002F 90th",[892,1533,901,1539,901,1542,901,1545,901,1550,901,1556,901,1560,901,1566,901,1570,901,1574,901,1578,901,1582,901,1586,901,1590,901,1594,901,1598,901,1602,901,1606,901,1610,901,1614,901,1617,901,1621,901,1623,901,1626,901,1628,901,1631,901,1633,901,1636,901,1638,901,1641,901,1643,901,1646,901,1649,901,1652,901,1654,901,1657,901,1659,901,1663,901,1665,901,1668,901,1670,901,1673,901,1677,901,1681,901,1683,901,1686,901,1689,901,1693,901,1695,901,1698,901,1700,901,1703,901,1705,901,1708,901,1710,901,1713,901,1715,901,1718,901,1720,901,1723,901,1726,901,1729,901,1731,901,1734,901,1736,901,1739,901,1741,901,1744,901,1746,901,1749,901,1751,901,1754,901,1756,901,1759,901,1762,901,1766,901,1768,901,1771,901,1773,901,1776,901,1778,901,1781,901,1783,901,1786,901,1788,901,1791,901,1793],{"viewBox":1534,"role":895,"ariaLabelledBy":1535,"xmlns":899,"style":1538},"137 0 485 196",[1536,1537],"cs-render-t","cs-render-d","width:100%;max-width:485px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[903,1540,1541],{"id":1536},"The per-row sheet as rendered",[907,1543,1544],{"id":1537},"With one colour scale per row, every product is green from December to February and red from May to August, showing the same seasonal pattern for the large and the small products alike.",[911,1546],{"x":1547,"y":913,"width":1548,"height":1549,"fill":916},"137","485","196",[911,1551],{"x":1552,"y":920,"width":1553,"height":1554,"rx":913,"fill":1555,"stroke":1450,"style":950},"154.0","32.0","24.0","#e7ebef",[911,1557],{"x":1558,"y":920,"width":1559,"height":1554,"rx":913,"fill":1555,"stroke":1450,"style":950},"186.0","78.7",[939,1561,1565],{"x":1562,"y":1563,"style":1564},"225.3","33.0","font-size:11px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","A",[911,1567],{"x":1568,"y":920,"width":1569,"height":1554,"rx":913,"fill":1555,"stroke":1450,"style":950},"264.7","69.2",[939,1571,1573],{"x":1572,"y":1563,"style":1564},"299.2","B",[911,1575],{"x":1576,"y":920,"width":1577,"height":1554,"rx":913,"fill":1555,"stroke":1450,"style":950},"333.8","69.1",[939,1579,1581],{"x":1580,"y":1563,"style":1564},"368.4","C",[911,1583],{"x":1584,"y":920,"width":1585,"height":1554,"rx":913,"fill":1555,"stroke":1450,"style":950},"402.9","69.5",[939,1587,1589],{"x":1588,"y":1563,"style":1564},"437.7","D",[911,1591],{"x":1592,"y":920,"width":1593,"height":1554,"rx":913,"fill":1555,"stroke":1450,"style":950},"472.4","67.3",[939,1595,1597],{"x":1596,"y":1563,"style":1564},"506.1","E",[911,1599],{"x":1600,"y":920,"width":1601,"height":1554,"rx":913,"fill":1555,"stroke":1450,"style":950},"539.7","66.3",[939,1603,1605],{"x":1604,"y":1563,"style":1564},"572.9","F",[911,1607],{"x":1552,"y":1608,"width":1553,"height":1609,"rx":913,"fill":1555,"stroke":1450,"style":950},"40.0","28.0",[939,1611,364],{"x":1612,"y":1613,"style":1564},"170.0","59.0",[911,1615],{"x":1558,"y":1608,"width":1559,"height":1609,"rx":913,"fill":1413,"stroke":1414,"style":1616},"stroke-width:1.5px",[939,1618,1620],{"x":1562,"y":1613,"style":1619},"font-size:12px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Product",[911,1622],{"x":1568,"y":1608,"width":1569,"height":1609,"rx":913,"fill":1413,"stroke":1414,"style":1616},[939,1624,1625],{"x":1572,"y":1613,"style":1619},"Dec",[911,1627],{"x":1576,"y":1608,"width":1577,"height":1609,"rx":913,"fill":1413,"stroke":1414,"style":1616},[939,1629,1630],{"x":1580,"y":1613,"style":1619},"Jan",[911,1632],{"x":1584,"y":1608,"width":1585,"height":1609,"rx":913,"fill":1413,"stroke":1414,"style":1616},[939,1634,1635],{"x":1588,"y":1613,"style":1619},"Feb",[911,1637],{"x":1592,"y":1608,"width":1593,"height":1609,"rx":913,"fill":1413,"stroke":1414,"style":1616},[939,1639,1640],{"x":1596,"y":1613,"style":1619},"May",[911,1642],{"x":1600,"y":1608,"width":1601,"height":1609,"rx":913,"fill":1413,"stroke":1414,"style":1616},[939,1644,1645],{"x":1604,"y":1613,"style":1619},"Jul",[911,1647],{"x":1552,"y":1648,"width":1553,"height":1609,"rx":913,"fill":1555,"stroke":1450,"style":950},"68.0",[939,1650,466],{"x":1612,"y":1651,"style":1564},"87.0",[911,1653],{"x":1558,"y":1648,"width":1559,"height":1609,"rx":913,"fill":916,"stroke":1450,"style":950},[939,1655,1656],{"x":1562,"y":1651,"style":954},"Bolts",[911,1658],{"x":1568,"y":1648,"width":1569,"height":1609,"rx":913,"fill":971,"stroke":972,"style":1616},[939,1660,1662],{"x":1572,"y":1651,"style":1661},"font-size:12px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","72,300",[911,1664],{"x":1576,"y":1648,"width":1577,"height":1609,"rx":913,"fill":916,"stroke":1450,"style":950},[939,1666,1667],{"x":1580,"y":1651,"style":954},"56,830",[911,1669],{"x":1584,"y":1648,"width":1585,"height":1609,"rx":913,"fill":916,"stroke":1450,"style":950},[939,1671,1672],{"x":1588,"y":1651,"style":954},"65,300",[911,1674],{"x":1592,"y":1648,"width":1593,"height":1609,"rx":913,"fill":1675,"stroke":1676,"style":1616},"#fce9e9","var(--danger,#dc2626)",[939,1678,1680],{"x":1596,"y":1651,"style":1679},"font-size:12px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","41,060",[911,1682],{"x":1600,"y":1648,"width":1601,"height":1609,"rx":913,"fill":916,"stroke":1450,"style":950},[939,1684,1685],{"x":1604,"y":1651,"style":954},"39,510",[911,1687],{"x":1552,"y":1688,"width":1553,"height":1609,"rx":913,"fill":1555,"stroke":1450,"style":950},"96.0",[939,1690,1692],{"x":1612,"y":1691,"style":1564},"115.0","3",[911,1694],{"x":1558,"y":1688,"width":1559,"height":1609,"rx":913,"fill":916,"stroke":1450,"style":950},[939,1696,1697],{"x":1562,"y":1691,"style":954},"Nuts",[911,1699],{"x":1568,"y":1688,"width":1569,"height":1609,"rx":913,"fill":971,"stroke":972,"style":1616},[939,1701,1702],{"x":1572,"y":1691,"style":1661},"25,080",[911,1704],{"x":1576,"y":1688,"width":1577,"height":1609,"rx":913,"fill":916,"stroke":1450,"style":950},[939,1706,1707],{"x":1580,"y":1691,"style":954},"21,620",[911,1709],{"x":1584,"y":1688,"width":1585,"height":1609,"rx":913,"fill":916,"stroke":1450,"style":950},[939,1711,1712],{"x":1588,"y":1691,"style":954},"24,980",[911,1714],{"x":1592,"y":1688,"width":1593,"height":1609,"rx":913,"fill":916,"stroke":1450,"style":950},[939,1716,1717],{"x":1596,"y":1691,"style":954},"16,260",[911,1719],{"x":1600,"y":1688,"width":1601,"height":1609,"rx":913,"fill":1675,"stroke":1676,"style":1616},[939,1721,1722],{"x":1604,"y":1691,"style":1679},"15,290",[911,1724],{"x":1552,"y":1725,"width":1553,"height":1609,"rx":913,"fill":1555,"stroke":1450,"style":950},"124.0",[939,1727,211],{"x":1612,"y":1728,"style":1564},"143.0",[911,1730],{"x":1558,"y":1725,"width":1559,"height":1609,"rx":913,"fill":916,"stroke":1450,"style":950},[939,1732,1733],{"x":1562,"y":1728,"style":954},"Rivets",[911,1735],{"x":1568,"y":1725,"width":1569,"height":1609,"rx":913,"fill":916,"stroke":1450,"style":950},[939,1737,1738],{"x":1572,"y":1728,"style":954},"2,900",[911,1740],{"x":1576,"y":1725,"width":1577,"height":1609,"rx":913,"fill":916,"stroke":1450,"style":950},[939,1742,1743],{"x":1580,"y":1728,"style":954},"2,750",[911,1745],{"x":1584,"y":1725,"width":1585,"height":1609,"rx":913,"fill":971,"stroke":972,"style":1616},[939,1747,1748],{"x":1588,"y":1728,"style":1661},"3,090",[911,1750],{"x":1592,"y":1725,"width":1593,"height":1609,"rx":913,"fill":916,"stroke":1450,"style":950},[939,1752,1753],{"x":1596,"y":1728,"style":954},"2,070",[911,1755],{"x":1600,"y":1725,"width":1601,"height":1609,"rx":913,"fill":1675,"stroke":1676,"style":1616},[939,1757,1758],{"x":1604,"y":1728,"style":1679},"1,620",[911,1760],{"x":1552,"y":1761,"width":1553,"height":1609,"rx":913,"fill":1555,"stroke":1450,"style":950},"152.0",[939,1763,1765],{"x":1612,"y":1764,"style":1564},"171.0","5",[911,1767],{"x":1558,"y":1761,"width":1559,"height":1609,"rx":913,"fill":916,"stroke":1450,"style":950},[939,1769,1770],{"x":1562,"y":1764,"style":954},"Brackets",[911,1772],{"x":1568,"y":1761,"width":1569,"height":1609,"rx":913,"fill":916,"stroke":1450,"style":950},[939,1774,1775],{"x":1572,"y":1764,"style":954},"1,170",[911,1777],{"x":1576,"y":1761,"width":1577,"height":1609,"rx":913,"fill":916,"stroke":1450,"style":950},[939,1779,1780],{"x":1580,"y":1764,"style":954},"970",[911,1782],{"x":1584,"y":1761,"width":1585,"height":1609,"rx":913,"fill":971,"stroke":972,"style":1616},[939,1784,1785],{"x":1588,"y":1764,"style":1661},"1,230",[911,1787],{"x":1592,"y":1761,"width":1593,"height":1609,"rx":913,"fill":916,"stroke":1450,"style":950},[939,1789,1790],{"x":1596,"y":1764,"style":954},"730",[911,1792],{"x":1600,"y":1761,"width":1601,"height":1609,"rx":913,"fill":1675,"stroke":1676,"style":1616},[939,1794,1795],{"x":1604,"y":1764,"style":1679},"640",[29,1797,1799],{"id":1798},"step-4-check-the-result-and-mind-the-rule-count","Step 4 — Check the result, and mind the rule count",[34,1801,1803],{"className":82,"code":1802,"language":84,"meta":39,"style":39},"import subprocess\nfrom openpyxl import load_workbook\nfrom PIL import Image\n\ncheck = load_workbook(\"colour_scales.xlsx\")\nfor ws in check.worksheets:\n    print(f\"{ws.title:\u003C22} rules: {sum(len(cf.rules) for cf in ws.conditional_formatting)}\")\n\nsubprocess.run([\"soffice\", \"--headless\", \"--convert-to\", \"pdf\", \"colour_scales.xlsx\"], check=True, capture_output=True)\nsubprocess.run([\"pdftoppm\", \"-png\", \"-r\", \"60\", \"colour_scales.pdf\", \"scales\"], check=True)\ndef reds_and_greens(png):\n    counts = Image.open(png).convert(\"RGB\").getcolors(maxcolors=10**6)\n    red = sum(n for n, (r, g, b) in counts if r > 200 and g \u003C 160 and b \u003C 160)\n    green = sum(n for n, (r, g, b) in counts if g > 150 and r \u003C 170 and b \u003C 160)\n    return red, green\nfor page, name in [(1, \"One scale\"), (2, \"Per row\")]:\n    red, green = reds_and_greens(f\"scales-{page}.png\")\n    print(f\"{name:\u003C10} red-ish px {red:>6} | green-ish px {green:>6}\")\n",[41,1804,1805,1812,1823,1836,1840,1854,1866,1915,1919,1968,2010,2020,2050,2107,2154,2162,2193,2220],{"__ignoreMap":39},[44,1806,1807,1809],{"class":46,"line":47},[44,1808,92],{"class":91},[44,1810,1811],{"class":95}," subprocess\n",[44,1813,1814,1816,1818,1820],{"class":46,"line":105},[44,1815,121],{"class":91},[44,1817,124],{"class":95},[44,1819,92],{"class":91},[44,1821,1822],{"class":95}," load_workbook\n",[44,1824,1825,1827,1830,1833],{"class":46,"line":118},[44,1826,121],{"class":91},[44,1828,1829],{"class":210}," PIL",[44,1831,1832],{"class":91}," import",[44,1834,1835],{"class":95}," Image\n",[44,1837,1838],{"class":46,"line":132},[44,1839,149],{"emptyLinePlaceholder":148},[44,1841,1842,1845,1847,1850,1852],{"class":46,"line":145},[44,1843,1844],{"class":95},"check ",[44,1846,158],{"class":91},[44,1848,1849],{"class":95}," load_workbook(",[44,1851,1383],{"class":54},[44,1853,196],{"class":95},[44,1855,1856,1858,1861,1863],{"class":46,"line":152},[44,1857,369],{"class":91},[44,1859,1860],{"class":95}," ws ",[44,1862,375],{"class":91},[44,1864,1865],{"class":95}," check.worksheets:\n",[44,1867,1868,1871,1873,1875,1877,1879,1882,1885,1887,1890,1892,1894,1896,1898,1900,1902,1904,1906,1909,1911,1913],{"class":46,"line":199},[44,1869,1870],{"class":210},"    print",[44,1872,581],{"class":95},[44,1874,818],{"class":91},[44,1876,187],{"class":54},[44,1878,824],{"class":190},[44,1880,1881],{"class":95},"ws.title",[44,1883,1884],{"class":91},":\u003C22",[44,1886,830],{"class":190},[44,1888,1889],{"class":54}," rules: ",[44,1891,824],{"class":190},[44,1893,869],{"class":210},[44,1895,581],{"class":95},[44,1897,874],{"class":210},[44,1899,877],{"class":95},[44,1901,369],{"class":91},[44,1903,882],{"class":95},[44,1905,375],{"class":91},[44,1907,1908],{"class":95}," ws.conditional_formatting)",[44,1910,830],{"class":190},[44,1912,187],{"class":54},[44,1914,196],{"class":95},[44,1916,1917],{"class":46,"line":216},[44,1918,149],{"emptyLinePlaceholder":148},[44,1920,1921,1924,1927,1929,1932,1934,1937,1939,1942,1944,1946,1949,1952,1954,1957,1959,1962,1964,1966],{"class":46,"line":279},[44,1922,1923],{"class":95},"subprocess.run([",[44,1925,1926],{"class":54},"\"soffice\"",[44,1928,167],{"class":95},[44,1930,1931],{"class":54},"\"--headless\"",[44,1933,167],{"class":95},[44,1935,1936],{"class":54},"\"--convert-to\"",[44,1938,167],{"class":95},[44,1940,1941],{"class":54},"\"pdf\"",[44,1943,167],{"class":95},[44,1945,1383],{"class":54},[44,1947,1948],{"class":95},"], ",[44,1950,1951],{"class":175},"check",[44,1953,158],{"class":91},[44,1955,1956],{"class":210},"True",[44,1958,167],{"class":95},[44,1960,1961],{"class":175},"capture_output",[44,1963,158],{"class":91},[44,1965,1956],{"class":210},[44,1967,196],{"class":95},[44,1969,1970,1972,1975,1977,1980,1982,1985,1987,1990,1992,1995,1997,2000,2002,2004,2006,2008],{"class":46,"line":324},[44,1971,1923],{"class":95},[44,1973,1974],{"class":54},"\"pdftoppm\"",[44,1976,167],{"class":95},[44,1978,1979],{"class":54},"\"-png\"",[44,1981,167],{"class":95},[44,1983,1984],{"class":54},"\"-r\"",[44,1986,167],{"class":95},[44,1988,1989],{"class":54},"\"60\"",[44,1991,167],{"class":95},[44,1993,1994],{"class":54},"\"colour_scales.pdf\"",[44,1996,167],{"class":95},[44,1998,1999],{"class":54},"\"scales\"",[44,2001,1948],{"class":95},[44,2003,1951],{"class":175},[44,2005,158],{"class":91},[44,2007,1956],{"class":210},[44,2009,196],{"class":95},[44,2011,2012,2014,2017],{"class":46,"line":389},[44,2013,397],{"class":91},[44,2015,2016],{"class":400}," reds_and_greens",[44,2018,2019],{"class":95},"(png):\n",[44,2021,2022,2025,2027,2030,2033,2036,2039,2041,2043,2045,2048],{"class":46,"line":394},[44,2023,2024],{"class":95},"    counts ",[44,2026,158],{"class":91},[44,2028,2029],{"class":95}," Image.open(png).convert(",[44,2031,2032],{"class":54},"\"RGB\"",[44,2034,2035],{"class":95},").getcolors(",[44,2037,2038],{"class":175},"maxcolors",[44,2040,158],{"class":91},[44,2042,1195],{"class":210},[44,2044,709],{"class":91},[44,2046,2047],{"class":210},"6",[44,2049,196],{"class":95},[44,2051,2052,2055,2057,2060,2063,2065,2068,2070,2073,2076,2078,2081,2084,2087,2090,2093,2096,2098,2101,2103,2105],{"class":46,"line":407},[44,2053,2054],{"class":95},"    red ",[44,2056,158],{"class":91},[44,2058,2059],{"class":210}," sum",[44,2061,2062],{"class":95},"(n ",[44,2064,369],{"class":91},[44,2066,2067],{"class":95}," n, (r, g, b) ",[44,2069,375],{"class":91},[44,2071,2072],{"class":95}," counts ",[44,2074,2075],{"class":91},"if",[44,2077,791],{"class":95},[44,2079,2080],{"class":91},">",[44,2082,2083],{"class":210}," 200",[44,2085,2086],{"class":91}," and",[44,2088,2089],{"class":95}," g ",[44,2091,2092],{"class":91},"\u003C",[44,2094,2095],{"class":210}," 160",[44,2097,2086],{"class":91},[44,2099,2100],{"class":95}," b ",[44,2102,2092],{"class":91},[44,2104,2095],{"class":210},[44,2106,196],{"class":95},[44,2108,2109,2112,2114,2116,2118,2120,2122,2124,2126,2128,2130,2132,2135,2137,2139,2141,2144,2146,2148,2150,2152],{"class":46,"line":423},[44,2110,2111],{"class":95},"    green ",[44,2113,158],{"class":91},[44,2115,2059],{"class":210},[44,2117,2062],{"class":95},[44,2119,369],{"class":91},[44,2121,2067],{"class":95},[44,2123,375],{"class":91},[44,2125,2072],{"class":95},[44,2127,2075],{"class":91},[44,2129,2089],{"class":95},[44,2131,2080],{"class":91},[44,2133,2134],{"class":210}," 150",[44,2136,2086],{"class":91},[44,2138,791],{"class":95},[44,2140,2092],{"class":91},[44,2142,2143],{"class":210}," 170",[44,2145,2086],{"class":91},[44,2147,2100],{"class":95},[44,2149,2092],{"class":91},[44,2151,2095],{"class":210},[44,2153,196],{"class":95},[44,2155,2156,2159],{"class":46,"line":437},[44,2157,2158],{"class":91},"    return",[44,2160,2161],{"class":95}," red, green\n",[44,2163,2164,2166,2169,2171,2174,2176,2178,2181,2184,2186,2188,2190],{"class":46,"line":448},[44,2165,369],{"class":91},[44,2167,2168],{"class":95}," page, name ",[44,2170,375],{"class":91},[44,2172,2173],{"class":95}," [(",[44,2175,364],{"class":210},[44,2177,167],{"class":95},[44,2179,2180],{"class":54},"\"One scale\"",[44,2182,2183],{"class":95},"), (",[44,2185,466],{"class":210},[44,2187,167],{"class":95},[44,2189,762],{"class":54},[44,2191,2192],{"class":95},")]:\n",[44,2194,2195,2198,2200,2203,2205,2208,2210,2213,2215,2218],{"class":46,"line":481},[44,2196,2197],{"class":95},"    red, green ",[44,2199,158],{"class":91},[44,2201,2202],{"class":95}," reds_and_greens(",[44,2204,818],{"class":91},[44,2206,2207],{"class":54},"\"scales-",[44,2209,824],{"class":190},[44,2211,2212],{"class":95},"page",[44,2214,830],{"class":190},[44,2216,2217],{"class":54},".png\"",[44,2219,196],{"class":95},[44,2221,2222,2224,2226,2228,2230,2232,2235,2238,2240,2243,2245,2248,2251,2253,2256,2258,2261,2263,2265,2267],{"class":46,"line":495},[44,2223,1870],{"class":210},[44,2225,581],{"class":95},[44,2227,818],{"class":91},[44,2229,187],{"class":54},[44,2231,824],{"class":190},[44,2233,2234],{"class":95},"name",[44,2236,2237],{"class":91},":\u003C10",[44,2239,830],{"class":190},[44,2241,2242],{"class":54}," red-ish px ",[44,2244,824],{"class":190},[44,2246,2247],{"class":95},"red",[44,2249,2250],{"class":91},":>6",[44,2252,830],{"class":190},[44,2254,2255],{"class":54}," | green-ish px ",[44,2257,824],{"class":190},[44,2259,2260],{"class":95},"green",[44,2262,2250],{"class":91},[44,2264,830],{"class":190},[44,2266,187],{"class":54},[44,2268,196],{"class":95},[10,2270,2271,2272,2275],{},"The ",[14,2273,2274],{},"One scale"," sheet has one rule and the per-row sheets five each — one per product — while the column sheet has twelve. In the rendered pages, the single-scale sheet has more than twice as many red as green pixels, because four of the five products sit at the bottom of the shared range, while the per-row sheet shows a balance of red and green, since every row spans the full scale. On a large table the rule count matters: a rule per row on a 10,000-row sheet means 10,000 conditional formatting entries, which makes the file slower to open and edit. For long tables, scale per column — usually a few dozen rules — or colour in pandas and write fills directly when the colours never need to update.",[29,2277,2279],{"id":2278},"labelling-what-the-colours-mean","Labelling what the colours mean",[10,2281,2282,2283,2286,2287,2290],{},"Per-row and per-column scales change what a colour means, and readers need to know which they are looking at: \"green\" on a per-row sheet means ",[14,2284,2285],{},"this product's best month",", not ",[14,2288,2289],{},"a big month",". Put a one-line note above the table — \"Colours compare each product with its own months\" — or in the sheet title, and keep the same convention across a workbook. If both views are useful, give them separate sheets, as here, rather than mixing per-row and per-column scales on one table, where no single reading of the colours would be right. When the numbers are going to be read in print or by people with red–green colour blindness, a blue–white–orange scale keeps the order visible without relying on red and green.",[29,2292,2294],{"id":2293},"common-pitfalls","Common pitfalls",[2296,2297,2298,2306,2312,2318,2324],"ul",{},[2299,2300,2301,2305],"li",{},[2302,2303,2304],"strong",{},"One scale over items of very different sizes."," It shows size, not performance.",[2299,2307,2308,2311],{},[2302,2309,2310],{},"A rule per row on huge tables."," Thousands of rules slow Excel down noticeably.",[2299,2313,2314,2317],{},[2302,2315,2316],{},"Min\u002Fmax anchors with outliers."," One spike claims the whole end of the scale.",[2299,2319,2320,2323],{},[2302,2321,2322],{},"Percentages and totals in the same range."," Keep total rows and columns outside the scaled range.",[2299,2325,2326,2329],{},[2302,2327,2328],{},"Red for \"low\" when low is good."," Swap the colours for costs, returns or error rates.",[29,2331,2333],{"id":2332},"conclusion","Conclusion",[10,2335,2336,2337,2340],{},"A colour scale compares every cell in its range, so apply it to the range that holds the comparison you want: one ",[41,2338,2339],{},"ColorScaleRule"," per row to compare each item with itself, one per column to compare items within each period. Anchor the ends at percentiles when single outliers would otherwise dominate, keep totals outside the scaled ranges, and on large tables prefer per-column rules or static fills so the workbook stays responsive.",[29,2342,2344],{"id":2343},"frequently-asked-questions","Frequently asked questions",[10,2346,2347,2350],{},[2302,2348,2349],{},"How do I apply a separate colour scale to each row in openpyxl?","\nLoop over the rows and add a ColorScaleRule to each row's range, for example B2:M2, B3:M3 and so on.",[10,2352,2353,2356],{},[2302,2354,2355],{},"Why is my whole colour scale red except one row?","\nA single scale uses the minimum and maximum of the whole range, so one large row takes the green end; apply a scale per row or per column.",[10,2358,2359,2362],{},[2302,2360,2361],{},"Should colour scales use percentiles or min and max?","\nUse percentiles such as the 10th and 90th when outliers would otherwise take the ends of the scale, and min and max when the extremes are what matters.",[10,2364,2365,2368],{},[2302,2366,2367],{},"Do many conditional formatting rules slow Excel down?","\nYes. Thousands of rules make files slower to open and edit; use per-column rules or static fills for very long tables.",[29,2370,2372],{"id":2371},"related","Related",[2296,2374,2375,2381,2386,2393],{},[2299,2376,2377,2378,2380],{},"Up one level: ",[23,2379,26],{"href":25}," — rules from Python.",[2299,2382,2383,2385],{},[23,2384,1392],{"href":1391}," — the basics.",[2299,2387,2388,2392],{},[23,2389,2391],{"href":2390},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fturn-a-pivot-table-into-a-heatmap-in-excel\u002F","Turn a Pivot Table into a Heatmap in Excel"," — heatmaps from pivots.",[2299,2394,2395,2399],{},[23,2396,2398],{"href":2397},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fhighlight-values-outside-a-tolerance-of-target-with-openpyxl\u002F","Highlight Values Outside a Tolerance of Target with openpyxl"," — rule-based highlights.",[2401,2402,2403],"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 .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 .sP0c6, html code.shiki .sP0c6{--shiki-default:#005CC5;--shiki-dark:#91CBFF}html pre.shiki code .s_Opv, html code.shiki .s_Opv{--shiki-default:#6F42C1;--shiki-dark:#DBB7FF}html pre.shiki code .s-wDw, html code.shiki .s-wDw{--shiki-default:#6A737D;--shiki-dark:#BDC4CC}",{"title":39,"searchDepth":105,"depth":105,"links":2405},[2406,2407,2408,2409,2410,2411,2412,2413,2414,2415],{"id":31,"depth":105,"text":32},{"id":78,"depth":105,"text":79},{"id":740,"depth":105,"text":741},{"id":1003,"depth":105,"text":1004},{"id":1798,"depth":105,"text":1799},{"id":2278,"depth":105,"text":2279},{"id":2293,"depth":105,"text":2294},{"id":2332,"depth":105,"text":2333},{"id":2343,"depth":105,"text":2344},{"id":2371,"depth":105,"text":2372},"2026-10-02","Colour scales compare every cell in their range with every other cell, so one big product drowns out all the small ones. Apply a separate colour scale to each row or each column with openpyxl so every item is coloured against its own range, choose between min-max and percentile scaling, keep the number of rules manageable, and check the rendered result.","md",[2420,2422,2424,2426],{"q":2349,"a":2421},"Loop over the rows and add a ColorScaleRule to each row's range, for example B2:M2, B3:M3 and so on.",{"q":2355,"a":2423},"A single scale uses the minimum and maximum of the whole range, so one large row takes the green end; apply a scale per row or per column.",{"q":2361,"a":2425},"Use percentiles such as the 10th and 90th when outliers would otherwise take the ends of the scale, and min and max when the extremes are what matters.",{"q":2367,"a":2427},"Yes. Thousands of rules make files slower to open and edit; use per-column rules or static fills for very long tables.","colour scale per row or column openpyxl",null,{"breadcrumb":2431},[2432,2434,2437],{"name":2433,"item":308},"Home",{"name":2435,"item":2436},"Advanced Data Transformation and Cleaning for Excel Automation","\u002Fadvanced-data-transformation-and-cleaning\u002F",{"name":2438,"item":25},"Applying Conditional Formatting With openpyxl","\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fapply-a-colour-scale-per-row-or-per-column-with-openpyxl",{"title":5,"description":2441},"Per-row and per-column colour scales in openpyxl: why one ColorScaleRule over a whole table misleads, one rule per row or column, percentile versus min\u002Fmax anchors, rule counts on large tables, and a rendered check.","apply-a-colour-scale-per-row-or-per-column-with-openpyxl","advanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fapply-a-colour-scale-per-row-or-per-column-with-openpyxl\u002Findex",[2445,2446],"conditional-formatting","openpyxl","how-to","jalZoK7VSJryb35WaMj6JqdnGXEHkXgUBhhGUhNzooQ",[2450,2454],{"title":2451,"path":2452,"stem":2453,"children":-1},"Add Icon Sets to Excel Cells with openpyxl","\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fadd-icon-sets-with-openpyxl","advanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fadd-icon-sets-with-openpyxl\u002Findex",{"title":2455,"path":2456,"stem":2457,"children":-1},"Apply Conditional Formatting to an Excel Table That Grows","\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fapply-conditional-formatting-to-an-excel-table-that-grows","advanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fapply-conditional-formatting-to-an-excel-table-that-grows\u002Findex",[2459,2461],{"path":2460,"title":2438},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl",{"path":2462,"title":2435},"\u002Fadvanced-data-transformation-and-cleaning",[],[2465,2468,2470,2471,2472,2475],{"path":2466,"title":2467,"kind":2447},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fapply-conditional-formatting-with-xlsxwriter","Apply Conditional Formatting with xlsxwriter",{"path":2469,"title":1392,"kind":2447},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fadd-data-bars-and-colour-scales-with-openpyxl",{"path":2452,"title":2451,"kind":2447},{"path":2456,"title":2455,"kind":2447},{"path":2473,"title":2474,"kind":2447},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fcontrol-conditional-formatting-rule-order-and-stop-if-true","Control Conditional Formatting Rule Order and Stop If True",{"path":2476,"title":2477,"kind":2447},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fhighlight-an-entire-row-based-on-a-cell-value-with-openpyxl","Highlight an Entire Row Based on a Cell Value with openpyxl",1790972078061]