@graphysdk/geom-boxplot 0.1.1-beta.1793705972988 → 0.1.1-beta.1793707591025

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -41,6 +41,7 @@ declare const DOT_VOCABULARY: {
41
41
  readonly alpha: "unitInterval";
42
42
  readonly size: "pixels";
43
43
  readonly strokeWidth: "pixels";
44
+ readonly symbol: "pointSymbol";
44
45
  };
45
46
  /** Named so the published types reach the observations and every part through `@graphysdk/react`, the package's one peer. */
46
47
  interface BoxplotStyleTarget extends GeomStyleTarget {
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});let s=require("@graphysdk/react"),W=require("react"),f=require("react/jsx-runtime");var x={q1:"boxplotQ1",median:"boxplotMedian",q3:"boxplotQ3",lowerWhisker:"boxplotLowerWhisker",upperWhisker:"boxplotUpperWhisker",count:"boxplotCount",mean:"boxplotMean",notchLower:"boxplotNotchLower",notchUpper:"boxplotNotchUpper",relativeWidth:"boxplotRelativeWidth",outlier:"boxplotOutlier"},B=e=>(e.start+e.end)/2,G=(e,t)=>{const r=t==="x"?(0,s.getXMin)(e):(0,s.getYMin)(e),o=t==="x"?(0,s.getXMax)(e):(0,s.getYMax)(e),n=t==="x"?(0,s.getYMin)(e):(0,s.getXMin)(e),a=t==="x"?(0,s.getYMax)(e):(0,s.getXMax)(e),i=(0,s.getScaledAesthetic)(e,"q1"),u=(0,s.getScaledAesthetic)(e,"median"),c=(0,s.getScaledAesthetic)(e,"q3");if(r===null||o===null||n===null||a===null||u===null||i===null||c===null)return null;const l=T(e,"notchLower"),d=T(e,"notchUpper"),[m,k]=ne(r,o,e);return{observation:e,start:m,end:k,lowerWhisker:n,q1:i,median:u,q3:c,upperWhisker:a,mean:T(e,"mean"),notch:l===null||d===null?null:{lower:l,upper:d}}},X=(e,t)=>{const r=t==="x"?(0,s.getXMin)(e):(0,s.getYMin)(e),o=t==="x"?(0,s.getXMax)(e):(0,s.getYMax)(e),n=(0,s.getScaledAesthetic)(e,"outlier");return r===null||o===null||n===null?null:{observation:e,band:B({start:r,end:o}),value:n}},S=(e,t)=>{const r=[],o=[];for(const n of e){const a=G(n,t);if(a!==null){r.push(a);continue}const i=X(n,t);i!==null&&o.push(i)}return{boxes:r,outliers:o}},T=(e,t)=>(0,s.getScaledAesthetic)(e,t)??null,ne=(e,t,r)=>{const o=r[x.relativeWidth];if(typeof o!="number")return[e,t];const n=(e+t)/2,a=(t-e)*o/2;return[n-a,n+a]},b=1.5,F=e=>e==="min-max"||typeof e=="number"&&Number.isFinite(e)&&e>=0,ae=1.58,se=(e,t)=>{if(e.length===0)return null;const r=[...e].sort((m,k)=>m-k),o=_(r,.25),n=_(r,.5),a=_(r,.75),i=t==="min-max"?1/0:t*(a-o),u=o-i,c=a+i,l=r.filter(m=>m>=u&&m<=c),d=ae*(a-o)/Math.sqrt(e.length);return{lowerWhisker:Math.min(l[0]??o,o),q1:o,median:n,q3:a,upperWhisker:Math.max(l[l.length-1]??a,a),count:e.length,mean:r.reduce((m,k)=>m+k,0)/r.length,notchLower:n-d,notchUpper:n+d}},_=(e,t)=>{const r=(e.length-1)*t,o=Math.floor(r),n=e[o]??0;return n+((e[o+1]??n)-n)*(r-o)},H={q1:x.q1,median:x.median,q3:x.q3,lowerWhisker:x.lowerWhisker,upperWhisker:x.upperWhisker,count:x.count,outlier:x.outlier},Y=new Set([...Object.keys(H),"mean","notchLower","notchUpper"]),ie=class extends s.Stat{constructor(...e){super(...e),this.type="boxplot",this.computedAesthetics=Y}computeStat({data:e,mapping:t,params:r}){const o=(0,s.readVariableName)(t.x),n=(0,s.readVariableName)(t.y);if(o===null||n===null||!e.hasVariable(o)||!e.hasVariable(n))return{data:e,mapping:{}};if(e.size()>0&&e.getType(n)!=="numeric"){const i=e.getType(n);throw new s.UserInputError({code:"INCOMPATIBLE_TYPE",message:`'boxplot' stat requires a numeric 'y' (got '${i}' for variable '${n}')`,context:{aesthetic:"y",variableName:n,variableType:i},suggestion:"Map the raw values to 'y', or summarised columns under stat 'identity'."})}const a=r?.extent;return{data:le({data:e,xVariable:o,yVariable:n,groupVariables:(0,s.getGroupVariables)(e,t).filter(i=>i!==o),extent:F(a)?a:b}),mapping:H}}},le=({data:e,xVariable:t,yVariable:r,groupVariables:o,extent:n})=>{const a=ue(e,t,r,o),i=e.getVariableNames(),u=new Map(i.map(p=>[p,e.getValues(p)])),c=new Map(i.map(p=>[p,[]])),l={q1:[],median:[],q3:[],lowerWhisker:[],upperWhisker:[],count:[],mean:[],notchLower:[],notchUpper:[],outlier:[]},d=[];for(const p of a){const v=se(p.values,n);if(v===null)continue;for(const h of i)c.get(h)?.push(ce(u.get(h)??[],p.indices));l.q1.push(v.q1),l.median.push(v.median),l.q3.push(v.q3),l.lowerWhisker.push(v.lowerWhisker),l.upperWhisker.push(v.upperWhisker),l.count.push(v.count),l.mean.push(v.mean),l.notchLower.push(v.notchLower),l.notchUpper.push(v.notchUpper),l.outlier.push(null);const w={low:v.lowerWhisker,high:v.upperWhisker};p.indices.forEach((h,y)=>{const M=p.values[y];M!==void 0&&(M<w.low||M>w.high)&&d.push({index:h,value:M})})}for(const{index:p,value:v}of d){for(const w of i)c.get(w)?.push(u.get(w)?.[p]??null);l.q1.push(null),l.median.push(null),l.q3.push(null),l.lowerWhisker.push(null),l.upperWhisker.push(null),l.count.push(null),l.mean.push(null),l.notchLower.push(null),l.notchUpper.push(null),l.outlier.push(v)}const m=e.getValueFormat(r),k=Object.fromEntries(i.map(p=>[p,{type:e.getType(p),values:c.get(p)??[],valueFormat:e.getValueFormat(p)}]));for(const[p,v]of Object.entries(l)){const w=x[p];k[w]=p==="count"?{type:"numeric",values:v}:{type:"numeric",values:v,valueFormat:m}}return new s.Dataset(k)},ue=(e,t,r,o)=>{const n=[t,...o].map(u=>e.getValues(u)),a=e.getValues(r,{type:"numeric"}),i=new Map;return a.forEach((u,c)=>{if(u===null||!Number.isFinite(u))return;const l=n.map(m=>V(m[c]??null)).join("\0"),d=i.get(l)??{indices:[],values:[]};d.indices.push(c),d.values.push(u),i.set(l,d)}),[...i.values()]},ce=(e,t)=>{const r=e[t[0]??-1]??null,o=V(r);return t.every(n=>V(e[n]??null)===o)?r:null},V=e=>e===null?"\0null":e instanceof Date?`date:${e.getTime()}`:`${typeof e}:${String(e)}`,z=.6,he=1,de=2,pe=1.5,me=7,ve=1,ge=7,fe=1.5,ke=["q1","median","q3"],ye={strokeWidth:"pixels"},q={stroke:"color",alpha:"unitInterval",strokeWidth:"pixels",dashArray:"dashArray"},C={fill:"color",fillAlpha:"unitInterval",stroke:"color",alpha:"unitInterval",size:"pixels",strokeWidth:"pixels"},Q=class extends s.Geom{constructor(...e){super(...e),this.type="boxplot",this.defaultParams={extent:b,outliers:!0,notch:!1,showMean:!1,varwidth:!1},this.defaultStat=new ie,this.derivedVariables=Object.values(x),this.positionRoles=[{axis:"x",role:"point",valueKind:"value"},{axis:"y",role:"min",valueKind:"value",aesthetic:"lowerWhisker"},{axis:"y",role:"max",valueKind:"value",aesthetic:"upperWhisker"},{axis:"y",role:"scalar",valueKind:"value",aesthetic:"q1"},{axis:"y",role:"scalar",valueKind:"value",aesthetic:"median"},{axis:"y",role:"scalar",valueKind:"value",aesthetic:"q3"},{axis:"y",role:"scalar",valueKind:"value",aesthetic:"outlier"},{axis:"y",role:"scalar",valueKind:"value",aesthetic:"mean"},{axis:"y",role:"scalar",valueKind:"value",aesthetic:"notchLower"},{axis:"y",role:"scalar",valueKind:"value",aesthetic:"notchUpper"}],this.aesthetics=[{kind:"visual",name:"color"},{kind:"data",name:"y"},{kind:"data",name:"count"}],this.defaultPosition="dodge",this.supportedPositions=["identity","dodge"],this.supportedCoordTypes=["cartesian","flip"],this.scaleConstraints={requireMainAxisBands:!0},this.legend={suppressWhenSingleItem:!0},this.spatialKind="rects",this.highlightStrategy="observationRerender",this.tooltip=[{key:"Upper whisker",aesthetic:"upperWhisker",optional:!0},{key:"Q3",aesthetic:"q3",optional:!0},{key:"Median",aesthetic:"median",optional:!0},{key:"Q1",aesthetic:"q1",optional:!0},{key:"Lower whisker",aesthetic:"lowerWhisker",optional:!0},{key:"Count",aesthetic:"count",optional:!0},{key:"Mean",aesthetic:"mean",optional:!0},{key:"Outlier",aesthetic:"outlier",optional:!0}],this.styleTarget=(0,s.defineGeomStyleTarget)({observation:{vocabulary:ye,aesthetics:{fill:"color"},rest:{fill:(0,s.token)("geom"),fillAlpha:1,stroke:(0,s.token)("geomBorder"),strokeWidth:he}},parts:{median:{vocabulary:q,rest:{stroke:(0,s.token)("graphBackground"),alpha:1,strokeWidth:de,dashArray:[]}},whisker:{vocabulary:q,aesthetics:{stroke:"color"},rest:{stroke:(0,s.token)("geom"),alpha:1,strokeWidth:pe,dashArray:[]}},cap:{vocabulary:q,aesthetics:{stroke:"color"},rest:{stroke:(0,s.token)("geom"),alpha:1,strokeWidth:0,dashArray:[]}},outlier:{vocabulary:C,aesthetics:{fill:"color"},rest:{fill:(0,s.token)("geom"),fillAlpha:1,stroke:(0,s.token)("graphBackground"),alpha:1,size:me,strokeWidth:ve}},mean:{vocabulary:C,aesthetics:{stroke:"color"},rest:{fill:(0,s.token)("graphBackground"),fillAlpha:1,stroke:(0,s.token)("geom"),alpha:1,size:ge,strokeWidth:fe}}}}),this.resolveBandFraction=t=>R(t),this.resolveValueSource=t=>t.median??{variable:x.median},this.validateMapping=({mapping:t,computedAesthetics:r})=>r.has("y")?[{code:"CONFLICTING_STAT_MAPPING",message:"boxplot geom draws a summary, not a single 'y'; use the 'boxplot' stat or 'identity'"}]:r.has("median")?[...[...Y].filter(o=>t[o]!==void 0).map(o=>({code:"CONFLICTING_STAT_MAPPING",message:`boxplot stat computes '${o}' from 'y'; remove its mapping, or set the layer's stat to 'identity'`})),...t.y===void 0?[{code:"MISSING_AESTHETIC",message:"boxplot stat summarises 'y'; map it to the raw values"}]:[]]:ke.filter(o=>t[o]===void 0).map(o=>({code:"MISSING_AESTHETIC",message:`boxplot geom requires '${o}' when its data is already summarised`,context:{aesthetic:o}})),this.resolveAnchorPosition=(t,{coordSystem:r})=>{const o=(0,s.readMainAxis)(r),n=xe(t,o);return n===null?null:o==="x"?{x:n.band,y:n.value}:{x:n.value,y:n.band}}}resolveParams(e){const{extent:t,width:r,...o}=super.resolveParams(e);return{...o,extent:this.resolveExtent(t,e.diagnostics),...this.resolveWidth(r,e.diagnostics)}}compile({data:e,mapping:t,params:r}){const o=P(e,t.lowerWhisker),n=P(e,t.upperWhisker);if(o===null||n===null)return{data:e,mapping:{}};const{outliers:a,notch:i,showMean:u,varwidth:c}=r,l=P(e,t.outlier),d=a===!1&&l!==null?We(e,l):e,m=P(d,t.count),k=R(r)/2;return{data:d.addVariable(x.relativeWidth,"numeric",c===!0&&m!==null?we(d,m):Me(d)).addVariable(s.POSITION_VARIABLES.yMin,"numeric",D(d,o,l)).addVariable(s.POSITION_VARIABLES.yMax,"numeric",D(d,n,l)).addConstantVariable(s.POSITION_VARIABLES.xMin,"numeric",-k).addConstantVariable(s.POSITION_VARIABLES.xMax,"numeric",k),mapping:{...t.y===void 0&&{y:t.median},...u===!0&&t.mean===void 0&&d.hasVariable(x.mean)&&{mean:x.mean},...i===!0&&t.notchLower===void 0&&d.hasVariable(x.notchLower)&&{notchLower:x.notchLower,notchUpper:x.notchUpper}}}}resolveExtent(e,t){return F(e)?e:(t?.addWarning({code:"INVALID_GEOM_PARAM",message:`Boxplot extent must be a non-negative number or 'min-max', got ${String(e)}; falling back to ${b}.`,context:{geom:this.type,param:"extent",expected:"extent >= 0 or 'min-max'",actual:String(e)},suggestion:"Set params.extent to a number of interquartile ranges, or 'min-max'."}),b)}resolveWidth(e,t){if(e===void 0)return{};const r=typeof e=="number"&&Number.isFinite(e)?e:null;if(r!==null&&r>0&&r<=1)return{width:r};const o=r!==null&&r>1?1:void 0;return t?.addWarning({code:"INVALID_GEOM_PARAM",message:`Boxplot width must be a fraction in (0, 1], got ${String(e)}; falling back to ${o??z}.`,context:{geom:this.type,param:"width",expected:"0 < width <= 1",actual:r??String(e)},suggestion:"Set params.width to a fraction of the category band in (0, 1]."}),o!==void 0?{width:o}:{}}},xe=(e,t)=>{const r=G(e,t);if(r!==null)return{band:B(r),value:r.median};const o=X(e,t);return o===null?null:{band:o.band,value:o.value}},R=({width:e})=>e??z,we=(e,t)=>{const r=e.getValues(t,{type:"numeric"}),o=Math.max(0,...r.map(n=>n??0));return r.map(n=>n===null||o===0?null:Math.sqrt(n/o))},Me=e=>Array.from({length:e.size()},()=>null),D=(e,t,r)=>{const o=r===null?[]:e.getValues(r,{type:"numeric"});return e.getValues(t,{type:"numeric"}).map((n,a)=>n??o[a]??null)},We=(e,t)=>{const r=e.getValues(t,{type:"numeric"});return e.take(r.flatMap((o,n)=>o===null?[n]:[]))},P=(e,t)=>{const r=(0,s.readVariableName)(t);return r!==null&&e.hasVariable(r)?r:null},Se=5e-4,Ie=.5,Oe=.5,Z=(e,t)=>{const r=(e.q1+e.q3)/2,o=Math.max(Math.abs(e.q3-e.q1),Se)/2,n=g(t,e.start,r-o),a=g(t,e.end,r+o),[i,u]=K(n.x,a.x),[c,l]=K(n.y,a.y);return{x:i,y:c,width:u-i,height:l-c}},J=(e,t)=>{if(e.notch===null)return null;const{lower:r,upper:o}=e.notch,[n,a]=te(e);return[g(t,e.start,e.q1),g(t,e.start,r),g(t,n,e.median),g(t,e.start,o),g(t,e.start,e.q3),g(t,e.end,e.q3),g(t,e.end,o),g(t,a,e.median),g(t,e.end,r),g(t,e.end,e.q1)]},Pe=(e,t)=>{const[r,o]=e.notch===null?[e.start,e.end]:te(e);return{from:g(t,r,e.median),to:g(t,o,e.median)}},ee=(e,t)=>e.mean===null?null:g(t,B(e),e.mean),te=e=>{const t=(e.end-e.start)*(1-Oe)/2;return[e.start+t,e.end-t]},re=(e,t)=>{const r=B(e),o=(e.end-e.start)*Ie/2;return[{side:"lower",quartile:e.q1,reach:e.lowerWhisker},{side:"upper",quartile:e.q3,reach:e.upperWhisker}].filter(({quartile:n,reach:a})=>n!==a).map(({side:n,quartile:a,reach:i})=>({side:n,stem:{from:g(t,r,a),to:g(t,r,i)},cap:{from:g(t,r-o,i),to:g(t,r+o,i)}}))},g=(e,t,r)=>{const o=(0,s.composePoint)(e,{main:t,cross:r});return{x:(0,s.toViewBoxX)(o.x),y:(0,s.toViewBoxY)(o.y)}},K=(e,t)=>e<=t?[e,t]:[t,e],O=(e,t)=>({x:e.x*t.width,y:e.y*t.height}),N=(e,t)=>`${e.map((r,o)=>{const{x:n,y:a}=O(r,t);return`${o===0?"M":"L"}${n},${a}`}).join("")}Z`,be=(e,t)=>N([{x:e.x,y:e.y},{x:e.x+e.width,y:e.y},{x:e.x+e.width,y:e.y+e.height},{x:e.x,y:e.y+e.height}],t),Be=(e,t)=>{const r=O(e.from,t),o=O(e.to,t);return`M${r.x},${r.y}L${o.x},${o.y}`},Ee=({layer:e,coordSystem:t,panelRect:r,styleReaders:o})=>{const n=(0,s.readMainAxis)(t),{boxes:a,outliers:i}=S(e.data,n),u=a.map(h=>{const y=J(h,n);return y!==null?{kind:"region",pathData:N(y,r)}:{kind:"region",pathData:be(Z(h,n),r)}}),c=o.part("whisker"),l=o.part("cap"),d=a.flatMap(h=>re(h,n).flatMap(y=>[{segment:y.stem,readers:c},{segment:y.cap,readers:l}].flatMap(({segment:M,readers:E})=>{const I=E?.get("strokeWidth",h.observation)??0;return I>0?[{kind:"stroke",pathData:Be(M,r),width:I}]:[]}))),m=o.part("outlier"),k=m===void 0?[]:i.map(h=>({center:O(g(n,h.band,h.value),r),size:j(m,h.observation)})),p=o.part("mean"),v=p===void 0?[]:a.flatMap(h=>{const y=ee(h,n);return y===null?[]:[{center:O(y,r),size:j(p,h.observation)}]}),w=(0,s.buildDotsEditOutlineShapes)([...k,...v]);return[...d,...u,...w]},j=(e,t)=>(e.get("size",t)??0)+(e.get("strokeWidth",t)??0),A=e=>{const t=(0,s.createStableKeyGenerator)(e.data,e.mapping,e.id),r=(0,s.readVariableName)(e.mapping.outlier),o=n=>`${t(n.observation)}-outlier-${String(r===null?n.value:n.observation[r])}`;return{readBoxKey:t,readOutlierKeys:n=>{const a=new Map;return n.map(i=>{const u=o(i),c=a.get(u)??0;return a.set(u,c+1),c===0?u:`${u}-${c}`})}}},Te=(e,t,r)=>{const o=e.data.getVariableNames(),n=i=>JSON.stringify(o.map(u=>i.observation[u]??null)),a=new Set(r.map(n));return t.filter(i=>a.has(n(i)))},oe=(e,t,r)=>{const o=new Set(t.map(n=>r(n.observation)));return e.filter(n=>o.has(r(n.observation)))},L=({boxes:e,outliers:t,mainAxis:r,panelSize:o,source:n,styleReaders:a,keys:i,hovered:u,animateTransitions:c=!1})=>{const l=u===void 0?void 0:"hovered",d=a.part("whisker"),m=a.part("cap"),k=a.part("median"),p=a.part("mean"),v=a.part("outlier"),w=i.readOutlierKeys(t);return(0,f.jsxs)(f.Fragment,{children:[e.flatMap(h=>re(h,r).flatMap(y=>[{piece:"stem",testId:"boxplot-whisker",readers:d},{piece:"cap",testId:"boxplot-cap",readers:m}].map(({piece:M,testId:E,readers:I})=>I===void 0?null:(0,f.jsx)(U,{testId:E,segment:y[M],observation:h.observation,readers:I,state:l,animateTransitions:c},`${i.readBoxKey(h.observation)}-${y.side}-${M}`)))),(0,f.jsx)(s.GeomOverpaint,{styleReaders:a,state:l,children:e.map(h=>(0,f.jsx)(_e,{box:h,mainAxis:r,panelSize:o,source:n,styleReaders:a,state:l,animateTransitions:c},i.readBoxKey(h.observation)))}),k&&e.map(h=>(0,f.jsx)(U,{testId:"boxplot-median",segment:Pe(h,r),observation:h.observation,readers:k,state:l,animateTransitions:c},i.readBoxKey(h.observation))),p&&e.map(h=>{const y=ee(h,r);return y===null?null:(0,f.jsx)($,{testId:"boxplot-mean",centre:y,observation:h.observation,readers:p,state:l,animateTransitions:c},i.readBoxKey(h.observation))}),v&&t.map((h,y)=>(0,f.jsx)($,{testId:"boxplot-outlier",centre:g(r,h.band,h.value),observation:h.observation,readers:v,state:l,animateTransitions:c},w[y]))]})},U=({testId:e,segment:t,observation:r,readers:o,state:n,animateTransitions:a})=>{const i=o.get("strokeWidth",r,n)??0,u=o.get("stroke",r,n);return(0,f.jsx)(s.GeomLine,{"data-testid":e,x1:(0,s.toPercent)(t.from.x),y1:(0,s.toPercent)(t.from.y),x2:(0,s.toPercent)(t.to.x),y2:(0,s.toPercent)(t.to.y),stroke:u===void 0?void 0:(0,s.toPaintColor)(u),strokeOpacity:o.get("alpha",r,n),strokeWidth:i,strokeDasharray:(0,s.toStrokeDasharray)(o.get("dashArray",r,n),i),animateTransitions:a})},_e=({box:e,mainAxis:t,panelSize:r,source:o,styleReaders:n,state:a,animateTransitions:i})=>{const u=n.get("fill",e.observation,a),c=n.get("stroke",e.observation,a),l={fill:u===void 0?void 0:(0,s.toPaintColor)(u),opacity:n.get("alpha",e.observation,a),fillOpacity:n.get("fillAlpha",e.observation,a),stroke:c===void 0?void 0:(0,s.toPaintColor)(c),strokeOpacity:n.get("strokeAlpha",e.observation,a),strokeWidth:n.get("strokeWidth",e.observation,a),effects:(0,s.readGeomEffects)(n,e.observation,a),animateTransitions:i},d=J(e,t);if(d!==null)return(0,f.jsx)(s.GeomPath,{"data-testid":"boxplot-box",d:N(d,r),source:o,...l});const m=Z(e,t);return(0,f.jsx)(s.GeomRect,{"data-testid":"boxplot-box",x:(0,s.toPercent)(m.x),y:(0,s.toPercent)(m.y),width:(0,s.toPercent)(m.width),height:(0,s.toPercent)(m.height),cornerRadius:n.get("cornerRadius",e.observation,a),...l})},$=({testId:e,centre:t,observation:r,readers:o,state:n,animateTransitions:a})=>{const i=o.get("fill",r,n),u=o.get("stroke",r,n);return(0,f.jsx)(s.GeomCircle,{"data-testid":e,cx:(0,s.toPercent)(t.x),cy:(0,s.toPercent)(t.y),r:(o.get("size",r,n)??0)/2,fill:i===void 0?void 0:(0,s.toPaintColor)(i),opacity:o.get("alpha",r,n),fillOpacity:o.get("fillAlpha",r,n),stroke:u===void 0?void 0:(0,s.toPaintColor)(u),strokeWidth:o.get("strokeWidth",r,n),animateTransitions:a})},qe=({layer:e,sourceLayer:t,mainAxis:r,panelSize:o,styleReaders:n})=>{const a=(0,W.useMemo)(()=>A(t),[t]),i=(0,W.useMemo)(()=>S(t.data,r).outliers,[t.data,r]),{boxes:u,outliers:c}=(0,W.useMemo)(()=>{const l=S(e.data,r),d=new Set(Te(t,i,l.outliers)),m=new Set(oe(i,l.boxes,a.readBoxKey)),k=i.filter(p=>m.has(p)||d.has(p));return{boxes:l.boxes,outliers:k}},[e.data,r,t,i,a]);return(0,f.jsx)(L,{boxes:u,outliers:c,mainAxis:r,panelSize:o,source:t,styleReaders:n,keys:a})},Ve=({layer:e,primary:t,mainAxis:r,panelSize:o,styleReaders:n})=>{const a=(0,W.useMemo)(()=>S(e.data,r).outliers,[e.data,r]),i=(0,W.useMemo)(()=>A(e),[e]),{boxes:u,outliers:c}=S([t.observation],r);return(0,f.jsx)("g",{"data-testid":"hovered-boxes",children:(0,f.jsx)(L,{boxes:u,outliers:u.length>0?oe(a,u,i.readBoxKey):c,mainAxis:r,panelSize:o,source:e,styleReaders:n,keys:i,hovered:t.observation})})},Ne=({layer:e,mainAxis:t,panelSize:r,styleReaders:o,animateTransitions:n,intro:a})=>{const{boxes:i,outliers:u}=(0,W.useMemo)(()=>S(e.data,t),[e.data,t]),c=(0,f.jsx)(L,{boxes:i,outliers:u,mainAxis:t,panelSize:r,source:e,styleReaders:o,keys:(0,W.useMemo)(()=>A(e),[e]),animateTransitions:n});return a==null?c:(0,f.jsx)(s.IntroFade,{intro:{type:"fade",layerId:a.layerId,durationSeconds:a.durationSeconds},children:c})},Ae=(0,s.defineGeomRenderer)(new Q,{coord:"cartesian",swatchShape:"square",overpaintPlacement:"manual",guideMode:"band",render:({layer:e,coordSystem:t,panelRect:r,styleReaders:o,animateTransitions:n,intro:a})=>(0,f.jsx)(Ne,{layer:e,mainAxis:(0,s.readMainAxis)(t),panelSize:r,styleReaders:o,animateTransitions:n,intro:a}),renderHighlight:({layer:e,sourceLayer:t,coordSystem:r,panelRect:o,styleReaders:n})=>(0,f.jsx)(qe,{layer:e,sourceLayer:t,mainAxis:(0,s.readMainAxis)(r),panelSize:o,styleReaders:n}),renderHover:({layer:e,primary:t,coordSystem:r,panelRect:o,styleReaders:n})=>(0,f.jsx)(Ve,{layer:e,primary:t,mainAxis:(0,s.readMainAxis)(r),panelSize:o,styleReaders:n}),renderHoverCompanions:()=>null,getEditOutlineShapes:Ee});exports.BOXPLOT_VARIABLES=x;exports.BoxplotGeom=Q;exports.boxplot=Ae;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});let s=require("@graphysdk/react"),S=require("react"),f=require("react/jsx-runtime");var x={q1:"boxplotQ1",median:"boxplotMedian",q3:"boxplotQ3",lowerWhisker:"boxplotLowerWhisker",upperWhisker:"boxplotUpperWhisker",count:"boxplotCount",mean:"boxplotMean",notchLower:"boxplotNotchLower",notchUpper:"boxplotNotchUpper",relativeWidth:"boxplotRelativeWidth",outlier:"boxplotOutlier"},B=e=>(e.start+e.end)/2,G=(e,t)=>{const r=t==="x"?(0,s.getXMin)(e):(0,s.getYMin)(e),o=t==="x"?(0,s.getXMax)(e):(0,s.getYMax)(e),n=t==="x"?(0,s.getYMin)(e):(0,s.getXMin)(e),a=t==="x"?(0,s.getYMax)(e):(0,s.getXMax)(e),l=(0,s.getScaledAesthetic)(e,"q1"),u=(0,s.getScaledAesthetic)(e,"median"),c=(0,s.getScaledAesthetic)(e,"q3");if(r===null||o===null||n===null||a===null||u===null||l===null||c===null)return null;const i=T(e,"notchLower"),d=T(e,"notchUpper"),[m,k]=ne(r,o,e);return{observation:e,start:m,end:k,lowerWhisker:n,q1:l,median:u,q3:c,upperWhisker:a,mean:T(e,"mean"),notch:i===null||d===null?null:{lower:i,upper:d}}},X=(e,t)=>{const r=t==="x"?(0,s.getXMin)(e):(0,s.getYMin)(e),o=t==="x"?(0,s.getXMax)(e):(0,s.getYMax)(e),n=(0,s.getScaledAesthetic)(e,"outlier");return r===null||o===null||n===null?null:{observation:e,band:B({start:r,end:o}),value:n}},W=(e,t)=>{const r=[],o=[];for(const n of e){const a=G(n,t);if(a!==null){r.push(a);continue}const l=X(n,t);l!==null&&o.push(l)}return{boxes:r,outliers:o}},T=(e,t)=>(0,s.getScaledAesthetic)(e,t)??null,ne=(e,t,r)=>{const o=r[x.relativeWidth];if(typeof o!="number")return[e,t];const n=(e+t)/2,a=(t-e)*o/2;return[n-a,n+a]},P=1.5,F=e=>e==="min-max"||typeof e=="number"&&Number.isFinite(e)&&e>=0,ae=1.58,se=(e,t)=>{if(e.length===0)return null;const r=[...e].sort((m,k)=>m-k),o=_(r,.25),n=_(r,.5),a=_(r,.75),l=t==="min-max"?1/0:t*(a-o),u=o-l,c=a+l,i=r.filter(m=>m>=u&&m<=c),d=ae*(a-o)/Math.sqrt(e.length);return{lowerWhisker:Math.min(i[0]??o,o),q1:o,median:n,q3:a,upperWhisker:Math.max(i[i.length-1]??a,a),count:e.length,mean:r.reduce((m,k)=>m+k,0)/r.length,notchLower:n-d,notchUpper:n+d}},_=(e,t)=>{const r=(e.length-1)*t,o=Math.floor(r),n=e[o]??0;return n+((e[o+1]??n)-n)*(r-o)},H={q1:x.q1,median:x.median,q3:x.q3,lowerWhisker:x.lowerWhisker,upperWhisker:x.upperWhisker,count:x.count,outlier:x.outlier},Y=new Set([...Object.keys(H),"mean","notchLower","notchUpper"]),le=class extends s.Stat{constructor(...e){super(...e),this.type="boxplot",this.computedAesthetics=Y}computeStat({data:e,mapping:t,params:r}){const o=(0,s.readVariableName)(t.x),n=(0,s.readVariableName)(t.y);if(o===null||n===null||!e.hasVariable(o)||!e.hasVariable(n))return{data:e,mapping:{}};if(e.size()>0&&e.getType(n)!=="numeric"){const l=e.getType(n);throw new s.UserInputError({code:"INCOMPATIBLE_TYPE",message:`'boxplot' stat requires a numeric 'y' (got '${l}' for variable '${n}')`,context:{aesthetic:"y",variableName:n,variableType:l},suggestion:"Map the raw values to 'y', or summarised columns under stat 'identity'."})}const a=r?.extent;return{data:ie({data:e,xVariable:o,yVariable:n,groupVariables:(0,s.getGroupVariables)(e,t).filter(l=>l!==o),extent:F(a)?a:P}),mapping:H}}},ie=({data:e,xVariable:t,yVariable:r,groupVariables:o,extent:n})=>{const a=ue(e,t,r,o),l=e.getVariableNames(),u=new Map(l.map(p=>[p,e.getValues(p)])),c=new Map(l.map(p=>[p,[]])),i={q1:[],median:[],q3:[],lowerWhisker:[],upperWhisker:[],count:[],mean:[],notchLower:[],notchUpper:[],outlier:[]},d=[];for(const p of a){const v=se(p.values,n);if(v===null)continue;for(const h of l)c.get(h)?.push(ce(u.get(h)??[],p.indices));i.q1.push(v.q1),i.median.push(v.median),i.q3.push(v.q3),i.lowerWhisker.push(v.lowerWhisker),i.upperWhisker.push(v.upperWhisker),i.count.push(v.count),i.mean.push(v.mean),i.notchLower.push(v.notchLower),i.notchUpper.push(v.notchUpper),i.outlier.push(null);const w={low:v.lowerWhisker,high:v.upperWhisker};p.indices.forEach((h,y)=>{const M=p.values[y];M!==void 0&&(M<w.low||M>w.high)&&d.push({index:h,value:M})})}for(const{index:p,value:v}of d){for(const w of l)c.get(w)?.push(u.get(w)?.[p]??null);i.q1.push(null),i.median.push(null),i.q3.push(null),i.lowerWhisker.push(null),i.upperWhisker.push(null),i.count.push(null),i.mean.push(null),i.notchLower.push(null),i.notchUpper.push(null),i.outlier.push(v)}const m=e.getValueFormat(r),k=Object.fromEntries(l.map(p=>[p,{type:e.getType(p),values:c.get(p)??[],valueFormat:e.getValueFormat(p)}]));for(const[p,v]of Object.entries(i)){const w=x[p];k[w]=p==="count"?{type:"numeric",values:v}:{type:"numeric",values:v,valueFormat:m}}return new s.Dataset(k)},ue=(e,t,r,o)=>{const n=[t,...o].map(u=>e.getValues(u)),a=e.getValues(r,{type:"numeric"}),l=new Map;return a.forEach((u,c)=>{if(u===null||!Number.isFinite(u))return;const i=n.map(m=>V(m[c]??null)).join("\0"),d=l.get(i)??{indices:[],values:[]};d.indices.push(c),d.values.push(u),l.set(i,d)}),[...l.values()]},ce=(e,t)=>{const r=e[t[0]??-1]??null,o=V(r);return t.every(n=>V(e[n]??null)===o)?r:null},V=e=>e===null?"\0null":e instanceof Date?`date:${e.getTime()}`:`${typeof e}:${String(e)}`,z=.6,he=1,de=2,pe=1.5,me=7,ve=1,ge=7,fe=1.5,ke=["q1","median","q3"],ye={strokeWidth:"pixels"},q={stroke:"color",alpha:"unitInterval",strokeWidth:"pixels",dashArray:"dashArray"},C={fill:"color",fillAlpha:"unitInterval",stroke:"color",alpha:"unitInterval",size:"pixels",strokeWidth:"pixels",symbol:"pointSymbol"},Q=class extends s.Geom{constructor(...e){super(...e),this.type="boxplot",this.defaultParams={extent:P,outliers:!0,notch:!1,showMean:!1,varwidth:!1},this.defaultStat=new le,this.derivedVariables=Object.values(x),this.positionRoles=[{axis:"x",role:"point",valueKind:"value"},{axis:"y",role:"min",valueKind:"value",aesthetic:"lowerWhisker"},{axis:"y",role:"max",valueKind:"value",aesthetic:"upperWhisker"},{axis:"y",role:"scalar",valueKind:"value",aesthetic:"q1"},{axis:"y",role:"scalar",valueKind:"value",aesthetic:"median"},{axis:"y",role:"scalar",valueKind:"value",aesthetic:"q3"},{axis:"y",role:"scalar",valueKind:"value",aesthetic:"outlier"},{axis:"y",role:"scalar",valueKind:"value",aesthetic:"mean"},{axis:"y",role:"scalar",valueKind:"value",aesthetic:"notchLower"},{axis:"y",role:"scalar",valueKind:"value",aesthetic:"notchUpper"}],this.aesthetics=[{kind:"visual",name:"color"},{kind:"data",name:"y"},{kind:"data",name:"count"}],this.defaultPosition="dodge",this.supportedPositions=["identity","dodge"],this.supportedCoordTypes=["cartesian","flip"],this.scaleConstraints={requireMainAxisBands:!0},this.legend={suppressWhenSingleItem:!0},this.spatialKind="rects",this.highlightStrategy="observationRerender",this.tooltip=[{key:"Upper whisker",aesthetic:"upperWhisker",optional:!0},{key:"Q3",aesthetic:"q3",optional:!0},{key:"Median",aesthetic:"median",optional:!0},{key:"Q1",aesthetic:"q1",optional:!0},{key:"Lower whisker",aesthetic:"lowerWhisker",optional:!0},{key:"Count",aesthetic:"count",optional:!0},{key:"Mean",aesthetic:"mean",optional:!0},{key:"Outlier",aesthetic:"outlier",optional:!0}],this.styleTarget=(0,s.defineGeomStyleTarget)({observation:{vocabulary:ye,aesthetics:{fill:"color"},rest:{fill:(0,s.token)("geom"),fillAlpha:1,stroke:(0,s.token)("geomBorder"),strokeWidth:he}},parts:{median:{vocabulary:q,rest:{stroke:(0,s.token)("graphBackground"),alpha:1,strokeWidth:de,dashArray:[]}},whisker:{vocabulary:q,aesthetics:{stroke:"color"},rest:{stroke:(0,s.token)("geom"),alpha:1,strokeWidth:pe,dashArray:[]}},cap:{vocabulary:q,aesthetics:{stroke:"color"},rest:{stroke:(0,s.token)("geom"),alpha:1,strokeWidth:0,dashArray:[]}},outlier:{vocabulary:C,aesthetics:{fill:"color"},rest:{fill:(0,s.token)("geom"),fillAlpha:1,stroke:(0,s.token)("graphBackground"),alpha:1,size:me,strokeWidth:ve}},mean:{vocabulary:C,aesthetics:{stroke:"color"},rest:{fill:(0,s.token)("graphBackground"),fillAlpha:1,stroke:(0,s.token)("geom"),alpha:1,size:ge,strokeWidth:fe}}}}),this.resolveBandFraction=t=>R(t),this.resolveValueSource=t=>t.median??{variable:x.median},this.validateMapping=({mapping:t,computedAesthetics:r})=>r.has("y")?[{code:"CONFLICTING_STAT_MAPPING",message:"boxplot geom draws a summary, not a single 'y'; use the 'boxplot' stat or 'identity'"}]:r.has("median")?[...[...Y].filter(o=>t[o]!==void 0).map(o=>({code:"CONFLICTING_STAT_MAPPING",message:`boxplot stat computes '${o}' from 'y'; remove its mapping, or set the layer's stat to 'identity'`})),...t.y===void 0?[{code:"MISSING_AESTHETIC",message:"boxplot stat summarises 'y'; map it to the raw values"}]:[]]:ke.filter(o=>t[o]===void 0).map(o=>({code:"MISSING_AESTHETIC",message:`boxplot geom requires '${o}' when its data is already summarised`,context:{aesthetic:o}})),this.resolveAnchorPosition=(t,{coordSystem:r})=>{const o=(0,s.readMainAxis)(r),n=xe(t,o);return n===null?null:o==="x"?{x:n.band,y:n.value}:{x:n.value,y:n.band}}}resolveParams(e){const{extent:t,width:r,...o}=super.resolveParams(e);return{...o,extent:this.resolveExtent(t,e.diagnostics),...this.resolveWidth(r,e.diagnostics)}}compile({data:e,mapping:t,params:r}){const o=b(e,t.lowerWhisker),n=b(e,t.upperWhisker);if(o===null||n===null)return{data:e,mapping:{}};const{outliers:a,notch:l,showMean:u,varwidth:c}=r,i=b(e,t.outlier),d=a===!1&&i!==null?Se(e,i):e,m=b(d,t.count),k=R(r)/2;return{data:d.addVariable(x.relativeWidth,"numeric",c===!0&&m!==null?we(d,m):Me(d)).addVariable(s.POSITION_VARIABLES.yMin,"numeric",D(d,o,i)).addVariable(s.POSITION_VARIABLES.yMax,"numeric",D(d,n,i)).addConstantVariable(s.POSITION_VARIABLES.xMin,"numeric",-k).addConstantVariable(s.POSITION_VARIABLES.xMax,"numeric",k),mapping:{...t.y===void 0&&{y:t.median},...u===!0&&t.mean===void 0&&d.hasVariable(x.mean)&&{mean:x.mean},...l===!0&&t.notchLower===void 0&&d.hasVariable(x.notchLower)&&{notchLower:x.notchLower,notchUpper:x.notchUpper}}}}resolveExtent(e,t){return F(e)?e:(t?.addWarning({code:"INVALID_GEOM_PARAM",message:`Boxplot extent must be a non-negative number or 'min-max', got ${String(e)}; falling back to ${P}.`,context:{geom:this.type,param:"extent",expected:"extent >= 0 or 'min-max'",actual:String(e)},suggestion:"Set params.extent to a number of interquartile ranges, or 'min-max'."}),P)}resolveWidth(e,t){if(e===void 0)return{};const r=typeof e=="number"&&Number.isFinite(e)?e:null;if(r!==null&&r>0&&r<=1)return{width:r};const o=r!==null&&r>1?1:void 0;return t?.addWarning({code:"INVALID_GEOM_PARAM",message:`Boxplot width must be a fraction in (0, 1], got ${String(e)}; falling back to ${o??z}.`,context:{geom:this.type,param:"width",expected:"0 < width <= 1",actual:r??String(e)},suggestion:"Set params.width to a fraction of the category band in (0, 1]."}),o!==void 0?{width:o}:{}}},xe=(e,t)=>{const r=G(e,t);if(r!==null)return{band:B(r),value:r.median};const o=X(e,t);return o===null?null:{band:o.band,value:o.value}},R=({width:e})=>e??z,we=(e,t)=>{const r=e.getValues(t,{type:"numeric"}),o=Math.max(0,...r.map(n=>n??0));return r.map(n=>n===null||o===0?null:Math.sqrt(n/o))},Me=e=>Array.from({length:e.size()},()=>null),D=(e,t,r)=>{const o=r===null?[]:e.getValues(r,{type:"numeric"});return e.getValues(t,{type:"numeric"}).map((n,a)=>n??o[a]??null)},Se=(e,t)=>{const r=e.getValues(t,{type:"numeric"});return e.take(r.flatMap((o,n)=>o===null?[n]:[]))},b=(e,t)=>{const r=(0,s.readVariableName)(t);return r!==null&&e.hasVariable(r)?r:null},We=5e-4,Ie=.5,Oe=.5,Z=(e,t)=>{const r=(e.q1+e.q3)/2,o=Math.max(Math.abs(e.q3-e.q1),We)/2,n=g(t,e.start,r-o),a=g(t,e.end,r+o),[l,u]=K(n.x,a.x),[c,i]=K(n.y,a.y);return{x:l,y:c,width:u-l,height:i-c}},J=(e,t)=>{if(e.notch===null)return null;const{lower:r,upper:o}=e.notch,[n,a]=te(e);return[g(t,e.start,e.q1),g(t,e.start,r),g(t,n,e.median),g(t,e.start,o),g(t,e.start,e.q3),g(t,e.end,e.q3),g(t,e.end,o),g(t,a,e.median),g(t,e.end,r),g(t,e.end,e.q1)]},be=(e,t)=>{const[r,o]=e.notch===null?[e.start,e.end]:te(e);return{from:g(t,r,e.median),to:g(t,o,e.median)}},ee=(e,t)=>e.mean===null?null:g(t,B(e),e.mean),te=e=>{const t=(e.end-e.start)*(1-Oe)/2;return[e.start+t,e.end-t]},re=(e,t)=>{const r=B(e),o=(e.end-e.start)*Ie/2;return[{side:"lower",quartile:e.q1,reach:e.lowerWhisker},{side:"upper",quartile:e.q3,reach:e.upperWhisker}].filter(({quartile:n,reach:a})=>n!==a).map(({side:n,quartile:a,reach:l})=>({side:n,stem:{from:g(t,r,a),to:g(t,r,l)},cap:{from:g(t,r-o,l),to:g(t,r+o,l)}}))},g=(e,t,r)=>{const o=(0,s.composePoint)(e,{main:t,cross:r});return{x:(0,s.toViewBoxX)(o.x),y:(0,s.toViewBoxY)(o.y)}},K=(e,t)=>e<=t?[e,t]:[t,e],O=(e,t)=>({x:e.x*t.width,y:e.y*t.height}),N=(e,t)=>`${e.map((r,o)=>{const{x:n,y:a}=O(r,t);return`${o===0?"M":"L"}${n},${a}`}).join("")}Z`,Pe=(e,t)=>N([{x:e.x,y:e.y},{x:e.x+e.width,y:e.y},{x:e.x+e.width,y:e.y+e.height},{x:e.x,y:e.y+e.height}],t),Be=(e,t)=>{const r=O(e.from,t),o=O(e.to,t);return`M${r.x},${r.y}L${o.x},${o.y}`},Ee=({layer:e,coordSystem:t,panelRect:r,styleReaders:o})=>{const n=(0,s.readMainAxis)(t),{boxes:a,outliers:l}=W(e.data,n),u=a.map(h=>{const y=J(h,n);return y!==null?{kind:"region",pathData:N(y,r)}:{kind:"region",pathData:Pe(Z(h,n),r)}}),c=o.part("whisker"),i=o.part("cap"),d=a.flatMap(h=>re(h,n).flatMap(y=>[{segment:y.stem,readers:c},{segment:y.cap,readers:i}].flatMap(({segment:M,readers:E})=>{const I=E?.get("strokeWidth",h.observation)??0;return I>0?[{kind:"stroke",pathData:Be(M,r),width:I}]:[]}))),m=o.part("outlier"),k=m===void 0?[]:l.map(h=>({center:O(g(n,h.band,h.value),r),size:j(m,h.observation)})),p=o.part("mean"),v=p===void 0?[]:a.flatMap(h=>{const y=ee(h,n);return y===null?[]:[{center:O(y,r),size:j(p,h.observation)}]}),w=(0,s.buildDotsEditOutlineShapes)([...k,...v]);return[...d,...u,...w]},j=(e,t)=>(e.get("size",t)??0)+(e.get("strokeWidth",t)??0),A=e=>{const t=(0,s.createStableKeyGenerator)(e.data,e.mapping,e.id),r=(0,s.readVariableName)(e.mapping.outlier),o=n=>`${t(n.observation)}-outlier-${String(r===null?n.value:n.observation[r])}`;return{readBoxKey:t,readOutlierKeys:n=>{const a=new Map;return n.map(l=>{const u=o(l),c=a.get(u)??0;return a.set(u,c+1),c===0?u:`${u}-${c}`})}}},Te=(e,t,r)=>{const o=e.data.getVariableNames(),n=l=>JSON.stringify(o.map(u=>l.observation[u]??null)),a=new Set(r.map(n));return t.filter(l=>a.has(n(l)))},oe=(e,t,r)=>{const o=new Set(t.map(n=>r(n.observation)));return e.filter(n=>o.has(r(n.observation)))},L=({boxes:e,outliers:t,mainAxis:r,panelSize:o,source:n,styleReaders:a,keys:l,hovered:u,animateTransitions:c=!1})=>{const i=u===void 0?void 0:"hovered",d=a.part("whisker"),m=a.part("cap"),k=a.part("median"),p=a.part("mean"),v=a.part("outlier"),w=l.readOutlierKeys(t);return(0,f.jsxs)(f.Fragment,{children:[e.flatMap(h=>re(h,r).flatMap(y=>[{piece:"stem",testId:"boxplot-whisker",readers:d},{piece:"cap",testId:"boxplot-cap",readers:m}].map(({piece:M,testId:E,readers:I})=>I===void 0?null:(0,f.jsx)(U,{testId:E,segment:y[M],observation:h.observation,readers:I,state:i,animateTransitions:c},`${l.readBoxKey(h.observation)}-${y.side}-${M}`)))),(0,f.jsx)(s.GeomOverpaint,{styleReaders:a,state:i,children:e.map(h=>(0,f.jsx)(_e,{box:h,mainAxis:r,panelSize:o,source:n,styleReaders:a,state:i,animateTransitions:c},l.readBoxKey(h.observation)))}),k&&e.map(h=>(0,f.jsx)(U,{testId:"boxplot-median",segment:be(h,r),observation:h.observation,readers:k,state:i,animateTransitions:c},l.readBoxKey(h.observation))),p&&e.map(h=>{const y=ee(h,r);return y===null?null:(0,f.jsx)($,{testId:"boxplot-mean",centre:y,observation:h.observation,readers:p,state:i,animateTransitions:c},l.readBoxKey(h.observation))}),v&&t.map((h,y)=>(0,f.jsx)($,{testId:"boxplot-outlier",centre:g(r,h.band,h.value),observation:h.observation,readers:v,state:i,animateTransitions:c},w[y]))]})},U=({testId:e,segment:t,observation:r,readers:o,state:n,animateTransitions:a})=>{const l=o.get("strokeWidth",r,n)??0,u=o.get("stroke",r,n);return(0,f.jsx)(s.GeomLine,{"data-testid":e,x1:(0,s.toPercent)(t.from.x),y1:(0,s.toPercent)(t.from.y),x2:(0,s.toPercent)(t.to.x),y2:(0,s.toPercent)(t.to.y),stroke:u===void 0?void 0:(0,s.toPaintColor)(u),strokeOpacity:o.get("alpha",r,n),strokeWidth:l,strokeDasharray:(0,s.toStrokeDasharray)(o.get("dashArray",r,n),l),animateTransitions:a})},_e=({box:e,mainAxis:t,panelSize:r,source:o,styleReaders:n,state:a,animateTransitions:l})=>{const u=n.get("fill",e.observation,a),c=n.get("stroke",e.observation,a),i={fill:u===void 0?void 0:(0,s.toPaintColor)(u),opacity:n.get("alpha",e.observation,a),fillOpacity:n.get("fillAlpha",e.observation,a),stroke:c===void 0?void 0:(0,s.toPaintColor)(c),strokeOpacity:n.get("strokeAlpha",e.observation,a),strokeWidth:n.get("strokeWidth",e.observation,a),effects:(0,s.readGeomEffects)(n,e.observation,a),animateTransitions:l},d=J(e,t);if(d!==null)return(0,f.jsx)(s.GeomPath,{"data-testid":"boxplot-box",d:N(d,r),source:o,...i});const m=Z(e,t);return(0,f.jsx)(s.GeomRect,{"data-testid":"boxplot-box",x:(0,s.toPercent)(m.x),y:(0,s.toPercent)(m.y),width:(0,s.toPercent)(m.width),height:(0,s.toPercent)(m.height),cornerRadius:n.get("cornerRadius",e.observation,a),...i})},$=({testId:e,centre:t,observation:r,readers:o,state:n,animateTransitions:a})=>{const l=o.get("fill",r,n),u=o.get("stroke",r,n);return(0,f.jsx)(s.GeomCircle,{"data-testid":e,cx:(0,s.toPercent)(t.x),cy:(0,s.toPercent)(t.y),r:(o.get("size",r,n)??0)/2,fill:l===void 0?void 0:(0,s.toPaintColor)(l),opacity:o.get("alpha",r,n),fillOpacity:o.get("fillAlpha",r,n),stroke:u===void 0?void 0:(0,s.toPaintColor)(u),strokeWidth:o.get("strokeWidth",r,n),symbol:o.get("symbol",r,n),animateTransitions:a})},qe=({layer:e,sourceLayer:t,mainAxis:r,panelSize:o,styleReaders:n})=>{const a=(0,S.useMemo)(()=>A(t),[t]),l=(0,S.useMemo)(()=>W(t.data,r).outliers,[t.data,r]),{boxes:u,outliers:c}=(0,S.useMemo)(()=>{const i=W(e.data,r),d=new Set(Te(t,l,i.outliers)),m=new Set(oe(l,i.boxes,a.readBoxKey)),k=l.filter(p=>m.has(p)||d.has(p));return{boxes:i.boxes,outliers:k}},[e.data,r,t,l,a]);return(0,f.jsx)(L,{boxes:u,outliers:c,mainAxis:r,panelSize:o,source:t,styleReaders:n,keys:a})},Ve=({layer:e,primary:t,mainAxis:r,panelSize:o,styleReaders:n})=>{const a=(0,S.useMemo)(()=>W(e.data,r).outliers,[e.data,r]),l=(0,S.useMemo)(()=>A(e),[e]),{boxes:u,outliers:c}=W([t.observation],r);return(0,f.jsx)("g",{"data-testid":"hovered-boxes",children:(0,f.jsx)(L,{boxes:u,outliers:u.length>0?oe(a,u,l.readBoxKey):c,mainAxis:r,panelSize:o,source:e,styleReaders:n,keys:l,hovered:t.observation})})},Ne=({layer:e,mainAxis:t,panelSize:r,styleReaders:o,animateTransitions:n,intro:a})=>{const{boxes:l,outliers:u}=(0,S.useMemo)(()=>W(e.data,t),[e.data,t]),c=(0,f.jsx)(L,{boxes:l,outliers:u,mainAxis:t,panelSize:r,source:e,styleReaders:o,keys:(0,S.useMemo)(()=>A(e),[e]),animateTransitions:n});return a==null?c:(0,f.jsx)(s.IntroFade,{intro:{type:"fade",layerId:a.layerId,durationSeconds:a.durationSeconds},children:c})},Ae=(0,s.defineGeomRenderer)(new Q,{coord:"cartesian",swatchShape:"square",overpaintPlacement:"manual",guideMode:"band",render:({layer:e,coordSystem:t,panelRect:r,styleReaders:o,animateTransitions:n,intro:a})=>(0,f.jsx)(Ne,{layer:e,mainAxis:(0,s.readMainAxis)(t),panelSize:r,styleReaders:o,animateTransitions:n,intro:a}),renderHighlight:({layer:e,sourceLayer:t,coordSystem:r,panelRect:o,styleReaders:n})=>(0,f.jsx)(qe,{layer:e,sourceLayer:t,mainAxis:(0,s.readMainAxis)(r),panelSize:o,styleReaders:n}),renderHover:({layer:e,primary:t,coordSystem:r,panelRect:o,styleReaders:n})=>(0,f.jsx)(Ve,{layer:e,primary:t,mainAxis:(0,s.readMainAxis)(r),panelSize:o,styleReaders:n}),renderHoverCompanions:()=>null,getEditOutlineShapes:Ee});exports.BOXPLOT_VARIABLES=x;exports.BoxplotGeom=Q;exports.boxplot=Ae;
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
- import { Dataset as pe, Geom as me, GeomCircle as ve, GeomLine as ge, GeomOverpaint as fe, GeomPath as ke, GeomRect as ye, IntroFade as we, POSITION_VARIABLES as _, Stat as xe, UserInputError as We, buildDotsEditOutlineShapes as Me, composePoint as Se, createStableKeyGenerator as Ie, defineGeomRenderer as Oe, defineGeomStyleTarget as be, getGroupVariables as Ee, getScaledAesthetic as b, getXMax as A, getXMin as K, getYMax as U, getYMin as $, readGeomEffects as Be, readMainAxis as E, readVariableName as V, toPaintColor as B, toPercent as x, toStrokeDasharray as Te, toViewBoxX as _e, toViewBoxY as qe, token as M } from "@graphysdk/react";
1
+ import { Dataset as pe, Geom as me, GeomCircle as ve, GeomLine as ge, GeomOverpaint as fe, GeomPath as ye, GeomRect as ke, IntroFade as we, POSITION_VARIABLES as _, Stat as xe, UserInputError as We, buildDotsEditOutlineShapes as Me, composePoint as Se, createStableKeyGenerator as Ie, defineGeomRenderer as Oe, defineGeomStyleTarget as be, getGroupVariables as Ee, getScaledAesthetic as b, getXMax as A, getXMin as K, getYMax as U, getYMin as $, readGeomEffects as Be, readMainAxis as E, readVariableName as V, toPaintColor as B, toPercent as x, toStrokeDasharray as Te, toViewBoxX as _e, toViewBoxY as qe, token as M } from "@graphysdk/react";
2
2
  import { useMemo as S } from "react";
