From bf0b8d3e2c80dc1d28cd3c6c4e764ea2ed714d6c Mon Sep 17 00:00:00 2001 From: Joel Ostblom Date: Tue, 26 Mar 2024 14:05:41 -0700 Subject: [PATCH] feat: add explicit option to control how densities are resolved, change how densities are resolved by default (#9172) Will add more description soon, just seeing if tests pass first because my local installation doesn't work. --------- Co-authored-by: GitHub Actions Bot Co-authored-by: Dominik Moritz --- build/vega-lite-schema.json | 8 ++++++++ examples/compiled/area_density.png | Bin 9777 -> 9752 bytes examples/compiled/area_density.svg | 2 +- examples/compiled/area_density.vg.json | 3 ++- site/docs/transform/density.md | 2 +- src/compile/data/density.ts | 6 +++--- src/transform.ts | 8 ++++++++ test/compile/data/density.test.ts | 11 +++++++---- 8 files changed, 30 insertions(+), 10 deletions(-) diff --git a/build/vega-lite-schema.json b/build/vega-lite-schema.json index a251280b95..5b773b2649 100644 --- a/build/vega-lite-schema.json +++ b/build/vega-lite-schema.json @@ -8145,6 +8145,14 @@ "description": "The minimum number of samples to take along the extent domain for plotting the density.\n\n__Default value:__ `25`", "type": "number" }, + "resolve": { + "description": "Indicates how parameters for multiple densities should be resolved. If `\"independent\"`, each density may have its own domain extent and dynamic number of curve sample steps. If `\"shared\"`, the KDE transform will ensure that all densities are defined over a shared domain and curve steps, enabling stacking.\n\n__Default value:__ `\"shared\"`", + "enum": [ + "independent", + "shared" + ], + "type": "string" + }, "steps": { "description": "The exact number of samples to take along the extent domain for plotting the density. If specified, overrides both minsteps and maxsteps to set an exact number of uniform samples. Potentially useful in conjunction with a fixed extent to ensure consistent sample points for stacked densities.", "type": "number" diff --git a/examples/compiled/area_density.png b/examples/compiled/area_density.png index 46d40fa9137feb694cbd73459991a7179a700955..767f797ae0964f682698f8a29ca2565aa3aafed7 100644 GIT binary patch literal 9752 zcmZ{KbySpJ_~(!gNDSREfOL0@BMnL;ol;6mhcpbWA|QfvH%Nm>gQPTqG>D*dO75NC z_mACkcK3MfdFQ?LeCoN;nopJRaj9`35D31Cvb;6~g4PNCoB+iJzp8Y7-UPp4Td66@ zL+(&NvcD81K_H9}75PWHJ{h}Rj^bF#rD6 zdT00O>MMe(G@s%0F^R3?fA#`+-N7&fbX;!U@g8G13^9jLcmqQq`*N9-p>TO?Eh3h1 zSZ6Z^Y=HovlTa*8i6=gyG! zC7vwOa2X#R8NnwYASf;?3sYw4I{htXn(cjzn_zx4IyDw4{mI1M16s-x@REC5&d*_bw<=$|0#QwLkCGF zH6ko+Ihy^bMU^%aJjQ@PGnjZ8(%m70B@yY zfGr2{=fQ*DDuIo*R+QKgi8NXlO+@hM#Fbr1(xES(_@4)Vdu3;v)Up{tZR`A!45xs! zv;O65*Vq^#Jw3g+_Z}@dw?S}w;1z-qw$c%Tad3S6*v(DA%G!GM*RRNi+}_(PHNSh{C0O^# zvukUKjT@aK^75Dy7#N5W%WJhDd!<<{r!*c2{ys}CE6 z##!Fg(rq>C&WKu#MW-8xx!|R!dxocwFGM3tvjH+V=qSE^kYLi5*zbvG$ZO*-QBTmx z@qTNn9e=K`9vmVYcum9^3hGlB_ksASKQ)uieWT%(+&yus2kib`{ZTG{orA+~cE!VO z>M|MO`DyQex?iuCl_8b41F;UMoFxeN8CpYrzN2o)gQcJ*0MWSjDJbXxSyo28BB+lA zxA&DPd_9>-VnkVngI=UvOyFfOX+Q16^RKZT``$->PWx3NR?&D_cf_&P7g3H%aPIAc zOvbFSsG1sqy5DY`2)_a;Li*K#UioC|gQcVmckKQkwN6lJE+aJEUbGY4l7Dfqv9Y_x z$BAxlZ=EV}l%ZM=wbN+X5EIpRCgpwP9e17rocEW_Ri=wG`M2eX>KYmpRa9`i_Lt(} zk0V!5Wfs-Fo#qh^D=2;mTU#!2VP@e?-DT(8JeTqncNai&m(W8z8Mh=lIXryi>nrgz zOE#WEr;w4KA7*A|=JRhem57vdN{9mozF1hDOCXh?u=2W-q#>_3ADr3%A`hhs+g|us zl@4LwhqN@y(F}O3sW47X zj)hI&_YhOHUz`%)Lxa$83=0kjO%eV2<{RK3kodH{{9#_bDFQi0fg|(mKQN_ zf9-zH#leXaXYeAU>}OK*TWUfo8Ik!v9{Dk{p($9FH7T&R!RyxpYv8x%fPu;C_imKlxE`xLy( z{$;eHj_LQGofU>5Y5ON#X1R+@_Ag$FDUFxaZD$D=A@NQZNXE21mp5HbI22^3NNk3&Gz6EZWqQ zGdiP6vcYdd=u`Y8Yw04|f<^s9?Zz@AA|kM^udgjEEyveh_9xIeWeNj^=jG*vK&-8; z4GawG7KTWo<(q=;WHUZ}GCw(m<+?c+kgcu!6Xy)(7N_%~5PR1Q2G55Yd~`I<-`!nH zOG`9=|10w4{pGJg>1-8MRZ7e4fn*Dcii*WmRW6@zDotDYU6!O<*p!tiZu-7;ZdbR~ z9igdFVqfrzQ?V)r@{jxSFSrf7`fm09plyFRP3Ul3iJ^00fd*n>XBQ>qy=MVPhi9H% z!X5Kjm6?LFGW6u+g!D>+mH;r2ah-Yn3q9}t2l6}-4^r2RjHng_pb!~TC&!Os#LU>I zU@sk%UedJ?*u@b=%Oj(sL(Opn{&RHr@xuS-WYfwWRc z>gt%8`cpvuH24jt@EG&IoZ*&!eNEZuvfKw4H@l!9VrSe>)rrB5~uYK<=_{@KHw)2b??>Zl4n-!5EI8OL#0< z(#27IljRCkYzp&8i?)CRGtHPc&sgY3enSh5=e4(3yTP&vFqw7CR}h+X7ez>q>2pD zWS4*Of-_&61I#B9pbb(!*DFy-OsxO<-*Nix6XO#I$ zoRt-;kf+(@MS7G``M^!!`vfId(YQQgX{nCF!O8Zdc+jo1k94Nh^3mqdVO7wLTG|hw ztURKU6p}M*n26z&B|9*G1WjE>76Lt0XpWmn1Hs&AJ)xq)4~5tR@@b%u@wR0p=e8s@25Q6jbZDPziLLzc<-)E{K=B zKraB${)1Hj=o|g^0nNVT@o-%@9eHO)1}!BeWyg;nRG>7%LqgCX7Bl6B7gx)7OC(e{ z+tay|v4^__EYMzU)bm_b&K-7J;uj}(Bf*)@QG{Db^xrLshR4Q~fKY@0RV-hV?%?kbyL*DrCwdaqUkEl#U!VMJe>pMd@g3#w?cLpYtvp4zq+|=* z5zz#fd=Z89pV?LAQ4TvPTrId&30~HxSOt-5Nu1_X4_(eq( zb#zFc3sMo#OCzI6*v?Q-DnD066J;RCLs!lmihs`gdi{G_jZBG7nKHL&3u!C`pQ525 zRe424PEk?O_4DxJw?JVhV6!nt&zN070A!UMFGn$%z%s4D4+FsF$*iJ&JniLw zzNY}T;Jl3(;ivgCOli)KB?FgH>*L2u)&O_WkCpuFhUqe$K+0Kx=?{#K_APz!*V56! zU}k29bky1m&C{__Qd7qOFN_Yc9nFXaOBLF`4pdLMVXJ_3Uv_z%tUU74o>;|=^)GK1 z$@UaDDn-~svAtF%U;N0lOGy9y`-d8!ppejlbYWW?Z5TE_ zI>a6r&+plf*!ha?VI%#9cq{u_mrcO-`c28~SqJ!Y;NaoIbz=y!2u=?Uw`C=ofZkdP1`VCto^GGHkHZ(N1Nqv_QdIoE-*zN9+qjB~5I*7nvK{4_Ib9z<7J zSxG5mi-*#fYdtuSU^&JPu#sfDs57YkNs`Rd)6><}wc~KTKba`%4KGnl0Wc&)w_EGQ z5aQ&c{v)+$NIqQ0@pW!~ zAcB&3gJm?}#448o$4Y>`)Vbto=IU8(E0r*xXXlKA#+W2@A##M~g(a_v#=@z=oxD1k zCEjFy5WdU)A~A+>+^0a};s77n!$)-Pz(JEM8g9iQD?#&wYw{~2XQ;gOw@p0WSMCRU zjk9lbv`4&X5iRQMDOUSw>^ns55byzJGW{t_z`0MOmLd$8{`3%q7Z=*ebhY|Ajjbun zD=NIPC(SX40WfcUHU4Mniup^VCU?ZLhCp4y<||-lh0(hqz`t8g=J1=uj7I9R+DQ?^ z7gd>(yC3ostl|h)m_K8;L1My7SpeT>lv$cI>Wv zDVWW6{lqcX;mZvSKl@<&jJuzM@`fS|3(ua0w`US8xam@pJ(?&}wsG%S3<@90pxw|K zOSI<)wrsGB`k+dz&?-2M2z-hhe2VM6{vlBs2rAwqrVi49WJ0PA@RjwR<%v}vyCm`N z6@)nUYpLjBM$dCrtT7Abp)Z?_6kP>|*X6Wpg(tp7_LXjr`gj)J_wfAfJ8%aAx8isZ zOg$%;?Ys$PQywbI-X4K&vqV}RWErP{zjh={lUTmA>GEPpegr;C`&K@(mQxleAT3?P zs8Dx$`jnaMmQ3DP#79gZp<4OkQng-h$k*LJNhCRca={J;oF`9ARqBI2B?{FtJ@5aj zCyiG6C;b2{4_iHYOOX85zq+UkwmK)Q$oh9q#PfN1uG9zis8A8(qX72wSxz-$Q~V;P-3%J{R%T4 z#b_)iS4j3`FD>r2&V=AS<`RJA5>Q5Vj!YqXmbf}|zwuf23fr9sP1#B5CxUQO@}zu4 zhP$G-dxBb;yF%f$0}m$C&NR^k4U$FhT1=A05{IzHbwbTxM}pY458JVShe#JwMMzL0 ztP7VOckqvs7GE}u`z$W#Dfjxw+~^YQm-CWrt& zX<@wO(?pDgvomj3clYY=-$-EM8s-&wQ<=rZDS_`ZsC|y(=;V}4Rx}Gr7zTX+fENx^ z`Of}cj`3ag_V!ow9MX7%zy-R%#S^P3u^3H0SWbhPa;g9h{8Ngtb{NQ4GA?Au)|CiC zw|>K2y=yI{^c%HQiG~62ul2^F96hb12b7Rrx+8&3%Bar&?&e&}$Ou? zqAjr|qy~Z;TvIxyIYXN6m*td|1T)n%&#`$#OluJw3I`x#^*LYkuJJv#EjOyi1$gGO z|K&V8?|94cmoz;g07G^Tj*#|tSx!z)*R#Kdf9LDfsNNdr%(9~c>9W(p+B?@o-3|kR z*wj%v$ow$P!eH(#m?}^$5|H8e+MEt>sojHsvk*1;{nnNGMfBSSa#u>n98rxl&H||I z^XDtm&&;tPC;Q6`D9>12+_BObM&{)1?#}PNq5S*L-J#->5Bz8pye6888O~tM8A;Xd zny%U3XV<92Vdr4tYw(F3VKIRGa~o`-eD3Ael;)kbtQ@e>1QF zi!O)>DiD+a7#VIw1@M+S!b&+m=r40PY{HjVq}e9#J(In&bHe4NU$0kSpbR$;k8$1V z@xPc|kWv6c&ED{zQB9}I15pJqj?QCc=O<-YH$~==i?_@;@cd^((LCWnj%?ItFrdBW z78V+>vGXwZ+l~odZ43}aT2lV{mc$kpACJ$RteRe5Qc+=pjYrvmlxG6}WjmHB6ZiFN zQ0tbA>q@ZT8fSdVrp*-p=l|>1SH`}{6C^+D97s~Q4bg$WHE9o^0vsEakU+4rvr}z9 z&IIz&4iKrloGI^oS@k6nK#JcZV(_Dfvwlk@UqJ1kwyr3=L8RBr#Z4V$N0+`UBrF`Bm6c^>Y-~)! zrC+Y8j|rL-`KFQ#LDz@_GKJ4i0D;$w{p@+&9fHWdocsX0?BoxZHm6 z2Uhx)S;^{0txfsncHH~-r1A<1D7jGftSS<`YT@mC@76I$5i!%$u^AW`W->SJtH^~# zMb|)azxnpupgq91b-zTLK2EFf&urEDR#s5o*u%RxAQEfniuB&TeG7aHV_jX{n~aP& zphO7uJ3JwiP;UH0rp!eox!enoS$1OkE3Jri0>D=ua)H~ftK>({Rp_vR1M zzJeR>({#^yiKF>#21!W)LomIySZecKIrJ%i?odUJ()LtTRP3CbT^SOu7?Zxu%W7#P zPXFcwOJ&1r($wJD7EJkpZcQZChI#=|X#Z`|x<4lHth7tkIhf9|l06$=*Q0W7HEK5mE2kHg8IxcMpW4 zUe&-1pccnE?@}!h9B@Vn397BpPu;)=paueVfR;woG1!3HR!X%pO zp|0!InG?5B9TaR$aY;#MoA0sit@ff2=vPsSyE2;jsnl;(X2|%9E(IJv0Rg~0EG#Ua z)9Gi%!<7Z9b@lb|x7W?2>GDjEjEtzu(r!7KnKAbE_F{H%NLU$VWay5!#$4*ZpvEc2 z5O9D7iZT==+0}FfIv_Uz4r+CEwbSdpmrTF~jF#XYYN5dZn_FAEJ33IA^9NyvcY_)P zT4rVmz;!W!AW%g`1vH`Tb|;=a`}8o#Od$Fzr$5NG1w40jLF@yKKqLnRu|4^S87&_Q z>R^36@u4C>r^MlZKgob?HvO3T(Jxfh11Q-1{Cq}f>5N_WPivc-SbThZ7Z(>6|Bf~} z10QZqYCP-(;Ous=@`&ZZgH^BtP<;GefD%6vW(q-9kK^_V*sVUX}JjGST61VSQp0UAG}qD(bC3!@jnMP;4!Fz-Z(0ugR=z}3|mlam-x-H&{H#63JbEF2u7fj?-l7O@6aIy4l$_so2&;FfC#hw~e-cdpkL zZYH2?120c3rJkk^Y#!MrrI+OvsHIv>6>B;6`#1wXw!2*Z3=NFw`{dQD7rrtwGRd#) z*V7ITT$@^2N_%;bgM)*%`!$u7y!qPGX7znwy=7%(4cdGJy1Kgf11~)qm_>yAPV8CO z*ti;!-o0Dd*_pTXum6Jsk}}jj0LVZhk#dh8V}N+Q->cj+}?HkVJ<)wJwrLd^ee2-VY*Ui55evw9&qPF%s)pK;Tl@YP!aFA94^Y8X| zP5_i%wS7F2t+$<#xjrBr<6Uy&{&d9Ifw8>w- zQ&eQ>ij0fX{Wsjw($e($MiK}qOIzE>@Ni7j;#1k# z+0Dp)Xa&|%@8WdU90k%~g?oB?MgCBg=7KJv91F4K>CQ9=zO0>!HT>&Apo9s+)38sU z=$M$8=0}u;`cPeUgBP zg4Kz-3otM+pjlpB{rnrTxRexzhMmE`?V_yUqRA%!Rq;WUfd)X~nu)Eg?FVr;tIsu- zV8cOI=AG37I4RbBah(7QataEjnKZx=XusN%>TSr(q|eC602z3j?eUyfgaLQoGxIE(mh0k`0R(E@gtyGbg z9{>k%oZalthGN~Pl+7CB$Lq$tcTWgHiGhL9x3rWwK0R#%zNNv@K}5sBfdeCWd}6|C zczBp}3lP3J79o6FO!05P0x zDi4YGZ=BcG*TaTV`Is3QAzofy#igZP^Yt&?_I@_&FVIj^cY)gnXlQ63M4hP7F)&c& z)O-HQ-M!jvT@gg#=nz(o%%3H+;0D9@@o}wy)$Ljx@N$q*_jE_06h=s%Qliz!M-f!Y z3qfVkY)>Q8IM7hHeJ*SVP-}T3IHFdI1t?A=H#FOSt;&!!hU<07{my! zE`XRQ+<;pVczbX?BBrfP+VMwi!6HW))RN{D6K9(h^ur9A-5)&75D%&PdP}WSsNQ*T zxGp8V_d|XKJtX^wwj^i*fB^83f&vzxnAOeA={?^bD*;jGpGYbpTRAng`>$WW2DFa} zLAB)X5z_bUOqbPIc4I?2KqCu!5fq?+UQ91YU^|cRx!my#u zF3>^%+bVl>bTluWXu_+6K%i@DYXe7B`9Z>*H3`+x0bJDwK9c~hjzHu9jis6|g9%z% zSb%#P*bt4>lFrGY0?5klERQVt9^0v6kAL0P!i`v@No&-HxIR31<|=-X9&Iim(LKucFQ{N%(V z4v5&VtWpgRkZ14BRXu<=Grp#dOiF|@K`QdLu1 zFvVX1-6?)S!LB-o$v4T#5#TOMgFzv?tSmh^IpAUj3^*iypw6E1d|n6XaO0BSePA*! zHj*?fUcQW7?T%vR;<`VS!lT2zaybk#MFH0pxs8pDj+vRWW_{R?&vt}(czD&$i;{S> z;;@>UnvO{_J*bw=i3J|qR2WFJi_1&SJ^$vGmaf@Z3XthLjn9C4A)snvhQh#24OG|* zum)HKlo<5(_6F$2k>I;skV>jygC1N^@PL+IOP|6X95wxnW2%P_9~u}MKGM)2 zG%_+$R#uh+ViG0bQ7L@7OM3`t;2+d^Q;?8^y?F!E)z|L=?*pU--lS)eS^xQSSXEV3 zF7zB&H`FLZ1ZAY9fgD2)3@8I1!_3Kv3&<%lDM_dC%YHaJ22X)J)YlRO_3QnKQL(Z2 zeWdB>rF|e^V}F9qEiiwM{ml7KP}h<8)Vax-rKM>BxPG6Wjz~%(0Z!*h>f`9ay#H=W njb}Lkpce+Y&Hn-Pr$LJ0MM8gt3qF9WUJw<9r}C8ui_rfCG>A6y literal 9777 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 \ No newline at end of file +12345678910IMDB Rating0.00.10.20.3density \ No newline at end of file diff --git a/examples/compiled/area_density.vg.json b/examples/compiled/area_density.vg.json index 8fc8c8ca43..a34a2fc36d 100644 --- a/examples/compiled/area_density.vg.json +++ b/examples/compiled/area_density.vg.json @@ -15,7 +15,8 @@ "type": "kde", "field": "IMDB Rating", "bandwidth": 0.3, - "as": ["value", "density"] + "as": ["value", "density"], + "resolve": "shared" }, { "type": "impute", diff --git a/site/docs/transform/density.md b/site/docs/transform/density.md index bfe8d224d1..b7399b5663 100644 --- a/site/docs/transform/density.md +++ b/site/docs/transform/density.md @@ -21,7 +21,7 @@ The density transform performs one-dimensional [kernel density estimation](https ## Density Transform Definition -{% include table.html props="density,groupby,cumulative,counts,bandwidth,extent,minsteps,maxsteps,steps,as" source="DensityTransform" %} +{% include table.html props="density,groupby,cumulative,counts,bandwidth,extent,minsteps,maxsteps,resolve,steps,as" source="DensityTransform" %} ## Usage diff --git a/src/compile/data/density.ts b/src/compile/data/density.ts index 6b4317dc50..adbeb22682 100644 --- a/src/compile/data/density.ts +++ b/src/compile/data/density.ts @@ -19,6 +19,8 @@ export class DensityTransformNode extends DataFlowNode { this.transform = duplicate(transform); // duplicate to prevent side effects const specifiedAs = this.transform.as ?? [undefined, undefined]; this.transform.as = [specifiedAs[0] ?? 'value', specifiedAs[1] ?? 'density']; + const resolve = this.transform.resolve ?? 'shared'; + this.transform.resolve = resolve; } public dependentFields() { @@ -40,9 +42,7 @@ export class DensityTransformNode extends DataFlowNode { field: density, ...rest }; - if (this.transform.groupby) { - result.resolve = 'shared'; - } + result.resolve = this.transform.resolve; return result; } } diff --git a/src/transform.ts b/src/transform.ts index 33b10bb723..5019088f76 100644 --- a/src/transform.ts +++ b/src/transform.ts @@ -496,6 +496,14 @@ export interface DensityTransform { * __Default value:__ `["value", "density"]` */ as?: [FieldName, FieldName]; + /** + * Indicates how parameters for multiple densities should be resolved. + * If `"independent"`, each density may have its own domain extent and dynamic number of curve sample steps. + * If `"shared"`, the KDE transform will ensure that all densities are defined over a shared domain and curve steps, enabling stacking. + * + * __Default value:__ `"shared"` + */ + resolve?: 'independent' | 'shared'; } export function isDensity(t: Transform): t is DensityTransform { diff --git a/test/compile/data/density.test.ts b/test/compile/data/density.test.ts index 911510c88f..49e72d6dcc 100644 --- a/test/compile/data/density.test.ts +++ b/test/compile/data/density.test.ts @@ -41,6 +41,7 @@ describe('compile/data/fold', () => { expect(density.assemble()).toEqual({ type: 'kde', field: 'v', + resolve: 'shared', as: ['value', 'density'] }); }); @@ -54,21 +55,23 @@ describe('compile/data/fold', () => { expect(density.assemble()).toEqual({ type: 'kde', field: 'v', + resolve: 'shared', as: ['A', 'density'] }); }); - it('should add resolve shared if we group', () => { + it('should add resolve "independent" if we set it explicitly', () => { const transform: Transform = { density: 'v', - groupby: ['a'] + groupby: ['a'], + resolve: 'independent' }; const density = new DensityTransformNode(null, transform); expect(density.assemble()).toEqual({ type: 'kde', groupby: ['a'], field: 'v', - resolve: 'shared', + resolve: 'independent', as: ['value', 'density'] }); }); @@ -119,7 +122,7 @@ describe('compile/data/fold', () => { as: ['A', 'B'] }; const density = new DensityTransformNode(null, transform); - expect(density.hash()).toBe('DensityTransform {"as":["A","B"],"density":"v"}'); + expect(density.hash()).toBe('DensityTransform {"as":["A","B"],"density":"v","resolve":"shared"}'); }); });