From a1f876a009537e06a5b328ffda1d0ee70c11ee1a Mon Sep 17 00:00:00 2001 From: Mojtaba Samimi Date: Tue, 22 Nov 2022 10:38:51 -0500 Subject: [PATCH 1/5] introduce group scattermode attributes --- src/plots/plots.js | 3 ++ src/traces/bar/cross_trace_calc.js | 17 ++++++-- src/traces/bar/sieve.js | 9 +++- src/traces/scatter/attributes.js | 4 +- src/traces/scatter/cross_trace_calc.js | 41 ++++++++++++++++++ src/traces/scatter/defaults.js | 6 +++ src/traces/scatter/format_labels.js | 10 ++++- src/traces/scatter/index.js | 2 + src/traces/scatter/layout_attributes.js | 41 ++++++++++++++++++ src/traces/scatter/layout_defaults.js | 18 ++++++++ .../baselines/zz-grouped_scatter-linear.png | Bin 0 -> 23003 bytes test/image/baselines/zz-grouped_scatter.png | Bin 0 -> 21693 bytes .../mocks/zz-grouped_scatter-linear.json | 31 +++++++++++++ test/image/mocks/zz-grouped_scatter.json | 35 +++++++++++++++ test/plot-schema.json | 29 ++++++++++++- 15 files changed, 237 insertions(+), 9 deletions(-) create mode 100644 src/traces/scatter/layout_attributes.js create mode 100644 src/traces/scatter/layout_defaults.js create mode 100644 test/image/baselines/zz-grouped_scatter-linear.png create mode 100644 test/image/baselines/zz-grouped_scatter.png create mode 100644 test/image/mocks/zz-grouped_scatter-linear.json create mode 100644 test/image/mocks/zz-grouped_scatter.json diff --git a/src/plots/plots.js b/src/plots/plots.js index 29b375d62fa..3790ef8e9bc 100644 --- a/src/plots/plots.js +++ b/src/plots/plots.js @@ -14,6 +14,7 @@ var BADNUM = require('../constants/numerical').BADNUM; var axisIDs = require('./cartesian/axis_ids'); var clearOutline = require('../components/shapes/handle_outline').clearOutline; +var scatterAttrs = require('../traces/scatter/layout_attributes'); var animationAttrs = require('./animation_attributes'); var frameAttrs = require('./frame_attributes'); @@ -1566,6 +1567,8 @@ plots.supplyLayoutGlobalDefaults = function(layoutIn, layoutOut, formatObj) { 'fx', 'supplyLayoutGlobalDefaults' )(layoutIn, layoutOut, coerce); + + Lib.coerce(layoutIn, layoutOut, scatterAttrs, 'scattermode'); }; function getComputedSize(attr) { diff --git a/src/traces/bar/cross_trace_calc.js b/src/traces/bar/cross_trace_calc.js index f1cad80924d..a63b4cc248b 100644 --- a/src/traces/bar/cross_trace_calc.js +++ b/src/traces/bar/cross_trace_calc.js @@ -441,7 +441,14 @@ function setBarCenterAndWidth(pa, sieve) { // store the actual bar width and position, for use by hover var width = calcBar.w = barwidthIsArray ? barwidth[j] : barwidth; - calcBar[pLetter] = calcBar.p + (poffsetIsArray ? poffset[j] : poffset) + width / 2; + + if(calcBar.p === undefined) { + calcBar.p = calcBar[pLetter]; + calcBar['orig_' + pLetter] = calcBar[pLetter]; + } + + var delta = (poffsetIsArray ? poffset[j] : poffset) + width / 2; + calcBar[pLetter] = calcBar.p + delta; } } } @@ -498,13 +505,17 @@ function setBaseAndTop(sa, sieve) { for(var i = 0; i < calcTraces.length; i++) { var calcTrace = calcTraces[i]; var fullTrace = calcTrace[0].trace; + var isScatter = fullTrace.type === 'scatter'; + var isVertical = fullTrace.orientation === 'v'; var pts = []; var tozero = false; for(var j = 0; j < calcTrace.length; j++) { var bar = calcTrace[j]; - var base = bar.b; - var top = base + bar.s; + var base = isScatter ? 0 : bar.b; + var top = isScatter ? ( + isVertical ? bar.y : bar.x + ) : base + bar.s; bar[sLetter] = top; pts.push(top); diff --git a/src/traces/bar/sieve.js b/src/traces/bar/sieve.js index ad7eec482f8..54dc5a74b25 100644 --- a/src/traces/bar/sieve.js +++ b/src/traces/bar/sieve.js @@ -3,7 +3,6 @@ module.exports = Sieve; var distinctVals = require('../../lib').distinctVals; -var BADNUM = require('../../constants/numerical').BADNUM; /** * Helper class to sieve data from traces into bins @@ -27,12 +26,18 @@ function Sieve(traces, opts) { // for single-bin histograms - see histogram/calc var width1 = Infinity; + var axLetter = opts.posAxis._id.charAt(0); + var positions = []; for(var i = 0; i < traces.length; i++) { var trace = traces[i]; for(var j = 0; j < trace.length; j++) { var bar = trace[j]; - if(bar.p !== BADNUM) positions.push(bar.p); + var pos = bar.p; + if(pos === undefined) { + pos = bar[axLetter]; + } + if(pos !== undefined) positions.push(pos); } if(trace[0] && trace[0].width1) { width1 = Math.min(trace[0].width1, width1); diff --git a/src/traces/scatter/attributes.js b/src/traces/scatter/attributes.js index cce2de0cd7d..5a423d9741e 100644 --- a/src/traces/scatter/attributes.js +++ b/src/traces/scatter/attributes.js @@ -146,7 +146,9 @@ module.exports = { values: ['v', 'h'], editType: 'calc', description: [ - 'Only relevant when `stackgroup` is used, and only the first', + 'Only relevant in the following cases:', + '1. when `scattermode` is set to *group*.', + '2. when `stackgroup` is used, and only the first', '`orientation` found in the `stackgroup` will be used - including', 'if `visible` is *legendonly* but not if it is `false`. Sets the', 'stacking direction. With *v* (*h*), the y (x) values of subsequent', diff --git a/src/traces/scatter/cross_trace_calc.js b/src/traces/scatter/cross_trace_calc.js index 69006d8d45a..0f0e0ba5a1b 100644 --- a/src/traces/scatter/cross_trace_calc.js +++ b/src/traces/scatter/cross_trace_calc.js @@ -1,6 +1,43 @@ 'use strict'; var calc = require('./calc'); +var setGroupPositions = require('../bar/cross_trace_calc').setGroupPositions; + +function groupCrossTraceCalc(gd, plotinfo) { + var xa = plotinfo.xaxis; + var ya = plotinfo.yaxis; + + var fullLayout = gd._fullLayout; + var fullTraces = gd._fullData; + var calcTraces = gd.calcdata; + var calcTracesHorz = []; + var calcTracesVert = []; + + for(var i = 0; i < fullTraces.length; i++) { + var fullTrace = fullTraces[i]; + if( + fullTrace.visible === true && + fullTrace.type === 'scatter' && + fullTrace.xaxis === xa._id && + fullTrace.yaxis === ya._id + ) { + if(fullTrace.orientation === 'h') { + calcTracesHorz.push(calcTraces[i]); + } else if(fullTrace.orientation === 'v') { // check for v since certain scatter traces may not have an orientation + calcTracesVert.push(calcTraces[i]); + } + } + } + + var opts = { + mode: fullLayout.scattermode, + gap: fullLayout.scattergap, + groupgap: fullLayout.scattergroupgap + }; + + setGroupPositions(gd, xa, ya, calcTracesVert, opts); + setGroupPositions(gd, ya, xa, calcTracesHorz, opts); +} /* * Scatter stacking & normalization calculations @@ -8,6 +45,10 @@ var calc = require('./calc'); */ module.exports = function crossTraceCalc(gd, plotinfo) { + if(gd._fullLayout.scattermode === 'group') { + groupCrossTraceCalc(gd, plotinfo); + } + var xa = plotinfo.xaxis; var ya = plotinfo.yaxis; var subplot = xa._id + ya._id; diff --git a/src/traces/scatter/defaults.js b/src/traces/scatter/defaults.js index 33ac037c920..9c980ca69de 100644 --- a/src/traces/scatter/defaults.js +++ b/src/traces/scatter/defaults.js @@ -31,6 +31,12 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout coerce('yhoverformat'); var stackGroupOpts = handleStackDefaults(traceIn, traceOut, layout, coerce); + if( + layout.scattermode === 'group' && + traceOut.orientation === undefined + ) { + coerce('orientation', 'v'); + } var defaultMode = !stackGroupOpts && (len < constants.PTS_LINESONLY) ? 'lines+markers' : 'lines'; diff --git a/src/traces/scatter/format_labels.js b/src/traces/scatter/format_labels.js index 5908a425466..079afd0956f 100644 --- a/src/traces/scatter/format_labels.js +++ b/src/traces/scatter/format_labels.js @@ -9,8 +9,14 @@ module.exports = function formatLabels(cdi, trace, fullLayout) { var xa = Axes.getFromTrace(mockGd, trace, 'x'); var ya = Axes.getFromTrace(mockGd, trace, 'y'); - labels.xLabel = Axes.tickText(xa, xa.c2l(cdi.x), true).text; - labels.yLabel = Axes.tickText(ya, ya.c2l(cdi.y), true).text; + var x = cdi.orig_x; + if(x === undefined) x = cdi.x; + + var y = cdi.orig_y; + if(y === undefined) y = cdi.y; + + labels.xLabel = Axes.tickText(xa, xa.c2l(x), true).text; + labels.yLabel = Axes.tickText(ya, ya.c2l(y), true).text; return labels; }; diff --git a/src/traces/scatter/index.js b/src/traces/scatter/index.js index ca331864668..2de0e3ed8cd 100644 --- a/src/traces/scatter/index.js +++ b/src/traces/scatter/index.js @@ -9,8 +9,10 @@ module.exports = { isBubble: subtypes.isBubble, attributes: require('./attributes'), + layoutAttributes: require('./layout_attributes'), supplyDefaults: require('./defaults'), crossTraceDefaults: require('./cross_trace_defaults'), + supplyLayoutDefaults: require('./layout_defaults'), calc: require('./calc').calc, crossTraceCalc: require('./cross_trace_calc'), arraysToCalcdata: require('./arrays_to_calcdata'), diff --git a/src/traces/scatter/layout_attributes.js b/src/traces/scatter/layout_attributes.js new file mode 100644 index 00000000000..67d21372b33 --- /dev/null +++ b/src/traces/scatter/layout_attributes.js @@ -0,0 +1,41 @@ +'use strict'; + + +module.exports = { + scattermode: { + valType: 'enumerated', + values: ['group', 'overlay'], + dflt: 'overlay', + editType: 'calc', + description: [ + 'Determines how scatter points at the same location coordinate', + 'are displayed on the graph.', + 'With *group*, the scatter points are plotted next to one another', + 'centered around the shared location.', + 'With *overlay*, the scatter points are plotted over one another,', + 'you might need to reduce *opacity* to see multiple scatter points.' + ].join(' ') + }, + scattergap: { + valType: 'number', + min: 0, + max: 1, + editType: 'calc', + description: [ + 'Sets the gap (in plot fraction) between scatter points of', + 'adjacent location coordinates.', + 'Defaults to `bargap`.' + ].join(' ') + }, + scattergroupgap: { + valType: 'number', + min: 0, + max: 1, + dflt: 0, + editType: 'calc', + description: [ + 'Sets the gap (in plot fraction) between scatter points of', + 'the same location coordinate.' + ].join(' ') + } +}; diff --git a/src/traces/scatter/layout_defaults.js b/src/traces/scatter/layout_defaults.js new file mode 100644 index 00000000000..a05ff888330 --- /dev/null +++ b/src/traces/scatter/layout_defaults.js @@ -0,0 +1,18 @@ +'use strict'; + +var Lib = require('../../lib'); + +var layoutAttributes = require('./layout_attributes'); + +module.exports = function(layoutIn, layoutOut) { + function coerce(attr, dflt) { + return Lib.coerce(layoutIn, layoutOut, layoutAttributes, attr, dflt); + } + + var groupBarmode = layoutOut.barmode === 'group'; + + if(layoutOut.scattermode === 'group') { + coerce('scattergap', groupBarmode ? layoutOut.bargap : 0.2); + coerce('scattergroupgap'); + } +}; diff --git a/test/image/baselines/zz-grouped_scatter-linear.png b/test/image/baselines/zz-grouped_scatter-linear.png new file mode 100644 index 0000000000000000000000000000000000000000..55e0666acaa6851019af332ab2ab0fe043121232 GIT binary patch literal 23003 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 literal 0 HcmV?d00001 diff --git a/test/image/baselines/zz-grouped_scatter.png b/test/image/baselines/zz-grouped_scatter.png new file mode 100644 index 0000000000000000000000000000000000000000..7d19f1a20d96811b5c67b71350eb0c929d5dbace GIT binary patch literal 21693 zcmeFZc{r5s`!`-1nN*g9B72sMC4{oemL;;x7=%Hxlk9t@B!uiC`_5ppW;Z0+_k9c5 zx9mI5HSgu~{XWm{c%J`%$MO9mj+x9o=XGD_buO>-^|}L|sVZD2rXjv?;lg#rC$btB zE)XCuT)6lNdKtX)T9E$pg$s-q6lJBgTn*L|h(5yyD(ZYLU6R=_m6EM|lYHyhhc|DA zIRXOJAIPs72l26Ko2<5$>MLW0gD2|v_zYNu1HYnJexQk;gpnx0ml6&or$pLgTiYcB zj#rDjCO5q46Uofh;FEUtouXD=9&2CFXf%Pn^aTR4Hy0p`7cN2%hN0R@_%f-fNr|;&$7YQB`Bn@o|l!J{$ndx zHpyRW`s>^NXW4&m+5hY|*_;1y@_$a%|D0{;|Ib5Oxbxa*#*l%>Q=j9psS>yCmx9*A z&lVCr3P>alQ2rikqotL*gL;BigIt0Zy|OU|?m6ze%X1DK+5bjx-)s=!ov#kU3ae9% z8s9(ijT0~n;i)@$eLBbMqi$eNi!K4vETlwWlP%?_I{PUT7eWl>*n=vul1=4fggETFMV1WHb6(B8VIl{@HRM zx2gRK-$jTODX!vhK7K;;oj;xP=Mc#=SMl9`P0kaW=~h@_|IaWM!B@ZP$^3-`^i6{9 z3yc?kg_l8#`7C3X1oYm;POIh(u)IO7NxV1eh!b4y&xuH@Fz;dBznPMcDz%$3aG7+= ziW9O~E`zMydpySPxz)n1lX1^%oe4Q`OmsV|iX8J$uFBm+4x8H?S|uQJ0T=$9xhfyY zty3gh_S;g8|Wllq)kqyofsQQ+|rCpUMMKeqvHg%k*f< zRMfj_7!>jIlI(sf*d0DTPw?|FP@p%82^mIGSorp;3U;zq=V<29Qgf4rx1GfzL;8A} z7v0sUCjSd)$|NKazXk+G)*faK!3E0Rx^!EX5iPhPxa6m)6q2QCvQ)jF&UOspSEUJ{ zx(I>kZnhtolVLvkGg^tfL76_y=AZ15g0vwDCu=fRk!tSIaLj|wH*VYWOOqZOP6~H* z0#%bFyc`GM+7(n?635p0&nx)d&~S2$0Iss3Gh^xu`-*!rL3fa2sMdE!8Lmb zLG)ZOMTXc7DXbVe^|NT_TkW~~^U~hWVWK+h$)AH9IU5**Xu!f48T z*Gz{87UW#YFOociAI#3l4(-#0k>%(_q?anE57wj`Y0KJr{2Ab_9T0}q)cO8SbFPA^j{YqPwq?*txD=j5Y=Y0BNg9yR#csj9Lf8mk{!j5&mf@dp^bK>A& za~2<%vlT+=6CqYVKHgqu{NvByjdXL9(~I64q#V10PM|cGO z$$njSR6U?o6gej`vUzQy(n%8}v6r1+mdY;J5Vn2KDx$>Di8?PNqFnjOy}|q&P!3*aEFVcFh#~6VahQ#*+?91$C2}al51Xy6XXpo^QJ26 zR`lE!W<64(vYeyK^7ons`+2R{EFHOzyxo|S^ZdX}Q;@!~JBSSlS|d70XE+-&$>*$s zr)rho#T&7?@~4q>C?m#TIgz;p&gBt^RZo*IsC`Q+F-%#?!o)T0HCkd}J7@L%138VT zGv;+`i*VkuIXNabe75%W6)d{x`yVCHD=7uOP9)58OoUHl2C!c|PN2&ZgS}LF2xUZ0 ze~@|M?u(LRi?m>XqNAL@hgsA|prU>j=iZ}pbY>1n5X<}7{??in{GSc^RW~1U%qJoa z*$El!>f;*UzKkz48g<3#jRlchu?bfRm_Wkv<6<0{q=Uf5 zSZ+N(C&&Cknt3R%#I!$q8)~cB*^%Xe>-FEKi?Z=`#ukQni$+m~ zN4xXQ_Rr$LX~&;~Ajpo;RD9Z_#SvSe9uIRvVDF@_$ixIDnVGsFywrv&-}0!xjrOSO ztF2)C#0^}yc=>@{)a@~&+m#qM2;4fWmB-# zv5PM#XK~)(^0>WY=X0#bu2NXD7gtcd)v7dB4WiFLx!u(7z|S>*MiBL@eqFmOLqin{ ziSai}gK34A&yF{Sv<V);F7akWCb>(>xe9iT@|REVjnp2Q{>^S&~;-MDE2)m(7=YGmcI- zd^Wr%bK$TFw}pg)T8GX@3h}~rgOu9OQ}|4Nn1d8E*$kIfgtSqA)Y8B^70*9TmGXKe zTCvdZUWe-=zHH#El)*P}TlOT?uL2*e2yRf0Dy1pDaw`1V^+enokr^EbSwUar=`I~I z$Q#VpTLF==ShvJHr6)}xW{iS@k0OWG_M3EqsEf1dd}l)5m|dMdKACLM>wUHC%M7N- zF$sAjkFQ!ZMkoJCCS}}9&3>pu=`fLSd?+weXisgg-L;HWy5Vx9LR- z@!-kfw$r5B!aZT(&7(9ln!ssobRb_M%4I|-+2-PCAbi^N%2r|RQLb&}Qs!?T4^Y9s z&DkWFzM z5~=Dv8Kb&pL1;DeJpfbDTs5YhFArzZ=NE>p+&?6Z$W&nZ7?Ll_e{9ZdUIW&Gr=JJArHbWIy;>u71Q7aGgc z=AGIz?R)Ueo~o0DX`K^Fk{k$r^?|_<9X7h^Smu1I4nEBknc!@AQPP z=lLHYUB>PG^>%3_y*>Gf+P+&YcBjB^E5&*saif>yMI&ZG9qRm2)TjYcu02-eVrQ7F zP;mnSYwg)}v4%$1iOFcjw-r|^#ch_$#_X*pJ?v_w-zb~`7Lq@w8h?p4RfAHklj+2C zJ)FJvG)baHg(s2@_a}bpOAo z_U^Ub2OMI?WznCNIqpOB znGN&Jgfxm2X4LuMD(6|eRkp|zvubh|0T1I3Ov)yrN`J{W^Xqio3pQ@-$s6#{I zlf|jJy7#0EJjecBaM}7>ai74^rRE~b{`BT_jE|{Mze*^*C{n7kNDaQ76m!q)klGef zwI``q_1-WG?au8<7iKdzY(|WR-+?nd-?j7IOB)`lis@#dfcz0E-Ir}7%#gV$HV~xuZ*M#{d}>!z@wj3DI4VJ4HrOF zP{l-@=wT0zX*5p4X<3WTv0J)@yCL4Lc0`;+_rTojf_-Zo8yN<31^z=c5M?R`$#F>r z)x~U021`MVJ6)2y{=IQuRK|s%)D*A*it9a3JuFjp;w#rSRXtLFRjw37BorGxx^Q@S zxE|KIK2hb*_Q7Zwil)poe^F&^cXkw>W*BgAlj)W0xVr6a9K6-HQ?I zH+i2F4Y1PU4b1{4XfYKeOTV%pb2eL%OEU{PI_xA56-7?mbBw%E`j4>$GEZeBK#S%1 zP7!_s-Nf~GJ;W(9*VgSXe zbOc9XVP*rz@7{=N^xwgQ3lE-O2kn61FMBH;0w`5+0}O!Ku$(uoQ7y%}u(dl zf5&WMbCT|lh2X-5_8PYV3jNQwzj+PH9QUNp5Ba}$)E_3vRA0%gTRjX z_N?APqYdxosjDrCKvP3}u22Om-wLe}4n@VqV{=*-2 z*vvl{$JMo5Bbq_F5$0?iMN>ACVCIziyD!LAb6t~Am=WpSn_iF%?woX3h@vPIp+d0M zc%K|BI#X9}Nem|1X!*z_X3D!iK2jF^<~=HN@agqpLN2kXoGvlG zL1nzP{J0{EHNJCl(?0~20mW1{DKF@ZEUiSFnW|lJulC-bp*~tMQ&x^V>-bY}v_?K5 zHu$X67>XG9X0QDc6bG?$3>Aaqn4f+RY%V><_P#HB(Ihdi<8;uN&Y!S8k{Nck8IQA| zyM~TJRBI)&fx8`7|D#kF0xJkp^BRXDmfJNd(^L}SwGU2om)=BZb{3Dq8J`|)>75=O zcC|Sg6|y<);uuJjbF6Zx&f&I@eko~WwG%;g-#<4BsZZ#G$pN3T-oeSCZoHp9#79c}q3GF7Gh3fn{G zjnQ=LbtB6Ijk8AT*8VXD?O7dtH`Gr165A33fZZS<0nO%{)V2 z5!bgJ_kO90nAS_=8dhbJCgi(Qf{h!oH=75p6KlfI5>1YI@?Mbp?PF}NZz(XaW3*R| zHpPOpE+O-973U2QZ6(Q&8CDWjMX9i>{?pTGl_ zTlw=xi2($b>08)SUbk4U=1_D#{7&%vKR94z_G0M4ysbpPEeIAfZ>3a`6xP~UhfTO17Z`pyE6SQ~~X z*ZI_{kk$&QO<_iV(Uhi9$?w^w88QsQC$?$bSD(xWGJ#v7)&>XNCp>}9B^rQS#=7{6 z!5`-W2j#Y?CkznFt8UFOZ`;#%U!Rq8f6?mcRqh;Qg>mknIg+b$wuNE!`zj4&qBdVc z5kF+4h;pSa;BpBb*p7f9SN=}^ zF&i*?ma%QxRLSkWIC1EHHrq5>?UehwZT&X?!RW5hvxyUMK&c>34YB2E<@AG2C{TjicIUSwa zDE;FHg;@@yYZ!{7Qin10h&K}w{oJ;$|~ae6k;OwW?~?9d|r(H<=IoJ&uhS=wcXcV#N+Yo5>Ni?RtNe&o}Oa1*3kc z+mYY`-QS(k8m{6S-ho<{^fbEyaD~o-xPwlyrwMgzx37sBH$>UCSyp~Lvg3qjlU_>H5=TM^TmkLQj>>$= zgO0klRiZ}+T+wOK-tIO?2@wr2-{C8WSh2j9y;xXAt=SX7R-d7%vV^Lg7`5o-6qf~y z&Hea0x*lE~pD&FqH8fUcdx1vD-puI{1eVuGJ=V#Btdcq38?##hO-{tAjBRgv08iy2 z^IF~c*?QLAlx@u}0wA(&r>ninyzoMU8e>rlPMU}4rjkEOj6!I<8_O3s{(02f4NDgZ zZfh#FA5#_IoqjBSc1DmtiXDjhO3icrx?V!WN{UTL^0-(f-kyFJgjHNN|2aG@OoIkD55VfW_-5}jpUFR!QXeFs(HgM#TkM&{<21BSQ+lVzIoia^-~g(X@>KPj%)s z^j_-A7_Bskffc*-Rf;ThchY!tPqwyooTX9a3b>K~$LCv_>RdOC^}Tin+(AKF>b`5K z|GI_MeLmJKoE7xn>Hr*l!k*}AoH>KAs8aSG#^B0p;hE#-UtYaYT^uXuJv&FgeTm@O9n%LVvP=-iNKP!b<~(C;QwX})u2qa~nZ#;s)% z$buYr)0}@BKpatz?a;44OZpcUR_}YM)Ov(p-=Ra$ef4W|IIE4R)lh-H$XZEXiT&)4 zkA#J(@29?$D%BmfedL!@JyF!t7tPfhJ$nA^Su()5vJv^Hvb%jkWSpv^7mv$dZnFvt z6O0)Mh5TFb8u>-!ta+*S?McVvFczxcjy~5ZL4xPdO`2QJru{eLDt~zdd(8Cl>lb^D)x`Dp{8{IA0%@40`)f|&gz$U4a$ERB<;XU( zj^V{;v1SBgCyZ#jBbFo~Qf+$g>REt^%*iR?Q#AGF~RMVzGvvY_+0>hTO_` zN>M{b$7TJ8GNMawYFYz7n|&td{RW0%F{!?&sB4aEqa*tUEg#edZZyhZooBIA>G*1z z{qjPRkN1u6)BV{{NdqNScgJZV z!6nzCFVhy@20%h?nYON6ZQgN)j|?4#v-I0SBSmcnN0vksXWuNU@JZ3G9a(VC0l^w! z$sOkWYA9N@EMzs7H=LQ^i+GxMj^q5C{f0J39-?X+? zud3;EsIt^@8Q||$C!bU;Cpb2{uW8SLN~86*IkLv#t4!NpTOB)@&&#$= zS`C&3l=EJK^si|Ir4q>_Fk`9ylL>_jk_KGIO-($< zO~1e35+-utPUTZFG(V&&{ZNGHSoy!{Cl8bcIu4u@43fT%Um3#8twhKa^9Hkgv7XEG zX@1E{&#Hh;eQ>E)G#W#ON2&kC8C4r}zP*fC_pmAe-H9ixsKriPDxhlo}+}J_qxm0yQe{B$e=TiW$)`sGnAR`Sp z3T$WnGli^_4Pjelww5|c7pH)`hcY6YP73XzoM9reuK*^-JP^kF$t08|U!>A6C)30l=b2FtGFDz)dxgyx(LjdeY;0-E@ z6Xx4}?p#B^Cr0wd5i@l!^Hn6inlD^DOZU<&FEUl!T8n$lgHXx(N$*c5f{&i1T~ZeP zbQ*c|woQYodct4h4)tfQ!9-0@&4@|{3Q1RTJGmeI;Y--2#VN7tFRN06!a)Cp39^v2 z#pi)tDVx_86fzHNvCdAvM zDPlZ}S1)hK4D%{a&jE3hwPoy3Qem&8@#*$%UuVZeO3?F7mQVJ$*KP)ujXUPgG(Z0^Rk?JlJas89IfE z04X8*!ZngR5I>~25~FM@dHf*8tTZz@h2G1qHZiu68*@0G#t zzP*7<8OXTlg(p?pnCQXfw zmN$fKM=37yqTwf#Psf~F6I=O5+*ej8b<0f^wwfg^roP*-ge*_UdkA0Mw+i@7oyJ$%H z=W0jGa$wACYMyU3VOZB0|Lb?{ADZ6$4B+T;mqhIQ9}j0zqbbWibTjaR^TZp;F&iu8 z1e}V+kVikheJrlZSZ1r4n|7Wx;y3Bi_~TN`qV`{pq?kAtt59CsnGcSWdNJA*74Y@Z z8cL+)xUjV(Japp@lSi%b&RIYj)vBU)!7Bi1G~A|khl3G+(Cr!6MM=Uu*Jduo$ujb_ zF0-JZ@ZYq*=PD_FgF?VHbTC&fyt;5x#msbo3S&c?{-{v7m`%}P>Qfn&cuwxPh{l4E z#(vLeg-wLz*_02fKfi;vNAQ?aaLD>lBVB3zZJVW!MUqY|$g@}J(I~M0xUCRRtEC&5 znO_Jy?A^ofqBkTDUIvTi{p8VWIkL#25_w%W$fHgd$d`AiDN!>YWz1 ztM+I`4OAM;pbxgiG587tG^$}?oryMS!SKxlp zb|Q@}V%69wehAij_zULC2+4Ex7q%VCae0~Vxbei(YOwWp+Ad=LjdS$fsnGipQ`())p7*ucC^z zW>)*e42dLdC+QPus1YWMHVH*&RKP%-oszRqUHRBiam1jh&y<%=HG{iLZQ{A>*HubY zXPxn85Eh&FZ4?R&=4A}#=oyi4`R3r;cLCpk%=>11XF4is{*g^fXbby|IvsfA-KkV* z8@kEjQV*xDV=m5k)sUZ$c*JphaB~>8{!84 zq?5C=L;lzoV*?(AKPpj3YPuQ*aAP^DYlVUUi6WwvfElC|hzL)|J4I}ufFagBP5D!K zb$%Ds`R9|cggcUsQwR~ux zB2TM~5Sg`l3^VhrQgx|&qyVy0ShdZw7%CATbF=HKz09AbyOkKh0hGGm_n`|Mk0jq8 zHI-Om#O61QZrwn_T{|~D=kSxggaA0H2fOjPYDa=K-9%n++t~D0?3;WQuhYPt-Mbdk z9=!#rZ%yHa6(t)VzV8_>G^USl9gdB_DW+l$~+WyEYpJgUEupC?QqJavnx({BT^I5Y;=*cWoPor9{Vne%X9kwX$x%=V8(@rqH#_zQ|VGXhli?BjR&Ai zr9Uki|J@L36O6EdFSCQ`Fm&pzm66-{Srj~aGKdb$2asX&|zdv}-h zT=hv5UDlt|lW@W@dJZRs9GirY{?7U1T-%9C4_OO^S0{538K7r((>*z5)9&n)5Cve3 z$bPqKbs;}n1Q{++F_}e31p+g^*s=4fNCz8OETHhYtmM9;cg1}E=;ssr;-gY0+0eoD zSADn%-EUEm!-k^eirbSsN*d+cxx|Gu6&n810iK-78g`#Iyfu3Gu9p=Z^!s1kJvhEv zVkz_3ac%mY0FhH~&ZRvjZJw7Dpy$@9XW@Sifie4DYrCJyjLdM;4L_00Vpk0>&!V_m z2b@HiGB*jqlg%Hb_oh={ zJptL5>58mYB{>oJ+Pqyo=f$-VnEqrmNc4k(C+@+!%n@^IO+aN3PQM9|=L_vQishvL64yQA0r$~vFa;Ts>*D`R_Y=wt$ zvjF40J@he{(-sZCQ^NYf=b(ee<)rcVZCH4P4C3WRrV}_KJpzVAF4x?`J#jo1oBhl= zM@B|1hb7um-!*-lzdR1Ig~wTejv(#$Tu^(X3nl^}4DZw3KLxgPfmaEdKu~Y@x5kGa zlm5r!3lFa%HnGU?lZ7Ck?iJ_B!H;uAcM2NX4EV)7UBav9?B?d)Gb(yF56aR<&1rTV zN?P>o%Qb$@uMLqIkMLQx|EN`G>F-KI5z$376`R%Nvha1}YGtS>HbK;>MrPZcDRIP+ zI|8gtr8jFW7bLR4FhB*2EvP-R45k;?HTm&T@$C1ASyI$#j!tpru^s48`^ERiHR1DN zwWK&s$?7T0_^0-z*LI3;F zmjKz(AJ49++@JJF5ZeV%$2-)7&-p2!4#vE{cKb$~Vt8vZIi}TOL^)t>m#3`AlsAjV z((|rrMVXeeOILYCC5#M3m5d_$r@NIR`eC$7 z(Q8#Zt98^BSp;>Ux1ua(;px0Hj0fM6M@LftZJ)Rcmy5aXO-~9e6PvkHs?Ln8VyS#J z{dl0z&@h7SsYaT7uo86e-4zPQcE09pmyJpFpt_A&X{?5fB?xUDx+$Ox?XD^YWxSqo zHS5p#S8y1w#i4e1P(;zkv!%PHyd7OiLHI)d(qJ;ch` zcNc2&-W|%8wN5-n@&%8P6m;wlM|V(Ey>@W$S|g2;3#~7+8Pm!`aL=W`y7pv;Ba%+N z#$D{zjroTx!2CSN3wD)DY`Ys%hK>HDF)h^Ed=4g+#cAfI$iVlqpzdR?){!l;P5kG++FNSLv7|>I&e+PTc360K2f#wZA zPb9WC7w8i#gZ8z1t!daCoD_~8G))a`fmx;uVaw$@n0cnfF43c$QJ-$}QY(Xs-&z^v z8|?;js`}^q=C2$AxA(0X04-7)o2iKJ_%Bb}}Ko_Vvqv%g$wsDHR>>7w0;>c6L%T zN3~Y(9@^&9F8@5$UCBP(0yWPvogXR-Q@1x)zJ4t)b}HY&3%h?m(ecmZx|2|T-XC2? z2<*B8YbyLNSo^!bAIgmkvr(z{7uvXbLm9(gz&9Q2VFBm*=jf7SEd#nC%(_ zlQkX6mw(R{eLto?FP0@$i!E%LV&A$R-=CM!N4k_PaM?L~utFai9Rq##1Ed+izWO&V zn?dpdaU->gaiWjxBOAU5r_U%ZS2(42HU@@hW{;Kh%3C)r^~p_DQEQ9^)$yE#NEy@!u4Ti0J?QjIR5V0?Rb^rDBL-$lVM$Q0jE4{JOat!a%#W+7VDl z9tZGafU>9v%sHa+!>(G?kzwKITO!t}@c(7-dE^sx(D+D*6Ij1lthC<jO)=)D$L1O@k zE!^3;+z(~yaxydO@z)f#?;8s{(iwp(QlnVV97!5*P!6~9K=nlUWfOr=-pXni$Td7!y?xrxAxUeCd!WH>k?e2rdEBP z&}vhrl;TS(XNIgl4msXI9H_2VJ}f#a%Bby07CGi4Dyzp56j8ZXK8-2gfU01v1(yM- zUC6s0X>mL#8(x`!F>uwv{T0J2TF|h zah0~D8{4!eRp0lL<`DLNae!~X{O4V+0~C?nAZ_+9!CjcZ_X@%dhAg9WZMtDcm!b6o zRGqg;r3W1WI2-q@r^gsHgPCs&Ap{hdt=HK1C(<;|euc9sMLPf^>}?jZ6l6iF2bqig zc#CRc>GTcezmF>-2ZW*|$(UR52}K46H;qtf87a$nlBNu=!9Fu`Gtfm#J_sep8qRcE zAsI~>&es>53oe%XgFD2932Fb)eJ}JjuJ!EJdrJu3R`TUeMq~tY0IN(z$)*5N!p+oM?YEFP;`a_Wb)~VXWK9Rb zfMsCV-X~%Vf#tihz#pM0b6#aS-G?G{H#OYiz}>bWpdGR#$9$8Q*tG}T6@j1?Iw;~f zOVY%wJT|b&ZluVx5|ADR-FM7`Zws&;QXDsXt>l+m4q|jH@uR?+9gW@P0az7FQsyKJ z{$eA^G^`?=tI> zRmA(Eh*s2p6}kcs^4|Uo@_m&ZC)8@2Hrq?iLVS>X3bSIBU$;vi0-WWJcJ@x(WZtM zfa<9_(S7-zpm}$FRP9zPOz`#ZC)e*hyg%O4A+<5g+m+E(nP1(d;vjf^zEcZ+dN$o&Y9+%w@gEw(F(GSb(u>}J-MQ!+qAUOo2ebaEJy^Ec ztr!}-aU#0FIFS85hF-?Cxj^abq3{+@h|}oz9|N8h)H01XU;9f~!8KfbLmNb4-DFH4~6UW-!UTcjchlV1^>9XOmhN$^R01aG@zT4$M{-$+<|w;_n-w z@fw}o^@%Z=C0A;2NxE|_`A|Sgg-x20V_cgh^%O!;ZXd?~_og|`v+~`A3pcIt&jt9m zfo^V0*o2|+R>0}_&~W(c%_<86VNZO zq}-I_2P4y5g2Q;*O2yOT{h>e8jiz;e4wU3r-gcX@GA5)-pwgAksFA4ncs≈_vam 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 literal 0 HcmV?d00001 diff --git a/test/image/mocks/zz-grouped_scatter-linear.json b/test/image/mocks/zz-grouped_scatter-linear.json new file mode 100644 index 00000000000..e0d0ce0da1b --- /dev/null +++ b/test/image/mocks/zz-grouped_scatter-linear.json @@ -0,0 +1,31 @@ +{ + "data": [ + { + "mode": "markers+lines+text", + "texttemplate": "x:%{x}", + "textposition": "bottom center", + "textfont": { "size": 16 }, + "y": [ + 1, + 3, + 2 + ] + }, + { + "mode": "markers+lines+text", + "texttemplate": "x:%{x}", + "textposition": "bottom center", + "textfont": { "size": 16 }, + "y": [ + 2, + 1, + 3 + ] + } + ], + "layout": { + "width": 600, + "height": 400, + "scattermode": "group" + } +} diff --git a/test/image/mocks/zz-grouped_scatter.json b/test/image/mocks/zz-grouped_scatter.json new file mode 100644 index 00000000000..2ad6f2efd01 --- /dev/null +++ b/test/image/mocks/zz-grouped_scatter.json @@ -0,0 +1,35 @@ +{ + "data": [ + { + "x": [ + "giraffes", + "orangutans", + "monkeys" + ], + "y": [ + 20, + 14, + 23 + ], + "name": "SF Zoo" + }, + { + "x": [ + "giraffes", + "orangutans", + "monkeys" + ], + "y": [ + 12, + 18, + 29 + ], + "name": "LA Zoo" + } + ], + "layout": { + "width": 600, + "height": 400, + "scattermode": "group" + } +} diff --git a/test/plot-schema.json b/test/plot-schema.json index c32d24547c3..5f632f280ec 100644 --- a/test/plot-schema.json +++ b/test/plot-schema.json @@ -44902,7 +44902,7 @@ "valType": "number" }, "orientation": { - "description": "Only relevant when `stackgroup` is used, and only the first `orientation` found in the `stackgroup` will be used - including if `visible` is *legendonly* but not if it is `false`. Sets the stacking direction. With *v* (*h*), the y (x) values of subsequent traces are added. Also affects the default value of `fill`.", + "description": "Only relevant in the following cases: 1. when `scattermode` is set to *group*. 2. when `stackgroup` is used, and only the first `orientation` found in the `stackgroup` will be used - including if `visible` is *legendonly* but not if it is `false`. Sets the stacking direction. With *v* (*h*), the y (x) values of subsequent traces are added. Also affects the default value of `fill`.", "editType": "calc", "valType": "enumerated", "values": [ @@ -45307,6 +45307,33 @@ "scatter-like", "zoomScale" ], + "layoutAttributes": { + "scattergap": { + "description": "Sets the gap (in plot fraction) between scatter points of adjacent location coordinates. Defaults to `bargap`.", + "editType": "calc", + "max": 1, + "min": 0, + "valType": "number" + }, + "scattergroupgap": { + "description": "Sets the gap (in plot fraction) between scatter points of the same location coordinate.", + "dflt": 0, + "editType": "calc", + "max": 1, + "min": 0, + "valType": "number" + }, + "scattermode": { + "description": "Determines how scatter points at the same location coordinate are displayed on the graph. With *group*, the scatter points are plotted next to one another centered around the shared location. With *overlay*, the scatter points are plotted over one another, you might need to reduce *opacity* to see multiple scatter points.", + "dflt": "overlay", + "editType": "calc", + "valType": "enumerated", + "values": [ + "group", + "overlay" + ] + } + }, "meta": { "description": "The scatter trace type encompasses line charts, scatter charts, text charts, and bubble charts. The data visualized as scatter point or lines is set in `x` and `y`. Text (appearing either on the chart or on hover only) is via `text`. Bubble charts are achieved by setting `marker.size` and/or `marker.color` to numerical arrays." }, From fca1c114936cf5f1240a7630f4b17e6d4b5e2410 Mon Sep 17 00:00:00 2001 From: Mojtaba Samimi Date: Mon, 12 Dec 2022 15:28:49 -0500 Subject: [PATCH 2/5] drop scattergroupgap --- src/traces/scatter/cross_trace_calc.js | 3 +-- src/traces/scatter/layout_attributes.js | 11 ----------- src/traces/scatter/layout_defaults.js | 1 - test/plot-schema.json | 8 -------- 4 files changed, 1 insertion(+), 22 deletions(-) diff --git a/src/traces/scatter/cross_trace_calc.js b/src/traces/scatter/cross_trace_calc.js index 0f0e0ba5a1b..0456de332c7 100644 --- a/src/traces/scatter/cross_trace_calc.js +++ b/src/traces/scatter/cross_trace_calc.js @@ -31,8 +31,7 @@ function groupCrossTraceCalc(gd, plotinfo) { var opts = { mode: fullLayout.scattermode, - gap: fullLayout.scattergap, - groupgap: fullLayout.scattergroupgap + gap: fullLayout.scattergap }; setGroupPositions(gd, xa, ya, calcTracesVert, opts); diff --git a/src/traces/scatter/layout_attributes.js b/src/traces/scatter/layout_attributes.js index 67d21372b33..86c2d474f47 100644 --- a/src/traces/scatter/layout_attributes.js +++ b/src/traces/scatter/layout_attributes.js @@ -26,16 +26,5 @@ module.exports = { 'adjacent location coordinates.', 'Defaults to `bargap`.' ].join(' ') - }, - scattergroupgap: { - valType: 'number', - min: 0, - max: 1, - dflt: 0, - editType: 'calc', - description: [ - 'Sets the gap (in plot fraction) between scatter points of', - 'the same location coordinate.' - ].join(' ') } }; diff --git a/src/traces/scatter/layout_defaults.js b/src/traces/scatter/layout_defaults.js index a05ff888330..37deee850db 100644 --- a/src/traces/scatter/layout_defaults.js +++ b/src/traces/scatter/layout_defaults.js @@ -13,6 +13,5 @@ module.exports = function(layoutIn, layoutOut) { if(layoutOut.scattermode === 'group') { coerce('scattergap', groupBarmode ? layoutOut.bargap : 0.2); - coerce('scattergroupgap'); } }; diff --git a/test/plot-schema.json b/test/plot-schema.json index 5f632f280ec..a049cd3f41c 100644 --- a/test/plot-schema.json +++ b/test/plot-schema.json @@ -45315,14 +45315,6 @@ "min": 0, "valType": "number" }, - "scattergroupgap": { - "description": "Sets the gap (in plot fraction) between scatter points of the same location coordinate.", - "dflt": 0, - "editType": "calc", - "max": 1, - "min": 0, - "valType": "number" - }, "scattermode": { "description": "Determines how scatter points at the same location coordinate are displayed on the graph. With *group*, the scatter points are plotted next to one another centered around the shared location. With *overlay*, the scatter points are plotted over one another, you might need to reduce *opacity* to see multiple scatter points.", "dflt": "overlay", From cc99d1861397841fbe52d1069c970f9ea797a0e7 Mon Sep 17 00:00:00 2001 From: Mojtaba Samimi Date: Tue, 20 Dec 2022 13:32:44 -0500 Subject: [PATCH 3/5] add group positioning options to scatter --- src/traces/bar/attributes.js | 23 ++---------------- src/traces/bar/defaults.js | 2 +- src/traces/box/defaults.js | 2 +- src/traces/funnel/defaults.js | 2 +- src/traces/histogram/cross_trace_defaults.js | 2 +- src/traces/scatter/attributes.js | 23 ++++++++++++++++++ src/traces/scatter/cross_trace_defaults.js | 24 +++++++++++++++++-- .../{bar => scatter}/grouping_defaults.js | 0 src/traces/waterfall/defaults.js | 2 +- test/plot-schema.json | 12 ++++++++++ 10 files changed, 64 insertions(+), 28 deletions(-) rename src/traces/{bar => scatter}/grouping_defaults.js (100%) diff --git a/src/traces/bar/attributes.js b/src/traces/bar/attributes.js index de48a83c666..12d909f4c95 100644 --- a/src/traces/bar/attributes.js +++ b/src/traces/bar/attributes.js @@ -196,27 +196,8 @@ module.exports = { marker: marker, - offsetgroup: { - valType: 'string', - dflt: '', - editType: 'calc', - description: [ - 'Set several traces linked to the same position axis', - 'or matching axes to the same', - 'offsetgroup where bars of the same position coordinate will line up.' - ].join(' ') - }, - alignmentgroup: { - valType: 'string', - dflt: '', - editType: 'calc', - description: [ - 'Set several traces linked to the same position axis', - 'or matching axes to the same', - 'alignmentgroup. This controls whether bars compute their positional', - 'range dependently or independently.' - ].join(' ') - }, + offsetgroup: scatterAttrs.offsetgroup, + alignmentgroup: scatterAttrs.alignmentgroup, selected: { marker: { diff --git a/src/traces/bar/defaults.js b/src/traces/bar/defaults.js index 419cb45c095..3ed0e57ddea 100644 --- a/src/traces/bar/defaults.js +++ b/src/traces/bar/defaults.js @@ -7,7 +7,7 @@ var Registry = require('../../registry'); var handleXYDefaults = require('../scatter/xy_defaults'); var handlePeriodDefaults = require('../scatter/period_defaults'); var handleStyleDefaults = require('./style_defaults'); -var handleGroupingDefaults = require('./grouping_defaults'); +var handleGroupingDefaults = require('../scatter/grouping_defaults'); var attributes = require('./attributes'); var coerceFont = Lib.coerceFont; diff --git a/src/traces/box/defaults.js b/src/traces/box/defaults.js index 5ecb56e0e02..f2f087b714a 100644 --- a/src/traces/box/defaults.js +++ b/src/traces/box/defaults.js @@ -4,7 +4,7 @@ var Lib = require('../../lib'); var Registry = require('../../registry'); var Color = require('../../components/color'); var handlePeriodDefaults = require('../scatter/period_defaults'); -var handleGroupingDefaults = require('../bar/grouping_defaults'); +var handleGroupingDefaults = require('../scatter/grouping_defaults'); var autoType = require('../../plots/cartesian/axis_autotype'); var attributes = require('./attributes'); diff --git a/src/traces/funnel/defaults.js b/src/traces/funnel/defaults.js index eaba2fb103b..f729bc21639 100644 --- a/src/traces/funnel/defaults.js +++ b/src/traces/funnel/defaults.js @@ -2,7 +2,7 @@ var Lib = require('../../lib'); -var handleGroupingDefaults = require('../bar/grouping_defaults'); +var handleGroupingDefaults = require('../scatter/grouping_defaults'); var handleText = require('../bar/defaults').handleText; var handleXYDefaults = require('../scatter/xy_defaults'); var handlePeriodDefaults = require('../scatter/period_defaults'); diff --git a/src/traces/histogram/cross_trace_defaults.js b/src/traces/histogram/cross_trace_defaults.js index 15eeb3c8eb7..5e09a9e34c6 100644 --- a/src/traces/histogram/cross_trace_defaults.js +++ b/src/traces/histogram/cross_trace_defaults.js @@ -4,7 +4,7 @@ var Lib = require('../../lib'); var axisIds = require('../../plots/cartesian/axis_ids'); var traceIs = require('../../registry').traceIs; -var handleGroupingDefaults = require('../bar/grouping_defaults'); +var handleGroupingDefaults = require('../scatter/grouping_defaults'); var nestedProperty = Lib.nestedProperty; var getAxisGroup = require('../../plots/cartesian/constraints').getAxisGroup; diff --git a/src/traces/scatter/attributes.js b/src/traces/scatter/attributes.js index 5a423d9741e..f6beafa16a4 100644 --- a/src/traces/scatter/attributes.js +++ b/src/traces/scatter/attributes.js @@ -123,6 +123,29 @@ module.exports = { xhoverformat: axisHoverFormat('x'), yhoverformat: axisHoverFormat('y'), + offsetgroup: { + valType: 'string', + dflt: '', + editType: 'calc', + description: [ + 'Set several traces linked to the same position axis', + 'or matching axes to the same', + 'offsetgroup where bars of the same position coordinate will line up.' + ].join(' ') + }, + + alignmentgroup: { + valType: 'string', + dflt: '', + editType: 'calc', + description: [ + 'Set several traces linked to the same position axis', + 'or matching axes to the same', + 'alignmentgroup. This controls whether bars compute their positional', + 'range dependently or independently.' + ].join(' ') + }, + stackgroup: { valType: 'string', dflt: '', diff --git a/src/traces/scatter/cross_trace_defaults.js b/src/traces/scatter/cross_trace_defaults.js index 61b4f734b57..6505c6573d7 100644 --- a/src/traces/scatter/cross_trace_defaults.js +++ b/src/traces/scatter/cross_trace_defaults.js @@ -1,9 +1,29 @@ 'use strict'; +var Lib = require('../../lib'); +var handleGroupingDefaults = require('./grouping_defaults'); +var attributes = require('./attributes'); // remove opacity for any trace that has a fill or is filled to -module.exports = function crossTraceDefaults(fullData) { - for(var i = 0; i < fullData.length; i++) { +module.exports = function crossTraceDefaults(fullData, fullLayout) { + var traceIn, traceOut, i; + + function coerce(attr) { + return Lib.coerce(traceOut._input, traceOut, attributes, attr); + } + + if(fullLayout.scattermode === 'group') { + for(i = 0; i < fullData.length; i++) { + traceOut = fullData[i]; + + if(traceOut.type === 'scatter') { + traceIn = traceOut._input; + handleGroupingDefaults(traceIn, traceOut, fullLayout, coerce); + } + } + } + + for(i = 0; i < fullData.length; i++) { var tracei = fullData[i]; if(tracei.type !== 'scatter') continue; diff --git a/src/traces/bar/grouping_defaults.js b/src/traces/scatter/grouping_defaults.js similarity index 100% rename from src/traces/bar/grouping_defaults.js rename to src/traces/scatter/grouping_defaults.js diff --git a/src/traces/waterfall/defaults.js b/src/traces/waterfall/defaults.js index 299c894e39d..e5b07290ab6 100644 --- a/src/traces/waterfall/defaults.js +++ b/src/traces/waterfall/defaults.js @@ -2,7 +2,7 @@ var Lib = require('../../lib'); -var handleGroupingDefaults = require('../bar/grouping_defaults'); +var handleGroupingDefaults = require('../scatter/grouping_defaults'); var handleText = require('../bar/defaults').handleText; var handleXYDefaults = require('../scatter/xy_defaults'); var handlePeriodDefaults = require('../scatter/period_defaults'); diff --git a/test/plot-schema.json b/test/plot-schema.json index a049cd3f41c..89dc9488fc3 100644 --- a/test/plot-schema.json +++ b/test/plot-schema.json @@ -42935,6 +42935,12 @@ "scatter": { "animatable": true, "attributes": { + "alignmentgroup": { + "description": "Set several traces linked to the same position axis or matching axes to the same alignmentgroup. This controls whether bars compute their positional range dependently or independently.", + "dflt": "", + "editType": "calc", + "valType": "string" + }, "cliponaxis": { "description": "Determines whether or not markers and text nodes are clipped about the subplot axes. To show markers and text nodes above axis lines and tick labels, make sure to set `xaxis.layer` and `yaxis.layer` to *below traces*.", "dflt": true, @@ -44893,6 +44899,12 @@ "editType": "style", "valType": "string" }, + "offsetgroup": { + "description": "Set several traces linked to the same position axis or matching axes to the same offsetgroup where bars of the same position coordinate will line up.", + "dflt": "", + "editType": "calc", + "valType": "string" + }, "opacity": { "description": "Sets the opacity of the trace.", "dflt": 1, From 918068dcbee0bb2a9e867f07be9fdb5230e99360 Mon Sep 17 00:00:00 2001 From: Mojtaba Samimi Date: Tue, 20 Dec 2022 13:56:41 -0500 Subject: [PATCH 4/5] add mock using alignmentgroup and offsetgroup --- .../zz-scatter-grouping-vs-defaults.png | Bin 0 -> 37335 bytes .../zz-scatter-grouping-vs-defaults.json | 99 ++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 test/image/baselines/zz-scatter-grouping-vs-defaults.png create mode 100644 test/image/mocks/zz-scatter-grouping-vs-defaults.json diff --git a/test/image/baselines/zz-scatter-grouping-vs-defaults.png b/test/image/baselines/zz-scatter-grouping-vs-defaults.png new file mode 100644 index 0000000000000000000000000000000000000000..42e135f68245f5cf16e0101fdb78de289ccb4acf GIT binary patch literal 37335 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 literal 0 HcmV?d00001 diff --git a/test/image/mocks/zz-scatter-grouping-vs-defaults.json b/test/image/mocks/zz-scatter-grouping-vs-defaults.json new file mode 100644 index 00000000000..6512763fdde --- /dev/null +++ b/test/image/mocks/zz-scatter-grouping-vs-defaults.json @@ -0,0 +1,99 @@ +{ + "data": [ + { + "type": "bar", + "y": [ 1, 2, 1 ], + "yaxis": "y2" + }, + { + "type": "bar", + "y": [ 2, 1, 2 ] + }, + { + "type": "bar", + "y": [ 1, 3, 0 ] + }, + { + "type": "bar", + "y": [ 1, 2, 1 ], + "alignmentgroup": "top", + "hovertext": "alignmentgroup: top", + "xaxis": "x2", + "yaxis": "y2" + }, + { + "type": "bar", + "y": [ 2, 1, 2 ], + "hovertext": "alignmentgroup: top
offsetgroup: 1", + "alignmentgroup": "bottom", + "offsetgroup": "1", + "xaxis": "x2" + }, + { + "type": "bar", + "y": [ 1, 3, 0 ], + "hovertext": "alignmentgroup: top
offsetgroup: 2", + "alignmentgroup": "bottom", + "offsetgroup": "2", + "xaxis": "x2" + }, + { + "type": "scatter", + "y": [ 1, 2, 1 ], + "yaxis": "y2" + }, + { + "type": "scatter", + "y": [ 2, 1, 2 ] + }, + { + "type": "scatter", + "y": [ 1, 3, 0 ] + }, + { + "type": "scatter", + "y": [ 1, 2, 1 ], + "alignmentgroup": "top", + "hovertext": "alignmentgroup: top", + "xaxis": "x2", + "yaxis": "y2" + }, + { + "type": "scatter", + "y": [ 2, 1, 2 ], + "hovertext": "alignmentgroup: top
offsetgroup: 1", + "alignmentgroup": "bottom", + "offsetgroup": "1", + "xaxis": "x2" + }, + { + "type": "scatter", + "y": [ 1, 3, 0 ], + "hovertext": "alignmentgroup: top
offsetgroup: 2", + "alignmentgroup": "bottom", + "offsetgroup": "2", + "xaxis": "x2" + } + ], + "layout": { + "scattermode": "group", + "showlegend": false, + "grid": { + "rows": 2, + "columns": 2, + "roworder": "bottom to top" + }, + "colorway": [ "blue", "orange", "green" ], + "margin": { "t": 20 }, + "xaxis": { + "title": { + "text": "no alignmentgroup
no offsetgroup" + } + }, + "xaxis2": { + "title": { + "text": "with alignmentgroup
with offsetgroup" + } + } + } +} From e98f3c6748bf6a8bb55138d8ee98034e746220c6 Mon Sep 17 00:00:00 2001 From: Mojtaba Samimi Date: Wed, 21 Dec 2022 09:29:26 -0500 Subject: [PATCH 5/5] draft log for PR 6381 --- draftlogs/6381_add.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 draftlogs/6381_add.md diff --git a/draftlogs/6381_add.md b/draftlogs/6381_add.md new file mode 100644 index 00000000000..562a5f008f5 --- /dev/null +++ b/draftlogs/6381_add.md @@ -0,0 +1,2 @@ + - Introduce group attributes for `scatter` trace i.e. `alignmentgroup`, `offsetgroup`, `scattermode` and `scattergap` [[#6381](https://github.com/plotly/plotly.js/pull/6381)], + this feature was anonymously sponsored: thank you to our sponsor!