3
- import { Fragment as Pe, jsx as k, jsxs as Ve } from "react/jsx-runtime";
4
- var y = {
3
+ import { Fragment as Pe, jsx as y, jsxs as Ve } from "react/jsx-runtime";
4
+ var k = {
5
5
  q1: "boxplotQ1",
6
6
  median: "boxplotMedian",
7
7
  q3: "boxplotQ3",
@@ -58,7 +58,7 @@ var y = {
58
58
  outliers: o
59
59
  };
60
60
  }, L = (e, t) => b(e, t) ?? null, Ne = (e, t, r) => {
61
- const o = r[y.relativeWidth];
61
+ const o = r[k.relativeWidth];
62
62
  if (typeof o != "number") return [e, t];
63
63
  const n = (e + t) / 2, a = (t - e) * o / 2;
64
64
  return [n - a, n + a];
@@ -80,13 +80,13 @@ var y = {
80
80
  const r = (e.length - 1) * t, o = Math.floor(r), n = e[o] ?? 0;
81
81
  return n + ((e[o + 1] ?? n) - n) * (r - o);
82
82
  }, ne = {
83
- q1: y.q1,
84
- median: y.median,
85
- q3: y.q3,
86
- lowerWhisker: y.lowerWhisker,
87
- upperWhisker: y.upperWhisker,
88
- count: y.count,
89
- outlier: y.outlier
83
+ q1: k.q1,
84
+ median: k.median,
85
+ q3: k.q3,
86
+ lowerWhisker: k.lowerWhisker,
87
+ upperWhisker: k.upperWhisker,
88
+ count: k.count,
89
+ outlier: k.outlier
90
90
  }, ae = /* @__PURE__ */ new Set([
91
91
  ...Object.keys(ne),
92
92
  "mean",
@@ -167,7 +167,7 @@ var y = {
167
167
  valueFormat: e.getValueFormat(d)
168
168
  }]));
169
169
  for (const [d, m] of Object.entries(l)) {
170
- const w = y[d];
170
+ const w = k[d];
171
171
  g[w] = d === "count" ? {
172
172
  type: "numeric",
173
173
  values: m
@@ -206,7 +206,8 @@ var y = {
206
206
  stroke: "color",
207
207
  alpha: "unitInterval",
208
208
  size: "pixels",
209
- strokeWidth: "pixels"
209
+ strokeWidth: "pixels",
210
+ symbol: "pointSymbol"
210
211
  }, Qe = class extends me {
211
212
  constructor(...e) {
212
213
  super(...e), this.type = "boxplot", this.defaultParams = {
@@ -215,7 +216,7 @@ var y = {
215
216
  notch: !1,
216
217
  showMean: !1,
217
218
  varwidth: !1
218
- }, this.defaultStat = new De(), this.derivedVariables = Object.values(y), this.positionRoles = [
219
+ }, this.defaultStat = new De(), this.derivedVariables = Object.values(k), this.positionRoles = [
219
220
  {
220
221
  axis: "x",
221
222
  role: "point",
@@ -395,7 +396,7 @@ var y = {
395
396
  }
396
397
  }
397
398
  }
398
- }), this.resolveBandFraction = (t) => Y(t), this.resolveValueSource = (t) => t.median ?? { variable: y.median }, this.validateMapping = ({ mapping: t, computedAesthetics: r }) => r.has("y") ? [{
399
+ }), this.resolveBandFraction = (t) => Y(t), this.resolveValueSource = (t) => t.median ?? { variable: k.median }, this.validateMapping = ({ mapping: t, computedAesthetics: r }) => r.has("y") ? [{
399
400
  code: "CONFLICTING_STAT_MAPPING",
400
401
  message: "boxplot geom draws a summary, not a single 'y'; use the 'boxplot' stat or 'identity'"
401
402
  }] : r.has("median") ? [...[...ae].filter((o) => t[o] !== void 0).map((o) => ({
@@ -435,13 +436,13 @@ var y = {
435
436
  };
436
437
  const { outliers: a, notch: s, showMean: i, varwidth: u } = r, l = q(e, t.outlier), h = a === !1 && l !== null ? tt(e, l) : e, p = q(h, t.count), g = Y(r) / 2;
437
438
  return {
438
- data: h.addVariable(y.relativeWidth, "numeric", u === !0 && p !== null ? Je(h, p) : et(h)).addVariable(_.yMin, "numeric", j(h, o, l)).addVariable(_.yMax, "numeric", j(h, n, l)).addConstantVariable(_.xMin, "numeric", -g).addConstantVariable(_.xMax, "numeric", g),
439
+ data: h.addVariable(k.relativeWidth, "numeric", u === !0 && p !== null ? Je(h, p) : et(h)).addVariable(_.yMin, "numeric", j(h, o, l)).addVariable(_.yMax, "numeric", j(h, n, l)).addConstantVariable(_.xMin, "numeric", -g).addConstantVariable(_.xMax, "numeric", g),
439
440
  mapping: {
440
441
  ...t.y === void 0 && { y: t.median },
441
- ...i === !0 && t.mean === void 0 && h.hasVariable(y.mean) && { mean: y.mean },
442
- ...s === !0 && t.notchLower === void 0 && h.hasVariable(y.notchLower) && {
443
- notchLower: y.notchLower,
444
- notchUpper: y.notchUpper
442
+ ...i === !0 && t.mean === void 0 && h.hasVariable(k.mean) && { mean: k.mean },
443
+ ...s === !0 && t.notchLower === void 0 && h.hasVariable(k.notchLower) && {
444
+ notchLower: k.notchLower,
445
+ notchUpper: k.notchUpper
445
446
  }
446
447
  }
447
448
  };
@@ -654,7 +655,7 @@ var y = {
654
655
  piece: "cap",
655
656
  testId: "boxplot-cap",
656
657
  readers: p
657
- }].map(({ piece: W, testId: C, readers: O }) => O === void 0 ? null : /* @__PURE__ */ k(J, {
658
+ }].map(({ piece: W, testId: C, readers: O }) => O === void 0 ? null : /* @__PURE__ */ y(J, {
658
659
  testId: C,
659
660
  segment: f[W],
660
661
  observation: c.observation,
@@ -662,10 +663,10 @@ var y = {
662
663
  state: l,
663
664
  animateTransitions: u
664
665
  }, `${s.readBoxKey(c.observation)}-${f.side}-${W}`)))),
665
- /* @__PURE__ */ k(fe, {
666
+ /* @__PURE__ */ y(fe, {
666
667
  styleReaders: a,
667
668
  state: l,
668
- children: e.map((c) => /* @__PURE__ */ k(ct, {
669
+ children: e.map((c) => /* @__PURE__ */ y(ct, {
669
670
  box: c,
670
671
  mainAxis: r,
671
672
  panelSize: o,
@@ -675,7 +676,7 @@ var y = {
675
676
  animateTransitions: u
676
677
  }, s.readBoxKey(c.observation)))
677
678
  }),
678
- g && e.map((c) => /* @__PURE__ */ k(J, {
679
+ g && e.map((c) => /* @__PURE__ */ y(J, {
679
680
  testId: "boxplot-median",
680
681
  segment: at(c, r),
681
682
  observation: c.observation,
@@ -685,7 +686,7 @@ var y = {
685
686
  }, s.readBoxKey(c.observation))),
686
687
  d && e.map((c) => {
687
688
  const f = ue(c, r);
688
- return f === null ? null : /* @__PURE__ */ k(ee, {
689
+ return f === null ? null : /* @__PURE__ */ y(ee, {
689
690
  testId: "boxplot-mean",
690
691
  centre: f,
691
692
  observation: c.observation,
@@ -694,7 +695,7 @@ var y = {
694
695
  animateTransitions: u
695
696
  }, s.readBoxKey(c.observation));
696
697
  }),
697
- m && t.map((c, f) => /* @__PURE__ */ k(ee, {
698
+ m && t.map((c, f) => /* @__PURE__ */ y(ee, {
698
699
  testId: "boxplot-outlier",
699
700
  centre: v(r, c.band, c.value),
700
701
  observation: c.observation,
@@ -705,7 +706,7 @@ var y = {
705
706
  ] });
706
707
  }, J = ({ testId: e, segment: t, observation: r, readers: o, state: n, animateTransitions: a }) => {
707
708
  const s = o.get("strokeWidth", r, n) ?? 0, i = o.get("stroke", r, n);
708
- return /* @__PURE__ */ k(ge, {
709
+ return /* @__PURE__ */ y(ge, {
709
710
  "data-testid": e,
710
711
  x1: x(t.from.x),
711
712
  y1: x(t.from.y),
@@ -728,14 +729,14 @@ var y = {
728
729
  effects: Be(n, e.observation, a),
729
730
  animateTransitions: s
730
731
  }, h = ie(e, t);
731
- if (h !== null) return /* @__PURE__ */ k(ke, {
732
+ if (h !== null) return /* @__PURE__ */ y(ye, {
732
733
  "data-testid": "boxplot-box",
733
734
  d: F(h, r),
734
735
  source: o,
735
736
  ...l
736
737
  });
737
738
  const p = le(e, t);
738
- return /* @__PURE__ */ k(ye, {
739
+ return /* @__PURE__ */ y(ke, {
739
740
  "data-testid": "boxplot-box",
740
741
  x: x(p.x),
741
742
  y: x(p.y),
@@ -746,7 +747,7 @@ var y = {
746
747
  });
747
748
  }, ee = ({ testId: e, centre: t, observation: r, readers: o, state: n, animateTransitions: a }) => {
748
749
  const s = o.get("fill", r, n), i = o.get("stroke", r, n);
749
- return /* @__PURE__ */ k(ve, {
750
+ return /* @__PURE__ */ y(ve, {
750
751
  "data-testid": e,
751
752
  cx: x(t.x),
752
753
  cy: x(t.y),
@@ -756,6 +757,7 @@ var y = {
756
757
  fillOpacity: o.get("fillAlpha", r, n),
757
758
  stroke: i === void 0 ? void 0 : B(i),
758
759
  strokeWidth: o.get("strokeWidth", r, n),
760
+ symbol: o.get("symbol", r, n),
759
761
  animateTransitions: a
760
762
  });
761
763
  }, ht = ({ layer: e, sourceLayer: t, mainAxis: r, panelSize: o, styleReaders: n }) => {
@@ -772,7 +774,7 @@ var y = {
772
774
  s,
773
775
  a
774
776
  ]);
775
- return /* @__PURE__ */ k(X, {
777
+ return /* @__PURE__ */ y(X, {
776
778
  boxes: i,
777
779
  outliers: u,
778
780
  mainAxis: r,
@@ -783,9 +785,9 @@ var y = {
783
785
  });
784
786
  }, dt = ({ layer: e, primary: t, mainAxis: r, panelSize: o, styleReaders: n }) => {
785
787
  const a = S(() => I(e.data, r).outliers, [e.data, r]), s = S(() => H(e), [e]), { boxes: i, outliers: u } = I([t.observation], r);
786
- return /* @__PURE__ */ k("g", {
788
+ return /* @__PURE__ */ y("g", {
787
789
  "data-testid": "hovered-boxes",
788
- children: /* @__PURE__ */ k(X, {
790
+ children: /* @__PURE__ */ y(X, {
789
791
  boxes: i,
790
792
  outliers: i.length > 0 ? de(a, i, s.readBoxKey) : u,
791
793
  mainAxis: r,
@@ -797,7 +799,7 @@ var y = {
797
799
  })
798
800
  });
799
801
  }, pt = ({ layer: e, mainAxis: t, panelSize: r, styleReaders: o, animateTransitions: n, intro: a }) => {
800
- const { boxes: s, outliers: i } = S(() => I(e.data, t), [e.data, t]), u = /* @__PURE__ */ k(X, {
802
+ const { boxes: s, outliers: i } = S(() => I(e.data, t), [e.data, t]), u = /* @__PURE__ */ y(X, {
801
803
  boxes: s,
802
804
  outliers: i,
803
805
  mainAxis: t,
@@ -807,7 +809,7 @@ var y = {
807
809
  keys: S(() => H(e), [e]),
808
810
  animateTransitions: n
809
811
  });
810
- return a == null ? u : /* @__PURE__ */ k(we, {
812
+ return a == null ? u : /* @__PURE__ */ y(we, {
811
813
  intro: {
812
814
  type: "fade",
813
815
  layerId: a.layerId,
@@ -820,7 +822,7 @@ var y = {
820
822
  swatchShape: "square",
821
823
  overpaintPlacement: "manual",
822
824
  guideMode: "band",
823
- render: ({ layer: e, coordSystem: t, panelRect: r, styleReaders: o, animateTransitions: n, intro: a }) => /* @__PURE__ */ k(pt, {
825
+ render: ({ layer: e, coordSystem: t, panelRect: r, styleReaders: o, animateTransitions: n, intro: a }) => /* @__PURE__ */ y(pt, {
824
826
  layer: e,
825
827
  mainAxis: E(t),
826
828
  panelSize: r,
@@ -828,14 +830,14 @@ var y = {
828
830
  animateTransitions: n,
829
831
  intro: a
830
832
  }),
831
- renderHighlight: ({ layer: e, sourceLayer: t, coordSystem: r, panelRect: o, styleReaders: n }) => /* @__PURE__ */ k(ht, {
833
+ renderHighlight: ({ layer: e, sourceLayer: t, coordSystem: r, panelRect: o, styleReaders: n }) => /* @__PURE__ */ y(ht, {
832
834
  layer: e,
833
835
  sourceLayer: t,
834
836
  mainAxis: E(r),
835
837
  panelSize: o,
836
838
  styleReaders: n
837
839
  }),
838
- renderHover: ({ layer: e, primary: t, coordSystem: r, panelRect: o, styleReaders: n }) => /* @__PURE__ */ k(dt, {
840
+ renderHover: ({ layer: e, primary: t, coordSystem: r, panelRect: o, styleReaders: n }) => /* @__PURE__ */ y(dt, {
839
841
  layer: e,
840
842
  primary: t,
841
843
  mainAxis: E(r),
@@ -846,7 +848,7 @@ var y = {
846
848
  getEditOutlineShapes: it
847
849
  });
848
850
  export {
849
- y as BOXPLOT_VARIABLES,
851
+ k as BOXPLOT_VARIABLES,
850
852
  Qe as BoxplotGeom,
851
853
  ft as boxplot
852
854
  };
package/package.json CHANGED
@@ -13,7 +13,7 @@
13
13
  "boxplot",
14
14
  "box-plot"
15
15
  ],
16
- "version": "0.1.1-beta.1793705972988",
16
+ "version": "0.1.1-beta.1793707591025",
17
17
  "type": "module",
18
18
  "sideEffects": false,
19
19
  "types": "./dist/index.d.ts",
@@ -32,7 +32,7 @@
32
32
  },
33
33
  "peerDependencies": {
34
34
  "react": "^19.0.0",
35
- "@graphysdk/react": "^1.9.0-beta.1793705972988"
35
+ "@graphysdk/react": "^1.9.0-beta.1793707591025"
36
36
  },
37
37
  "devDependencies": {
38
38
  "@testing-library/react": "^16.3.1",
@@ -44,11 +44,11 @@
44
44
  "vite": "^8.1.5",
45
45
  "vite-plugin-dts": "^4.5.4",
46
46
  "vitest": "^4.1.11",
47
- "@graphysdk/viz-engine": "1.9.0-beta.1793705972988",
48
- "@graphytools/vitest-config": "1.0.0",
49
47
  "@graphytools/typescript-config": "0.0.1",
48
+ "@graphytools/vitest-config": "1.0.0",
50
49
  "@graphytools/eslint-config": "0.0.1",
51
- "@graphysdk/react": "1.9.0-beta.1793705972988"
50
+ "@graphysdk/react": "1.9.0-beta.1793707591025",
51
+ "@graphysdk/viz-engine": "1.9.0-beta.1793707591025"
52
52
  },
53
53
  "publishConfig": {
54
54
  "access": "public"