Power BI • choose your denominator — Define whether percent of total retains a region slicer or removes it, and expose the DAX filter modifications behind each denominator.
HTML for this example
Select the code and use your copy shortcut. Changes in this preview are temporary.
<!doctype html>
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Power BI • choose your denominator</title><style>*{box-sizing:border-box}body{margin:0;background:var(--bg,#f3f7fa);color:var(--ink,#203342);font:16px/1.55 system-ui,Segoe UI,sans-serif}main{max-width:1100px;margin:auto;padding:28px 30px 50px}h1{font-size:clamp(27px,3.5vw,40px);line-height:1.18;letter-spacing:-.035em;margin:8px 0 12px}h2{font-size:21px;line-height:1.35;margin:0 0 16px}h3{font-size:18px}.eyebrow{color:var(--accent,#176783);font-size:12px;letter-spacing:.12em;font-weight:800;text-transform:uppercase}.intro,.muted,small{color:#516272}.intro{margin:0 0 24px}.panel{padding:24px;border:1px solid var(--line,#d6e0e7);border-radius:12px;background:white;margin:18px 0}.grid{display:grid;grid-template-columns:1fr 1fr;gap:22px}.grid>*{min-width:0}.controls{display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin:16px 0}button,input,textarea,select{font:inherit}button{border:1px solid var(--accent,#176783);background:var(--accent,#176783);color:white;padding:10px 16px;min-height:44px;border-radius:7px;font-weight:700;cursor:pointer}button.secondary{background:white;color:var(--accent,#176783)}button[aria-pressed=true]{background:var(--tint,#e3f2f8);color:var(--ink,#203342);box-shadow:inset 0 0 0 2px var(--accent,#176783)}button:hover{filter:brightness(.96)}:focus-visible{outline:3px solid #d56b00;outline-offset:3px}label{display:block;margin:12px 0 5px;font-size:14px;font-weight:650}input:not([type=checkbox]),select,textarea{width:100%;padding:10px 12px;min-height:44px;border:1px solid #94a5b2;background:white;color:inherit;border-radius:7px}textarea{resize:vertical;min-height:120px}input[type=checkbox]{width:20px;height:20px;margin-right:9px}label.inline{display:flex;align-items:center;font-weight:500;gap:7px}.result{padding:24px;background:var(--tint,#e3f2f8);border:1px solid var(--line,#c8dce7);border-radius:12px}.big{font-size:clamp(30px,5vw,48px);font-weight:780;line-height:1.25;letter-spacing:-.035em;margin:10px 0}.trace{font:15px/1.7 ui-monospace,Consolas,monospace;white-space:pre-wrap;overflow-wrap:anywhere}.error{color:#a12820;font-weight:650;min-height:24px}.table-wrap{overflow-x:auto}table{border-collapse:collapse;width:100%;font-size:15px}th,td{text-align:left;border-bottom:1px solid var(--line,#d6e0e7);padding:12px 9px;vertical-align:top}th{font-size:12px;text-transform:uppercase;letter-spacing:.03em;color:#516272}code,pre,.code{font:14px/1.65 ui-monospace,Consolas,monospace}pre{white-space:pre-wrap;overflow-wrap:anywhere;background:var(--tint,#eef3f7);padding:16px;border-radius:6px}details{border-top:1px solid var(--line,#d6e0e7);margin:24px 0;padding-top:16px}summary{cursor:pointer;font-weight:700;min-height:44px}footer{border-top:1px solid var(--line,#d6e0e7);margin-top:26px;padding-top:16px;font-size:13px;color:#516272}.bar{height:16px;background:#dce4ea;border-radius:20px;overflow:hidden;margin:12px 0}.bar span{display:block;height:100%;background:var(--accent,#176783)}[hidden]{display:none!important}@media(max-width:720px){main{padding:20px}.grid{grid-template-columns:1fr;gap:12px}.panel,.result{padding:20px}}@media(max-width:400px){main{padding:16px}.panel,.result{padding:16px}button{padding:10px 13px}}
body{--accent:#75600b;--bg:#f5f5f2;--ink:#272c31;--tint:#fff4bf;--line:#deded5}.toolbar{display:flex;justify-content:space-between;gap:20px;flex-wrap:wrap}.toolbar .controls{margin-top:7px}.results .global{background:#e5f0f7}.global .bar span{background:#26729c}.results{margin:18px 0 10px;grid-template-columns:1fr 1fr}.results .big{font-size:clamp(24px,4vw,48px)}.results p{font:14px/1.6 ui-monospace,Consolas,monospace;overflow-wrap:anywhere}@media(max-width:400px){.results{gap:10px}.results .result{padding:13px}}.active{background:#fff9df}.active th{color:#272c31}.result,.panel{border-radius:5px}.big{font-variant-numeric:tabular-nums}</style></head><body><main>
<header><span class="eyebrow">Filter-context companion / fictional R1 model</span><h1>One count. Two different shares.</h1><p class="intro">Keep the current numerator; change which filters the denominator retains.</p></header>
<div class="toolbar"><div><span class="eyebrow">Region slicer</span><div class="controls"><button type="button" id="west" class="secondary">West</button><button type="button" id="east" class="secondary">East</button><button type="button" id="all" class="secondary">All regions</button></div></div><div><span class="eyebrow">Inspect visual context</span><div class="controls"><button type="button" id="cat-a" class="secondary">Category A</button><button type="button" id="cat-b" class="secondary">Category B</button><button type="button" id="subtotal" class="secondary">Subtotal</button></div></div></div>
<div class="grid results"><section class="result"><span class="eyebrow">Share of region</span><div class="big" id="region-share">75%</div><p id="region-trace">3 ÷ 4 = 0.75</p><div class="bar"><span id="region-bar" style="width:75%"></span></div><small>Remove category filter; retain selected region.</small></section><section class="result global"><span class="eyebrow">Share of all counts</span><div class="big" id="all-share">30%</div><p id="all-trace">3 ÷ 10 = 0.3</p><div class="bar"><span id="all-bar" style="width:30%"></span></div><small>Remove all denominator report-context filters.</small></section></div>
<p id="context" class="muted">West / Category A</p><p id="error" class="error" role="alert"></p>
<section class="panel"><h2>Matrix • numerator and both totals</h2><div class="table-wrap"><table><thead><tr><th>Row</th><th>Count</th><th>Region total</th><th>Region share</th><th>All total</th><th>All share</th></tr></thead><tbody id="matrix"></tbody></table></div><p id="bad-ratio" class="muted"></p></section>
<div class="grid"><section class="panel"><h2>Fixture counts</h2><p class="muted" id="revision">R1 • original counts</p><div class="grid"><div><label for="wa">West / A</label><input id="wa" type="number" value="3"><label for="wb">West / B</label><input id="wb" type="number" value="1"></div><div><label for="ea">East / A</label><input id="ea" type="number" value="2"><label for="eb">East / B</label><input id="eb" type="number" value="4"></div></div><div class="controls"><button type="button" id="apply">Apply revised counts</button><button type="button" id="zero" class="secondary">Separate zero fixture</button><button type="button" id="reset" class="secondary">Restore R1</button></div></section>
<section class="panel"><h2>Measures to review natively</h2><pre>Count = SUM(FactCounts[Count])
Region Total = CALCULATE([Count],
REMOVEFILTERS(DimCategory[Category]))
Share of Region = DIVIDE([Count], [Region Total])
All Counts Total = CALCULATE([Count], REMOVEFILTERS())
Share of All Counts = DIVIDE([Count], [All Counts Total])</pre></section></div>
<details><summary>Model and filter manifest</summary><p>DimRegion contains unique West/East keys; DimCategory contains unique A/B keys. Active one-to-many, single-direction relationships filter FactCounts from each dimension. Visual rows use DimCategory[Category]; the slicer uses DimRegion[Region]. All keys match.</p><p>No other filters or security restrictions are in this fixture. Subtotals evaluate the measures without a category row filter; they do not average percentages. The separate all-zero fixture returns BLANK for zero denominators.</p></details>
<footer>JavaScript arithmetic illustrates the declared filter contract; this page does not run DAX, load a PBIX, or verify Power BI visuals. Native model and filter evidence is required. No security bypass or universal ALLSELECTED equivalence is implied. Values are fictional counts; edited data is not saved.</footer>
</main><script>const $=id=>document.getElementById(id);const on=(id,e,fn)=>$(id).addEventListener(e,fn);const txt=(id,v)=>$(id).textContent=v;const esc=s=>String(s).replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));const positive=x=>String(x).trim()!==''&&Number.isFinite(Number(x))&&Number(x)>0;const num=x=>Number(x.toPrecision(10)).toString();function enter(id,fn){on(id,'keydown',e=>{if(e.key==='Enter'&&!e.isComposing&&e.keyCode!==229){e.preventDefault();fn()}})}function selectText(id){$(id).focus();$(id).select()}
let region='West',category='A',data=[3,1,2,4];
function shares(d,r,c){if(d.length!==4||d.some(x=>!Number.isFinite(x)||x<0))throw Error('Use four finite, nonnegative counts.');const selected=r==='West'?d.slice(0,2):r==='East'?d.slice(2):[d[0]+d[2],d[1]+d[3]];const denominator=selected[0]+selected[1],total=d.reduce((a,b)=>a+b,0),count=c==='Subtotal'?denominator:selected[c==='A'?0:1];if(!Number.isFinite(total))throw Error('Counts exceed the supported numeric range.');return {count,denominator,total,region:denominator===0?null:count/denominator,all:total===0?null:count/total}}
const percent=x=>x===null?'BLANK':Number((x*100).toFixed(4))+'%';
function render(){if(data===null)return;const s=shares(data,region,category);txt('region-share',percent(s.region));txt('all-share',percent(s.all));txt('region-trace',s.count+' ÷ '+s.denominator+' = '+(s.region===null?'Undefined: denominator is zero':s.region));txt('all-trace',s.count+' ÷ '+s.total+' = '+(s.all===null?'Undefined: denominator is zero':s.all));$('region-bar').style.width=(s.region===null?0:s.region*100)+'%';$('all-bar').style.width=(s.all===null?0:s.all*100)+'%';txt('context',region+' / '+(category==='Subtotal'?'Subtotal (no category-row filter)':'Category '+category));$('matrix').innerHTML=['A','B','Subtotal'].map(c=>{const x=shares(data,region,c);return '<tr'+(c===category?' class="active"':'')+'><th>'+c+'</th><td>'+x.count+'</td><td>'+x.denominator+'</td><td>'+percent(x.region)+'</td><td>'+x.total+'</td><td>'+percent(x.all)+'</td></tr>'}).join('');txt('bad-ratio',s.count?'Same-context counterexample: '+s.count+' ÷ '+s.count+' = 100%. This is not a share-of-total measure.':'Same-context counterexample: 0 ÷ 0 is BLANK, not 100%.');for(const [id,v]of [['west','West'],['east','East'],['all','All regions']])$(id).setAttribute('aria-pressed',String(region===v));for(const [id,v]of [['cat-a','A'],['cat-b','B'],['subtotal','Subtotal']])$(id).setAttribute('aria-pressed',String(category===v));txt('error','')}
function invalidate(){data=null;txt('region-share','Pending');txt('all-share','Pending');txt('region-trace','Apply current counts.');txt('all-trace','');$('matrix').innerHTML='';$('region-bar').style.width='0%';$('all-bar').style.width='0%';txt('bad-ratio','');txt('error','')}
function apply(){try{const values=['wa','wb','ea','eb'].map(id=>{if(!$(id).value.trim())throw Error('Fill all four counts; blank is not zero.');return Number($(id).value)});shares(values,region,category);data=values;txt('revision',values.join(',')==='3,1,2,4'?'R1 • original counts':values.every(x=>x===0)?'Z0 • separate all-zero fixture':'Edited fixture • new expectations');render()}catch(e){invalidate();txt('error',e.message)}}
for(const [id,v]of [['west','West'],['east','East'],['all','All regions']])on(id,'click',()=>{region=v;render()});for(const [id,v]of [['cat-a','A'],['cat-b','B'],['subtotal','Subtotal']])on(id,'click',()=>{category=v;render()});for(const id of ['wa','wb','ea','eb']){on(id,'input',invalidate);enter(id,apply)}on('apply','click',apply);on('zero','click',()=>{for(const id of ['wa','wb','ea','eb'])$(id).value='0';apply()});on('reset','click',()=>{['wa','wb','ea','eb'].forEach((id,i)=>$(id).value=String([3,1,2,4][i]));region='West';category='A';apply()});render();
</script></body></html>