@@ -22,6 +22,7 @@ function updateScatter(obj,plotIndex)
22
22
obj.data{plotIndex }.type = ' scatter' ;
23
23
obj.data{plotIndex }.xaxis = sprintf(' x%d ' , xSource );
24
24
obj.data{plotIndex }.yaxis = sprintf(' y%d ' , ySource );
25
+ updateCategoricalAxis(obj , plotIndex );
25
26
else
26
27
obj.data{plotIndex }.type = ' scatter3d' ;
27
28
obj.data{plotIndex }.scene = sprintf(' scene%d ' , xSource );
@@ -36,8 +37,9 @@ function updateScatter(obj,plotIndex)
36
37
% -------------------------------------------------------------------------%
37
38
38
39
% -set trace data-%
39
- obj.data{plotIndex }.x = plotData .XData ;
40
- obj.data{plotIndex }.y = plotData .YData ;
40
+ [xData , yData ] = getTraceData2D(plotData );
41
+ obj.data{plotIndex }.x = xData ;
42
+ obj.data{plotIndex }.y = yData ;
41
43
42
44
if isScatter3D
43
45
obj.data{plotIndex }.z = plotData .ZData ;
@@ -214,3 +216,119 @@ function updateScene(obj, dataIndex)
214
216
% -------------------------------------------------------------------------%
215
217
end
216
218
219
+ function updateCategoricalAxis(obj , plotIndex )
220
+
221
+ % -INITIALIZATIONS-%
222
+ axIndex = obj .getAxisIndex(obj .State .Plot(plotIndex ).AssociatedAxis);
223
+ [xSource , ySource ] = findSourceAxis(obj ,axIndex );
224
+ plotData = get(obj .State .Plot(plotIndex ).Handle);
225
+
226
+ xData = plotData .XData ;
227
+ yData = plotData .YData ;
228
+
229
+ if iscategorical(xData )
230
+ ax = eval(sprintf(' obj.layout.xaxis%d ' , xSource ));
231
+ nTicks = length(ax .ticktext );
232
+
233
+ ax.autorange = false ;
234
+ ax.range = 0.5 + [0 nTicks ];
235
+ ax.type = ' linear' ;
236
+ ax.tickvals = 1 : nTicks ;
237
+
238
+ eval(sprintf(' obj.layout.xaxis%d = ax;' , xSource ));
239
+ end
240
+
241
+ if iscategorical(yData )
242
+ ax = eval(sprintf(' obj.layout.yaxis%d ' , ySource ));
243
+ nTicks = length(ax .ticktext );
244
+
245
+ ax.autorange = false ;
246
+ ax.range = 0.5 + [0 nTicks ];
247
+ ax.type = ' linear' ;
248
+ ax.tickvals = 1 : nTicks ;
249
+
250
+ eval(sprintf(' obj.layout.yaxis%d = ax;' , ySource ));
251
+ end
252
+ end
253
+
254
+ function [xData , yData ] = getTraceData2D(plotData )
255
+
256
+ % -initializations-%
257
+ isSwarmchart = isfield(plotData , ' XJitter' );
258
+ xData = categ2NumData(plotData .XData );
259
+ yData = categ2NumData(plotData .YData );
260
+
261
+ % -get 2D trace data-%
262
+ if isSwarmchart
263
+ if ~strcmp(plotData .XJitter , ' none' )
264
+ xData = setJitData(xData , yData , plotData , ' X' );
265
+
266
+ elseif ~strcmp(plotData .XJitter , ' none' )
267
+ yData = setJitData(yData , xData , plotData , ' Y' );
268
+ end
269
+ end
270
+ end
271
+
272
+ function jitData = setJitData(jitData , refData , plotData , axName )
273
+ jitType = eval(sprintf(' plotData.%s Jitter' , axName ));
274
+ jitWidth = eval(sprintf(' plotData.%s JitterWidth' , axName ));
275
+ jitUnique = sort(unique(jitData ), ' ascend' );
276
+ jitWeight = getJitWeight(jitData , refData );
277
+ isJitDensity = strcmp(jitType , ' density' );
278
+
279
+ for n = 1 : length(jitUnique )
280
+ jitInd = find(jitData == jitUnique(n ));
281
+
282
+ if length(jitInd ) > 1
283
+ jitDataN = getJitData(refData(jitInd ), jitWidth , jitType );
284
+ if isJitDensity , jitDataN = jitWeight(n )*jitDataN ; end
285
+ jitData(jitInd ) = jitData(jitInd ) + jitDataN ;
286
+ end
287
+ end
288
+ end
289
+
290
+ function jitWeight = getJitWeight(jitData , refData )
291
+ jitUnique = sort(unique(jitData ), ' ascend' );
292
+
293
+ for n = 1 : length(jitUnique )
294
+ jitInd = find(jitData == jitUnique(n ));
295
+
296
+ if length(jitInd ) > 1
297
+ refDataN = refData(jitInd );
298
+ stdData(n ) = std( refDataN(~isnan(refDataN )) );
299
+ end
300
+ end
301
+
302
+ jitWeight = ( stdData / min(stdData ) ).^(-1 );
303
+ end
304
+
305
+ function jitData = getJitData(refData , jitWeight , jitType )
306
+ jitData = rand(size(refData )) - 0.5 ;
307
+
308
+ if strcmp(jitType , ' density' )
309
+ refPoints = linspace(min(refData ), max(refData ), 2 * length(refData ));
310
+ [densityData , refPoints ] = ksdensity(refData , refPoints );
311
+ densityData = jitWeight * rescale(densityData , 0 , 1 );
312
+
313
+ for n = 1 : length(refData )
314
+ [~ , refInd ] = min(abs(refPoints - refData(n )));
315
+ jitData(n ) = jitData(n ) * densityData(refInd );
316
+ end
317
+
318
+ elseif strcmp(jitType , ' rand' )
319
+ jitData = jitWeight * jitData ;
320
+
321
+ elseif strcmp(jitType , ' rand' )
322
+ jitData = jitWeight * rescale(randn(size(refData )), - 0.5 , 0.5 );
323
+
324
+ end
325
+ end
326
+
327
+ function numData = categ2NumData(categData )
328
+ numData = categData ;
329
+
330
+ if iscategorical(categData )
331
+ [~ , ~ , numData ] = unique(numData );
332
+ numData = numData ' ;
333
+ end
334
+ end
0 commit comments