Skip to content

rs_disp_coordsets(data_in, aux)

aux_out=rs_disp_coordsets(data_in,aux) displays one or more views of pairs or triplets of coordinates in a dataset structure

Multiple views can be plotted, one eachin a subplot of the same figure. This is particularly helpful if the dimensionality of the coordinates is high: each subplot could show a different combination of two or three coordinates. Plots of two coordinates will produce a planar view; plots of three coordinates will produce an isometric 3D view. Subplots are left in the 'hold on' state.

Input arguments:

  • data_in (struct) –

    dataset structure to be processed, with fields

  • aux (struct) –

    auxiliary inputs, may be omitted, with fields

    • opts_disp (struct) – options for display, with fields to contol
        Data selection
        • set_select (int 1-D array) – list of records to show; defaults is [1:length(data_in.ds)]
        • dim_select (int) – dimension to show (>=2); i.e., dim_select=k results in display of the coordinates in data_in.ds{set_select}{k}; default is 3 unless only two dimensions are available; must be at least 2
        • coord_group_size (int) – number of coordinates to display together, in range [2 3]; default is min(dim_select,number of dimensions available,3)
        • coord_group_method (char) – method of selecting coordinates
          • 'all': (default) plot all combinations
          • 'keeplow': keep 1 to dim_select-1 and step the highest; [dim_select,coord_group_size]=[5,3] yields [1 2 3],[1 2 4],[1 2 5]
          • 'keepone': keep one dimension and step the rest; [dim_select,coord_group_size]=[5,3] yields [1 2 3],[1 2 4],[1 2 5],[1 3 4],[1 3 5],[1 4 5]
          • 'rolling': rolling contiguous subsets; [dim_select,coord_group_size]=[5,3] yields [1 2 3],[2 3 4],[3 4 5],[4 5 1],[5 1 2]
          • 'onlylowest': only the lowest dimensions; [dim_select,coord_group_size]=[5,3] yields [1 2 3]
          • 'list': specify a list in opts_disp.coord_groups, as an array with coord_group_size columns, e.g., opts_disp.coord_groups=[1 2 3;1 4 5;1 6 7] creates three subplots, with coordinates {1,2,3} in the first, {1,4,5} in the second, {1,6,7} in the third
        • coord_groups (int 2-D array) – groups of coordinates to show together if coord_group_method='list', as rows (of length coord_group_size) of an integer array; each row will generate one subplot
        • data_show_method (char) – which data points to show, options are 'all', 'none', 'first', 'last', 'list'; default is 'all'
        • data_show_list (int 1-D array) – list of data points to show, if data_show_method='list'; points plotted are data_in.ds{set_select}{k}(data_show_list,:); This applies to data in all records. To disable display of individual data points in specific records, set their coordinates to NaN.

        Figure and subplot control

        • fig_handle (handle) – handle to figure; will be created if empty or not provided
        • fig_position (int 1-D array) – position parameters [left bottom width height] for figure to be created; see note below regarding customization
        • fig_name (char) – title for figure; default is dimension shown
        • axis_handles (cell array of handles) – handle to axes, one for each subplot, will be created empty or not provided

        Labels

        • set_labels (char or cell array of char) – labels for each record that will appear in legend; defaults is 'set 1', etc.; cannot be empty; see note regarding plot formatting
        • data_label_setsel_method (char) – selects which records to label individual points, options are 'all','none', 'first' , 'last', or 'list'; default is 'first'; note that 'all','first', and 'last' apply to the records shown
        • data_label_setsel_list (int 1-D array) – list of datasets to label, if data_label_setsel_method='list'
        • data_label_method (char) – selects which data points to label, options are 'all', 'none', 'first', 'last', 'list'; default is 'all'; labels are taken from data_in.sas{k}.typenames; note that 'all','first',and 'last' refer to data points shown
        • data_label_list (int 1-D array) – list of data points to label, if data_label_method='list'
        • data_label_font_size (int) – font size for data labels, default is axis_font_size
        • data_label_interpreter (char) – interpreter for labeling data, [] (default) uses system default, alternatively 'none','tex','latex'
        • data_label_typenames_vary (int) – 1 to allow typenames to vary across datasets, 0 does not; default is 0
        • callout_amount (float) – moves the position of a label away from the data point, specified in units of rms deviation of data from callout_center; default is 0
        • callout_colors (cell array of color specifiers) – color for callout lines connecting labels and points; default is {'k'}; can also be 'set_colors' to match set_colors
        • callout_linestyles (cell array of char) – line styles for above callout lines; default is {'-.'}
        • callout_linewidths (int 1-D array) – line widths for above callout lines; default is 1
        • callout_center (char or int 1-D array) – callout lines point from the specified location outward; default is 'centroid' (centroid of data), can also be 'zero' or a coordinate value, of length 'dim_select'

        Formatting: axis and views

        • axis_font_size (int) – font size for axis; default is 8; see note below re customization
        • axis_label_font_size (char) – font size for axis labels; default is axis_font_size
        • axis_label_prefix (char) – prefix for axis label, default is 'coord'; see note below regarding customization
        • axis_labels (cell array of char) – cell array of strings, cycled through if necessary, with text for axis labels. If empty, then axis labels are genrated from axis_label_prefix
        • axis_view (int or float 1-D array or cell array) – 3-D view descriptor, default is 3 (standard 3-d view), 2 is 2-d view; can also be azimuth-elevation pair; standard 3-d view is [-37.5 30]; can be also be cell array of view specifiers, is cycled through for each subplot
        • axis_equal (int) – 1 to set axes to have equal scales, 0 autoscales; default is 1
        • axis_range (char) – 'tight' to set axis range to limits of data, 'auto' for autoscaling, or 'list' to specify by axis_range_list; default is 'tight'
        • axis_range_list (float 2-D array) – axis range specification, as rows of [low, high] values, one for each coordinate plotted; cycled through by rows if necessary

        Formatting: points and lines for each record

        • set_colors (color specifier or cell array of color specifiers) – color assigned to each record; default is {'k','b','c','m','r',[0.5 0.5 0],'g'}; elements can be any valid color specifier; see note regarding plot formatting
        • set_markers (char or cell array of char) – marker for each record; defaults is {'.'}; see note below regarding plot formatting
        • set_markersizes (int 1-D array) – marker size for each record; default is 8; see below note regarding plot formatting
        • set_filled (int 1-D array) – 1 for records in which markers are filled, 0 for unfilled if possible; default is 0; note that only some marker, e.g., o,s,h,p can be unfilled
        • set_colors_filled (color specifer or cell array of color specifiers) – color for inside of filled symbols for each record, ignored if set_filled=0; default is set_colors
        • set_alphas (float 1-D array) – alpha blending for each record, default is 1 (opaque); note that alpha-blending (transparency) may not be availble on all systems
        • connect_data_method (char) – which pairs of data points to connect within a record; default is 'none'; options refer to the points selected for display by 'data_show_method'; see note below regarding plot formatting
          • 'none': no connections between points
          • 'all': connect all pairs of points
          • 'star' or 'star_first': connect all points to first
          • 'star_last': connect all points to last
          • 'chain': connect first point =to second, second point to third, ..., and next-to-last point to last point
          • 'circuit': same as 'chain' but adds a connection from last point to first
          • 'list': specify the pairs of points in connect_data_list
        • connect_data_list (int 2-D array) – two-column array of data points to connect (if connect_data_method='list')
        • connect_data_linestyles (char or cell array of char) – line styles assigned to connections within each record, default is 'none' (disconnected)
        • connect_data_linewidths (int 1-D array) – line widths for connections within each record; default is 1

        Formatting: connections between records

        • connect_sets_method (char) – which records to connect; default is 'none'; options refer to the records selected for display by 'set_select'; see note below regarding plot formatting
          • 'none': no connections between data from different records
          • 'all': connect all pairs of records
          • 'star' or 'star_first': connect all records to first
          • 'star_last': connect all records to last
          • 'chain': connect first record to second, second record to third, ..., and next-to-last record to last record
          • 'circuit': same as 'chain' but adds a connection from last record to first
          • 'list': specify the pairs of records in connect_sets_list
        • connect_sets_list (int 2-D array) – two-column array of records to connect, used if connect_sets_method='list'
        • connect_sets_data_method (char) – selects the data points to connect between records: any of the options for data_label_method or 'labeled', which connects all data points designated by 'data_label_method'; default is 'all'
        • connect_sets_data_list (int 1-D array) – data points to connect between records, if connect_sets_data_method='list'
        • connect_sets_color_mode (char) – specifies how the connecting semgent between records is colored; default is 'split'
          • 'first': use color of first record in connected pair
          • 'last': use color of last record in connected pair
          • 'split': first half of segment matches first record in connected pair; second half of segmentmatches second record in connected pair
          • 'list': specify colors in connect_sets_colors
        • connect_sets_colors (color specifier or cell array of color specifiers) – if connect_sets_color_mode='list';, these are the colors for for connecting segments; cycled through if necessary
        • connect_sets_linestyles (char or cell array of char) – line styles assigned to connections between records; default is '-' (solid); cycled through if necessary
        • connect_sets_linewidths (int 1-D array) – line widths assigned to connections between records; default is 1; cycled through if necessary

        Formatting: positioning

        • set_offsets (float 2-D array or char) – this allows the data in each record to be offset to avoid overlap; default is no offset; specified by 0
          • if an array, each row, of length dim_select (which wll be truncated or padded as needed) specifies the offset for the corresponding record in data_in
          • 'margin_amount' puts a margin of set_offsets_margin_amount between each dataset and the next
          • 'margin_fraction' puts a fractional margin of set_offsets_margin_fraction * average span of adjacent sets
        • set_offsets_margin_amount (float 1-D array) – absolute margin between datasets if set_offsets='margin_amount; defaults to ones(1,dim_select); can be 0 or negative, truncated or padded to dim_select
        • set_offsets_margin_fraction (float 1-D array) – fractional margin between datasets if set_offsets='margin_fraction; defaults to zeros(1,dim_select); can be 0 or negative, truncated or padded to dim_select
        • set_offsets_coordchoices (int or char or cell array of char) – if set_offsets='margin_amount' or 'margin_fraction', this specifies which coordinate is offset; can be 'first','last','all', or a subset of [1:dim_select]; can also be a cell array of subsets

        Formatting: perpendiculars from points to walls

        • perp_data_dims (int or int 1-D array) – 1 to drop perpendiculars along that dimension,-1 for perpendicular to top, 0 to omit; default is 0; cycled through if necessary
        • perp_data_linestyles (char or cell array of char) – line styles for perpendiculars for each record, or 'use_data' to use the style specified by 'connect_data_linestyles' for connecting data points; default is '-' (solid); cycled through if necessary
        • perp_data_linewidths (int 1-D array) – line widths for perpendiculars for each record; default is 1
        • perp_data_usemarkers (int) – 1 to use markers from original data at foot of perpendicular, 0 for no markers; default is 1

        Formatting: legend, box, grid

        • if_legend (int) – 1 to include legend, 0 to omit, -1 to omit from all subplots but to create an extra subplot that only has the legend; default is 1
        • legend_font_size (int) – font size for legend; default is axis_font_size
        • legend_location (char) – location of legend within plot; any Matlab designator accepted; default is 'Best'
        • legend_interpreter (char) – interpreter for record labels in legend, [] (default) uses system default, alternatively 'none','tex','latex'
        • legend_tags (char) – single string that must be present in a dataset's tag for inclusion in a legend, default is 'set';
        • set_tags (char or cell array of char) – the 'tags' field applied to the plot of each record, for selecting which records appear in legend, default is 'set 1', etc.
        • if_box (int) – 1 to include the bounding box in a 3d plot, 0 to omit; default is 1
        • if_grid (int) – 1 to include the grid, 0 to omit; default is 1
        • if_finalize (int) – 1 to apply view, legend, labels, and perpendiculars, 0 to omit; default is 1
    • if_warn (int) – 1 to display warnings related to plot configurations, 0 to suppress; default is 1
    • opts_check (struct) – options for consistency checking, with field
      • if_warn (int) – 1 to show warnings when datasets are checked for consistency, 0 to suppress; default is 1

Output arguments:

  • aux_out ( struct ) –

    auxiliary outputs and parameter values used, with fields

    • warnings (char) – warnings generated during consistency check
    • warn_bad (int) – number of warnings that prevent further processing
    • opts_disp (struct) – aux.opts_disp, with defaults and overrides filled in, including fig_handle (handle to the figure) and axis_handles (handles to the subplot axes)
Note regarding customization
  • The default figure position can be changed by editing the line containing generic.opts_disp.fig_position in rs_aux_defaults_define, running it once, and saving the workspace as rs_aux_defaults.mat.
  • The default font size for axis labels can be changed by editing the line containing generic.opts_disp.axis_font_size in rs_aux_defaults_define, running it once, and saving the workspace as rs_aux_defaults.mat.
  • The default prefix for the axis label can be changed by editing the line containing generic.opts_disp.axis_label_prefix in rs_aux_defaults_define, running it once, and saving the workspace as rs_aux_defaults.mat.
Note regarding plot formatting
  • By default, each record is plotted with a different color, a solid dot marker, and no connecting lines.
  • These choices can be changed by 'set_colors', 'set_markers', 'set_markersizes', 'set_filled', 'set_colors_filled', 'set_alphas' (but alpha blending may not be availble on all systems).
  • The above specifiers can be singletons or cell arrays, and are indexed by the record position in data_in. If there are more records than specifiers, the specifiers are cycled.
  • The data points of each record are, by default, not interconnected. This can be changed with the 'connect_data*' options.
  • The data points between records are, by default, not interconnected . This can be changed with the 'connect_sets*' options.

See also: rs_disp_enh_coordsets, rs_check_coordsets, rs_get_coordsets, rs_align_coordsets, rs_knit_coordsets, rs_plot_style.

Source code in src/rs_disp_coordsets.m
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
function aux_out=rs_disp_coordsets(data_in,aux)
% aux_out=rs_disp_coordsets(data_in,aux) displays one or more views of pairs or triplets of coordinates in a `dataset structure`
%
% Multiple views can be plotted, one eachin a subplot of the same figure. This is particularly helpful if the dimensionality
% of the coordinates is high:  each subplot could show a different combination of two or three coordinates.
% Plots of two coordinates will produce a planar view; plots of three coordinates will produce an isometric 3D view. Subplots are left in the 'hold on' state.
%
% Args:
%   data_in (struct): `dataset structure` to be processed, with fields
%
%     - ds (cell array): `coordinate structure`, ds{k}{idim} is an array of [nstims idim] of coordinates for the kth record
%     - sas (cell array): `stimulus metadata structure`, sas{k} is the stimulus metadata for the kth record
%     - sets (cell array): `set metadata structure`, sets{k} is the response metadata for the kth record
%
%   aux (struct): auxiliary inputs, may be omitted, with fields
%
%     - opts_disp (struct): options for display, with fields to contol
%
%         - **Data selection**
%         - set_select (int 1-D array): list of records to show; defaults is [1:length(data_in.ds)]
%         - dim_select (int): dimension to show (>=2); i.e., dim_select=k results in display of the coordinates in data_in.ds{set_select}{k}; default is 3 unless only two dimensions are available; must be at least 2
%         - coord_group_size (int): number of coordinates to display together, in range [2 3]; default is min(dim_select,number of dimensions available,3)
%         - coord_group_method (char): method of selecting coordinates
%
%             - 'all': (default) plot all combinations
%             - 'keeplow': keep 1 to dim_select-1 and step the highest; [dim_select,coord_group_size]=[5,3] yields [1 2 3],[1 2 4],[1 2 5]
%             - 'keepone': keep one dimension and step the rest;        [dim_select,coord_group_size]=[5,3] yields [1 2 3],[1 2 4],[1 2 5],[1 3 4],[1 3 5],[1 4 5]
%             - 'rolling': rolling contiguous subsets;                  [dim_select,coord_group_size]=[5,3] yields [1 2 3],[2 3 4],[3 4 5],[4 5 1],[5 1 2]
%             - 'onlylowest': only the lowest dimensions;               [dim_select,coord_group_size]=[5,3] yields [1 2 3]
%             - 'list': specify a list in opts_disp.coord_groups, as an array with coord_group_size columns, e.g., opts_disp.coord_groups=[1 2 3;1 4 5;1 6 7] creates three subplots, with coordinates {1,2,3} in the first, {1,4,5} in the second, {1,6,7} in the third
%
%         - coord_groups (int 2-D array): groups of coordinates to show together if coord_group_method='list', as rows (of length coord_group_size) of an integer array; each row will generate one subplot
%         - data_show_method (char): which data points to show, options are 'all', 'none', 'first', 'last', 'list'; default is 'all'
%         - data_show_list (int 1-D array): list of data points to show, if data_show_method='list';  points plotted are data_in.ds{set_select}{k}(data_show_list,:);  This applies to data in all records. To disable display of individual data points in specific records, set their coordinates to NaN.
%
%         - **Figure and subplot control**
%         - fig_handle (handle): handle to figure; will be created if empty or not provided
%         - fig_position (int 1-D array): position parameters [left bottom width height] for figure to be created; see note below regarding customization
%         - fig_name (char): title for figure; default is dimension shown
%         - axis_handles (cell array of handles): handle to axes, one for each subplot, will be created empty or not provided
%
%         - **Labels**
%         - set_labels (char or cell array of char): labels for each record that will appear in legend; defaults is 'set 1', etc.; cannot be empty; see note regarding plot formatting
%         - data_label_setsel_method (char): selects which records to label individual points, options are 'all','none', 'first' , 'last', or 'list'; default is 'first'; note that 'all','first', and 'last' apply to the records shown
%         - data_label_setsel_list (int 1-D array): list of datasets to label, if data_label_setsel_method='list'
%         - data_label_method (char): selects which data points to label, options are 'all', 'none', 'first', 'last', 'list'; default is 'all'; labels are taken from data_in.sas{k}.typenames; note that 'all','first',and 'last' refer to data points shown
%         - data_label_list (int 1-D array): list of data points to label, if data_label_method='list'
%         - data_label_font_size (int): font size for data labels, default is axis_font_size
%         - data_label_interpreter (char): interpreter for labeling data, [] (default) uses system default, alternatively 'none','tex','latex'
%         - data_label_typenames_vary (int): 1 to allow typenames to vary across datasets, 0 does not; default is 0
%         - callout_amount (float): moves the position of a label away from the data point, specified in units of rms deviation of data from callout_center; default is 0
%         - callout_colors (cell array of color specifiers): color for callout lines connecting labels and points; default is {'k'}; can also be 'set_colors' to match set_colors
%         - callout_linestyles (cell array of char): line styles for above callout lines; default is {'-.'}
%         - callout_linewidths (int 1-D array): line widths for above callout lines; default is 1
%         - callout_center (char or int 1-D array): callout lines point from the specified location outward; default is 'centroid' (centroid of data), can also be 'zero' or a coordinate value, of length 'dim_select' 
%
%         - **Formatting: axis and views**
%         - axis_font_size (int): font size for axis; default is 8; see note below re customization
%         - axis_label_font_size (char): font size for axis labels; default is axis_font_size
%         - axis_label_prefix (char): prefix for axis label, default is 'coord'; see note below regarding customization
%         - axis_labels (cell array of char): cell array of strings, cycled through if necessary, with text for axis labels.  If empty, then axis labels are genrated from axis_label_prefix
%         - axis_view (int or float 1-D array or cell array): 3-D view descriptor, default is 3 (standard 3-d view), 2 is 2-d view; can also be azimuth-elevation pair; standard 3-d view is [-37.5 30]; can be also be cell array of view specifiers, is cycled through for each subplot
%         - axis_equal (int): 1 to set axes to have equal scales, 0 autoscales; default is 1
%         - axis_range (char): 'tight' to set axis range to limits of data, 'auto' for autoscaling, or 'list' to specify by axis_range_list; default is 'tight'
%         - axis_range_list (float 2-D array): axis range specification, as rows of [low, high] values, one for each coordinate plotted; cycled through by rows if necessary
%
%         - **Formatting: points and lines for each record**
%         - set_colors (color specifier or cell array of color specifiers): color assigned to each record; default is {'k','b','c','m','r',[0.5 0.5 0],'g'}; elements can be any valid color specifier; see note regarding plot formatting
%         - set_markers (char or cell array of char): marker for each record; defaults is {'.'}; see note below regarding plot formatting
%         - set_markersizes (int 1-D array): marker size for each record; default is 8; see below note regarding plot formatting
%         - set_filled (int 1-D array): 1 for records in which markers are filled, 0 for unfilled if possible; default is 0; note that only some marker, e.g., o,s,h,p can be unfilled
%         - set_colors_filled (color specifer or cell array of color specifiers): color for inside of filled symbols for each record, ignored if set_filled=0; default is set_colors
%         - set_alphas (float 1-D array): alpha blending for each record, default is 1 (opaque); note that alpha-blending (transparency) may not be availble on all systems
%         - connect_data_method (char): which pairs of data points to connect within a record; default is 'none'; options refer to the points selected for display by 'data_show_method'; see note below regarding plot formatting
%
%             - 'none': no connections between points
%             - 'all': connect all pairs of points
%             - 'star' or 'star_first': connect all points to first
%             - 'star_last': connect all points to last
%             - 'chain': connect first point =to second, second point to third, ..., and next-to-last point to last point
%             - 'circuit': same as 'chain' but adds a connection from last point to first
%             - 'list': specify the pairs of points in connect_data_list
% 
%         - connect_data_list (int 2-D array): two-column array of data points to connect (if connect_data_method='list')
%         - connect_data_linestyles (char or cell array of char): line styles assigned to connections within each record, default is 'none' (disconnected)
%         - connect_data_linewidths (int 1-D array): line widths for connections within each record; default is 1
%
%         - **Formatting: connections between records**
%         - connect_sets_method (char): which records to connect; default is 'none'; options refer to the records selected for display by 'set_select'; see note below regarding plot formatting
%
%             - 'none': no connections between data from different records
%             - 'all': connect all pairs of records
%             - 'star' or 'star_first': connect all records to first
%             - 'star_last': connect all records to last
%             - 'chain': connect first record to second, second record to third, ..., and next-to-last record to last record
%             - 'circuit': same as 'chain' but adds a connection from last record to first
%             - 'list': specify the pairs of records in connect_sets_list
% 
%         - connect_sets_list(int 2-D array): two-column array of records to connect, used if connect_sets_method='list'
%         - connect_sets_data_method (char): selects the data points to connect between records: any of the options for data_label_method or 'labeled', which connects all data points designated by 'data_label_method'; default is 'all'
%         - connect_sets_data_list (int 1-D array): data points to connect between records, if connect_sets_data_method='list'
%         - connect_sets_color_mode (char): specifies how the connecting semgent between records is colored; default is 'split'
%
%             - 'first': use color of first record in connected pair
%             - 'last': use color of last record in connected pair
%             - 'split': first half of segment matches first record in connected pair; second half of segmentmatches second record in connected pair
%             - 'list': specify colors in connect_sets_colors
%
%         - connect_sets_colors (color specifier or cell array of color specifiers): if connect_sets_color_mode='list';, these are the colors for for connecting segments; cycled through if necessary
%         - connect_sets_linestyles (char or cell array of char): line styles assigned to connections between records; default is  '-' (solid); cycled through if necessary
%         - connect_sets_linewidths (int 1-D array): line widths assigned to connections between records; default is 1; cycled through if necessary
%
%         - **Formatting: positioning** 
%         - set_offsets (float 2-D array or char): this allows the data in each record to be offset to avoid overlap; default is no offset; specified by 0
%
%              - if an array, each row, of length dim_select (which wll be truncated or padded as needed) specifies the offset for the corresponding record in `data_in`
%              - 'margin_amount' puts a margin of set_offsets_margin_amount between each dataset and the next
%              - 'margin_fraction' puts a fractional margin of set_offsets_margin_fraction * average span of adjacent sets
%
%         - set_offsets_margin_amount (float 1-D array): absolute margin between datasets if set_offsets='margin_amount; defaults to ones(1,dim_select); can be 0 or negative, truncated or padded to dim_select
%         - set_offsets_margin_fraction (float 1-D array): fractional margin between datasets if set_offsets='margin_fraction; defaults to zeros(1,dim_select); can be 0 or negative, truncated or padded to dim_select
%         - set_offsets_coordchoices (int or char or cell array of char): if set_offsets='margin_amount' or 'margin_fraction', this specifies which coordinate is offset; can be 'first','last','all', or a subset of [1:dim_select]; can also be a cell array of subsets
%
%         - **Formatting: perpendiculars from points to walls**
%         - perp_data_dims (int or int 1-D array): 1 to drop perpendiculars along that dimension,-1 for perpendicular to top, 0 to omit; default is 0; cycled through if necessary
%         - perp_data_linestyles (char or cell array of char): line styles for perpendiculars for each record, or 'use_data' to use the style specified by 'connect_data_linestyles' for connecting data points; default is '-' (solid); cycled through if necessary
%         - perp_data_linewidths (int 1-D array): line widths for perpendiculars for each record; default is 1
%         - perp_data_usemarkers (int): 1 to use markers from original data at foot of perpendicular, 0 for no markers; default is 1
%
%         - **Formatting: legend, box, grid**
%
%         - if_legend (int): 1 to include legend, 0 to omit, -1 to omit from all subplots but to create an extra subplot that only has the legend; default is 1
%         - legend_font_size (int): font size for legend; default is axis_font_size
%         - legend_location (char): location of legend within plot; any Matlab designator accepted; default is 'Best'
%         - legend_interpreter (char): interpreter for record labels in legend, [] (default) uses system default, alternatively 'none','tex','latex'
%         - legend_tags (char): single string that must be present in a dataset's tag for inclusion in a legend, default is 'set';
%         - set_tags (char or cell array of char): the 'tags' field applied to the plot of each record, for selecting which records appear in legend, default is  'set 1', etc.
%         - if_box (int): 1 to include the bounding box in a 3d plot, 0 to omit; default is 1
%         - if_grid (int): 1 to include the grid, 0 to omit; default is 1
%         - if_finalize (int): 1 to apply view, legend, labels, and perpendiculars, 0 to omit; default is 1
%
%        - if_warn (int): 1 to display warnings related to plot configurations, 0 to suppress; default is 1
%
%     - opts_check (struct): options for consistency checking, with field
%
%         - if_warn (int): 1 to show warnings when datasets are checked for consistency, 0 to suppress; default is 1
% 
% Returns:
%   aux_out (struct): auxiliary outputs and parameter values used, with fields
%
%     - warnings (char): warnings generated during consistency check
%     - warn_bad (int): number of warnings that prevent further processing
%     - opts_disp (struct): aux.opts_disp, with defaults and overrides filled in, including fig_handle (handle to the figure) and axis_handles (handles to the subplot axes)
%
% Note: Note regarding customization
%     - The default figure position can be changed by editing the line containing generic.opts_disp.fig_position in `rs_aux_defaults_define`, running it once, and saving the workspace as rs_aux_defaults.mat.
%     - The default font size for axis labels can be changed by editing the line containing generic.opts_disp.axis_font_size in `rs_aux_defaults_define`, running it  once, and saving the workspace as rs_aux_defaults.mat.
%     - The default prefix for the axis label can be changed by editing the line containing generic.opts_disp.axis_label_prefix in `rs_aux_defaults_define`, running it  once, and saving the workspace as rs_aux_defaults.mat.
%
% Note: Note regarding plot formatting
%     - By default, each record is plotted with a different color, a solid dot marker, and no connecting lines. 
%     - These choices can be changed by 'set_colors', 'set_markers',  'set_markersizes', 'set_filled', 'set_colors_filled', 'set_alphas' (but alpha blending may not be availble on all systems).
%     - The above specifiers can be singletons or cell arrays, and are indexed by the record position in data_in.  If there are more records than specifiers, the specifiers are cycled.
%     - The data points of each record are, by default, not interconnected. This can be changed with the 'connect_data*' options.
%     - The data points between records are, by default, not interconnected . This can be changed with the 'connect_sets*' options.
%
%  See also: RS_DISP_ENH_COORDSETS, RS_CHECK_COORDSETS, RS_GET_COORDSETS, RS_ALIGN_COORDSETS, RS_KNIT_COORDSETS, RS_PLOT_STYLE.
%
if (nargin<=1)
    aux=struct;
end
%fields that will be made into cells if singletons
make_cell={'set_colors','set_colors_filled','set_markers','connect_data_linestyles','set_labels','set_tags','legend_tags','axis_view','connect_sets_linestyles','connect_sets_colors',...
    'callout_colors','callout_linestyles','axis_labels','perp_data_linestyles'};
trunc_pad={'set_offsets','set_offsets_margin_amount','set_offsets_margin_fraction'}; %fields that are truncated or padded to have dim 2 length = dim_select
coords_together_allowed=[2 3]; %how many coords can be plotted together -eventually could include >=4
coords_together_default=[2 3]; %how many coords are plotted together by default
xyzlim={'XLim','YLim','ZLim'};
datapoint_tag='*datapoint*'; %string to identify data points
%
aux=filldefault(aux,'opts_check',struct);
aux.opts_check=filldefault(aux.opts_check,'if_warn',1);
%
%check consistency and get available stimuli, dimensions, typenames
%
aux_out=struct;
%
%prior to consistency checking, see if we need to allow for typenames to vary
%
data_label_typenames_vary=0;
if isfield(aux,'opts_disp')
    if isfield(aux.opts_disp,'data_label_typenames_vary')
        data_label_typenames_vary=aux.opts_disp.data_label_typenames_vary;
    end
end
data_in_check=data_in;
if data_label_typenames_vary
    for iset=1:length(data_in.sas)
        for istim=1:length(data_in.sas{iset}.typenames)
            data_in_check.sas{iset}.typenames{istim}=sprintf('stim_%1.0f',istim);
        end
    end
end
%
check=rs_check_coordsets(data_in_check,aux.opts_check);
%
aux_out.warnings=check.warnings;
aux_out.warn_bad=check.warn_bad;
nsets=check.nsets;
nstims_each=check.nstims_each;
dim_list_each=check.dim_list_each;
dim_list_union=check.dim_list_union;
dim_list_inter=check.dim_list_inter;
typenames_each=check.typenames_each;
typenames_union=check.typenames_union;
typenames_inter=check.typenames_inter;
%
nstims=min(nstims_each); %all nstims_each should be identical
%
%set up sub-structure options
aux=filldefault(aux,'opts_disp',struct); %options for this module (psg_template)
aux.opts_disp=filldefault(aux.opts_disp,'if_warn',1);
aux.opts_disp=filldefault(aux.opts_disp,'if_finalize',1);
%
aux.opts_disp=filldefault(aux.opts_disp,'fig_handle',[]);
aux.opts_disp=filldefault(aux.opts_disp,'axis_handles',[]);
aux.opts_disp=filldefault(aux.opts_disp,'axis_view',{3});
aux.opts_disp=filldefault(aux.opts_disp,'axis_equal',1);
aux.opts_disp=filldefault(aux.opts_disp,'axis_range','tight');
aux.opts_disp=filldefault(aux.opts_disp,'axis_range_list',[0 1]);
aux.opts_disp=filldefault(aux.opts_disp,'axis_labels',cell(0));
%
aux.opts_disp=filldefault(aux.opts_disp,'dim_select',max(intersect(coords_together_default,dim_list_inter)));
aux.opts_disp=filldefault(aux.opts_disp,'set_select',[1:nsets]);
aux.opts_disp=filldefault(aux.opts_disp,'set_offsets',zeros(1,aux.opts_disp.dim_select));
aux.opts_disp=filldefault(aux.opts_disp,'set_offsets_margin_amount',ones(1,aux.opts_disp.dim_select));
aux.opts_disp=filldefault(aux.opts_disp,'set_offsets_margin_fraction',zeros(1,aux.opts_disp.dim_select));
aux.opts_disp=filldefault(aux.opts_disp,'set_offsets_coordchoices','all');
%
aux.opts_disp=filldefault(aux.opts_disp,'coord_group_size',min(aux.opts_disp.dim_select,max(coords_together_default)));
aux.opts_disp=filldefault(aux.opts_disp,'coord_group_method','all');
aux.opts_disp=filldefault(aux.opts_disp,'fig_name',sprintf('dimension %2.0f',aux.opts_disp.dim_select));
%
aux.opts_disp=filldefault(aux.opts_disp,'set_colors',{'k','b','c','m','r','y','g'});
aux.opts_disp=filldefault(aux.opts_disp,'set_markers',{'.'});
aux.opts_disp=filldefault(aux.opts_disp,'set_markersizes',8);
aux.opts_disp=filldefault(aux.opts_disp,'set_filled',0);
aux.opts_disp=filldefault(aux.opts_disp,'set_colors_filled',aux.opts_disp.set_colors);
aux.opts_disp=filldefault(aux.opts_disp,'set_alphas',1);
%
aux.opts_disp=filldefault(aux.opts_disp,'data_show_method','all');
aux.opts_disp=filldefault(aux.opts_disp,'data_show_list',[]);
aux.opts_disp=filldefault(aux.opts_disp,'data_label_method','all');
aux.opts_disp=filldefault(aux.opts_disp,'data_label_list',[]);
aux.opts_disp=filldefault(aux.opts_disp,'data_label_setsel_method','first');
aux.opts_disp=filldefault(aux.opts_disp,'data_label_setsel_list',[]);
aux.opts_disp=filldefault(aux.opts_disp,'data_label_interpreter',[]);
aux.opts_disp=filldefault(aux.opts_disp,'data_label_typenames_vary',0);
%
aux.opts_disp=filldefault(aux.opts_disp,'callout_amount',0);
aux.opts_disp=filldefault(aux.opts_disp,'callout_colors',{'k'});
aux.opts_disp=filldefault(aux.opts_disp,'callout_linestyles',{'-.'});
aux.opts_disp=filldefault(aux.opts_disp,'callout_linewidths',1);
aux.opts_disp=filldefault(aux.opts_disp,'callout_center','centroid');
%
aux.opts_disp=filldefault(aux.opts_disp,'connect_data_method','none');
aux.opts_disp=filldefault(aux.opts_disp,'connect_data_list',[]);
aux.opts_disp=filldefault(aux.opts_disp,'connect_data_linestyles',{'none'});
aux.opts_disp=filldefault(aux.opts_disp,'connect_data_linewidths',1);
%
aux.opts_disp=filldefault(aux.opts_disp,'connect_sets_method','none');
aux.opts_disp=filldefault(aux.opts_disp,'connect_sets_list',[]);
aux.opts_disp=filldefault(aux.opts_disp,'connect_sets_data_method','all');
aux.opts_disp=filldefault(aux.opts_disp,'connect_sets_data_list',[]);
aux.opts_disp=filldefault(aux.opts_disp,'connect_sets_linestyles','-');
aux.opts_disp=filldefault(aux.opts_disp,'connect_sets_linewidths',1);
aux.opts_disp=filldefault(aux.opts_disp,'connect_sets_color_mode','split');
aux.opts_disp=filldefault(aux.opts_disp,'connect_sets_colors',[]);
%
aux.opts_disp=filldefault(aux.opts_disp,'perp_data_dims',0);
aux.opts_disp=filldefault(aux.opts_disp,'perp_data_linestyles','-');
aux.opts_disp=filldefault(aux.opts_disp,'perp_data_linewidths',1);
aux.opts_disp=filldefault(aux.opts_disp,'perp_data_usemarkers',1);
%
aux.opts_disp=filldefault(aux.opts_disp,'if_box',1);
aux.opts_disp=filldefault(aux.opts_disp,'if_grid',1);
aux.opts_disp=filldefault(aux.opts_disp,'if_legend',1);
aux.opts_disp=filldefault(aux.opts_disp,'legend_location','Best');
aux.opts_disp=filldefault(aux.opts_disp,'legend_interpreter',[]);
aux.opts_disp=filldefault(aux.opts_disp,'legend_tags',{'set'});
%
aux=rs_aux_customize(aux,'rs_disp_coordsets');
%quantities dependent on overall defaults
aux.opts_disp=filldefault(aux.opts_disp,'axis_label_font_size',aux.opts_disp.axis_font_size);
aux.opts_disp=filldefault(aux.opts_disp,'legend_font_size',aux.opts_disp.axis_font_size);
aux.opts_disp=filldefault(aux.opts_disp,'data_label_font_size',aux.opts_disp.axis_font_size);
%
%set up other defaults and check consistency
%
disp_msgs=[]; %for warnings encountered during plots
x=aux.opts_disp; %for convenience
switch x.coord_group_method %determine coordinate groups
    case 'all'
        x.coord_groups=nchoosek([1:x.dim_select],x.coord_group_size);
    case 'keeplow'
        x.coord_groups=[repmat([1:x.coord_group_size-1],x.dim_select-x.coord_group_size+1,1),[x.coord_group_size:x.dim_select]'];
    case 'keepone'
        coords_group_list_hi=nchoosek([2:x.dim_select],x.coord_group_size-1);
        x.coord_groups=[ones(size(coords_group_list_hi,1),1) coords_group_list_hi];
    case 'rolling'
        x.coord_groups=mod(repmat([0:x.coord_group_size-1],x.dim_select,1)+repmat([0:x.dim_select-1]',1,x.coord_group_size),x.dim_select)+1;
    case 'onlylowest'
        x.coord_groups=[1:x.coord_group_size];
    case 'list'
    otherwise
        wmsg=sprintf('grouping method (%s) not recognized; only lowest coords shown',x.coord_group_method);
        x.coord_groups=[1:x.coord_group_size];
        aux_out=rs_warning(wmsg,0,setfield(aux_out,'if_warn',x.if_warn));
end
if x.coord_group_size~=size(x.coord_groups,2)
    wmsg=sprintf('number of columnns in coord_groups (%3.0f) and coord_group_size (%3.0f) is inconsistent',size(x.coord_groups,2),x.coord_group_size);
    aux_out=rs_warning(wmsg,1,setfield(aux_out,'if_warn',x.if_warn));
end
if ~ismember(x.coord_group_size,coords_together_allowed)
    wmsg=sprintf('cannot plot groups of %3.0f coordinates on same axis',x.coord_group_size);
    aux_out=rs_warning(wmsg,1,setfield(aux_out,'if_warn',x.if_warn));
end
if any(x.coord_groups(:)<=0) | any(x.coord_groups(:)>x.dim_select)
    wmsg=sprintf('some specified dimensions are out of bounds for the dimension plotted (%2.0f)',x.dim_select);
    aux_out=rs_warning(wmsg,1,setfield(aux_out,'if_warn',x.if_warn));
end
if ~isempty(setdiff(x.set_select,[1:nsets]))
    wmsg=sprintf('some selections in set_select are out of bounds ([1:%1.0f], and ignored )',nsets);
    aux_out=rs_warning(wmsg,0,setfield(aux_out,'if_warn',x.if_warn));
    x.set_select=intersect(x.set_select,[1:nsets]);
end
ngroups=size(x.coord_groups,1);
ngroups_aug=ngroups;
if x.if_legend==-1
    ngroups_aug=ngroups+1;
end
%parse set_offsets
for ifn=1:length(trunc_pad) %trunc_pad={'set_offsets','set_offsets_margin_amount','set_offsets_margin_fraction'}; %fields that are truncated or padded to have dim 2 length = dim_select
    tp=trunc_pad{ifn};
    if isnumeric(x.(tp))
        needcols=[1 x.dim_select];
        needcols_msg=sprintf('1 to %1.0f',x.dim_select);
        %
        if_okcols=double((size(x.(tp),2)>=min(needcols)) & (size(x.(tp),2)<=max(needcols)));
        if if_okcols==0
            wmsg=sprintf('number of columns in %s (%1.0f) is inconsistent with number needed (%s); truncated or padded',tp,size(x.(tp),2),needcols_msg);
            aux_out=rs_warning(wmsg,0,setfield(aux_out,'if_warn',x.if_warn));
        end
        if size(x.(tp),2)>x.dim_select
            x.(tp)=x.(tp)(:,[1:x.dim_select]);
        end
        if size(x.(tp),2)<x.dim_select
            x.(tp)=cat(2,x.(tp),zeros(size(x.(tp),1),x.dim_select-size(x.(tp),2)));
        end
    end
end
if ~isnumeric(x.set_offsets)    
    %compute min and max of each coord in each set
    mins=zeros(nsets,x.dim_select);
    maxs=zeros(nsets,x.dim_select);
    for iset=1:nsets
        mins(iset,:)=min(data_in.ds{iset}{x.dim_select},[],1);
        maxs(iset,:)=max(data_in.ds{iset}{x.dim_select},[],1);
    end
    switch x.set_offsets
        case 'margin_amount' %space by an absolute amount
            upper=-Inf;
            x.set_offsets=zeros(nsets,x.dim_select);
            for iset=1:nsets
                if ismember(iset,x.set_select)
                    if (upper>-Inf) %have we encountered any sets
                        x.set_offsets(iset,:)=x.set_offsets_margin_amount+upper-mins(iset,:);
                        upper=x.set_offsets(iset,:)+maxs(iset,:);
                    else
                        upper=maxs(iset,:);
                    end
                end
            end
        case 'margin_fraction' %space by a fraction of the average size of the spans
            upper=-Inf;
            x.set_offsets=zeros(nsets,x.dim_select);
            for iset=1:nsets
                if ismember(iset,x.set_select)
                    if (upper>-Inf) %have we encountered any sets
                        meansize=(maxs(iset_prev,:)-mins(iset_prev,:)+maxs(iset,:)-mins(iset,:))/2; %mean span of current and previous set
                        x.set_offsets(iset,:)=x.set_offsets_margin_fraction.*meansize+upper-mins(iset,:);
                        upper=x.set_offsets(iset,:)+maxs(iset,:);
                        iset_prev=iset;
                    else
                        upper=maxs(iset,:);
                        iset_prev=iset;
                    end
                end
            end
      otherwise
            wmsg=sprintf('specification of offset (%s) not recognized; no offset used',x.set_offsets);
            aux_out=rs_warning(wmsg,0,setfield(aux_out,'if_warn',x.if_warn));
            x.set_offsets=zeros(1,x.dim_select);
    end
    x.set_offsets=x.set_offsets-repmat(mean(x.set_offsets(x.set_select,:),1),nsets,1); %center around zero
    %now process set_offsets_coordchoices:  which coordinates are offset in each coordinate group
    if ~ischar(x.set_offsets_coordchoices) %only force numeric arrays into cells
        if ~iscell(x.set_offsets_coordchoices)
            x.set_offsets_coordchoices={x.set_offsets_coordchoices};
        end
        off_choices=x.set_offsets_coordchoices;
    else %string values cannot be cells
        if iscell(x.set_offsets_coordchoices)
            x.set_offsets_coordchoices=x.set_offsets_coordchoices{1};
        end
        switch x.set_offsets_coordchoices
            case 'all'
                off_choices=num2cell(x.coord_groups,2);
            case 'first'
                off_choices=(num2cell(x.coord_groups(:,1)))';
            case 'last'
                off_choices=(num2cell(x.coord_groups(:,end)))';
            otherwise
                wmsg=sprintf('specification of offset coordinate choices (%s) not recognized; all coordinates offset',x.set_offsets_coordchoices);
                aux_out=rs_warning(wmsg,0,setfield(aux_out,'if_warn',x.if_warn));
                off_choices{1}=[1:x.dim_select];
        end
    end
    %convert off_choices to [0,1] selection
    x.offsets_select=zeros(ngroups,x.dim_select); %will have 1's to select coordinates with offsets
    for kptr=1:ngroups
        k=1+mod(kptr-1,length(off_choices));
        if (any(off_choices{k}<1) | any(off_choices{k}>x.dim_select) | any(off_choices{k}~=round(off_choices{k}))) 
            wmsg=sprintf(' specification of offset coordinate choices non-integer or out of range ([1 %1.0f], all coordinates offset',x.dim_select);
            aux_out=rs_warning(wmsg,0,setfield(aux_out,'if_warn',x.if_warn));
            off_choices{k}=[1:x.dim_select];
        end
        x.offsets_select(kptr,intersect(off_choices{k},x.coord_groups(kptr,:)))=1;
    end
else
    x.offsets_select=ones(ngroups,x.dim_select);
end
%
%set up axis scale
switch x.axis_range %check that it is 'tight','auto', or pairs of values
    case {'tight','auto'}
    case 'list'
        if (~isnumeric(x.axis_range_list) | size(x.axis_range_list,2)~=2)
            wmsg=sprintf('axis scale list must have two columns; tight scaling used');
            aux_out=rs_warning(wmsg,0,setfield(aux_out,'if_warn',x.if_warn));
            x.axis_range='tight';
            x.axis_range_list=[NaN NaN];
        end
    otherwise
        wmsg=sprintf('axis scale specifier (%s) not recognized, tight scaling used',x.axis_range);
        aux_out=rs_warning(wmsg,0,setfield(aux_out,'if_warn',x.if_warn));
        x.axis_range='tight';
        x.axis_range_list=[NaN NaN];
end
%set up data show and label params
[x.data_show_list,wmsg]=rs_disp_parse_listmethod(x.data_show_method,[1:nstims],x.data_show_list,'specification of data points to show');
if ~isempty(wmsg)
    aux_out=rs_warning(wmsg,0,setfield(aux_out,'if_warn',x.if_warn));
end
[x.data_label_list,wmsg]=rs_disp_parse_listmethod(x.data_label_method,[x.data_show_list],x.data_label_list,'specification of data points to label');
if ~isempty(wmsg)
    aux_out=rs_warning(wmsg,0,setfield(aux_out,'if_warn',x.if_warn));
end
[x.data_label_setsel_list,wmsg]=rs_disp_parse_listmethod(x.data_label_setsel_method,x.set_select,x.data_label_setsel_list,'specification of sets to label');
if ~isempty(wmsg)
    aux_out=rs_warning(wmsg,0,setfield(aux_out,'if_warn',x.if_warn));
end
%set up params for connecting points within sets
[x.connect_data_list,wmsg]=rs_disp_parse_pairmethod(x.connect_data_method,x.data_show_list,x.connect_data_list,'specification of data points to connect within a set');
if ~isempty(wmsg)
    aux_out=rs_warning(wmsg,0,setfield(aux_out,'if_warn',x.if_warn));
end
if ~isempty(x.connect_data_list) %convert a set of pairs to a set of chains to simplify plotting
    x.connect_data_chains=pairs2chains(x.connect_data_list);
else
    x.connect_data_chains=[];
end
%set up params for connecting points across sets
[x.connect_sets_list,wmsg]=rs_disp_parse_pairmethod(x.connect_sets_method,x.set_select,x.connect_sets_list,'specification of sets to connect');
if ~isempty(wmsg)
    aux_out=rs_warning(wmsg,0,setfield(aux_out,'if_warn',x.if_warn));
end
if strcmp(x.connect_sets_data_method,'labeled')
    x.connect_sets_data_method=x.data_label_method;
    x.connect_sets_data_list=x.data_label_list;
end
[x.connect_sets_data_list,wmsg]=rs_disp_parse_listmethod(x.connect_sets_data_method,[x.data_show_list],x.connect_sets_data_list,'specification of data points to connect between sets');
if ~isempty(wmsg)
    aux_out=rs_warning(wmsg,0,setfield(aux_out,'if_warn',x.if_warn));
end
%
%ensure that certain options are cell in a column, or cell array of triplets
for imc=1:length(make_cell)
    mc=make_cell{imc};
    if ~isempty(strfind(mc,'color'))
        x.(mc)=rs_disp_colorfix(x.(mc));
    end
end
%set up connection colors
if size(x.connect_sets_list,1)>0
    connect_sets_list_mod=mod(x.connect_sets_list-1,length(x.set_colors))+1;
    switch x.connect_sets_color_mode
        %connect_sets_list_mod=mod(x.connect_sets_list-1,length(x.set_colors))+1;
        case 'first'
            x.connect_sets_colors=x.set_colors(connect_sets_list_mod(:,1));
        case 'last'
            x.connect_sets_colors=x.set_colors(connect_sets_list_mod(:,2));
        case 'split'
            x.connect_sets_colors=[x.set_colors(connect_sets_list_mod(:,1)),x.set_colors(connect_sets_list_mod(:,2))];
        case 'list'
        otherwise
            wmsg=sprintf('connect color mode (%s) not recognized, connections ignored',x.connect_sets_method);
            x.connect_sets_list=[];
            aux_out=rs_warning(wmsg,0,setfield(aux_out,'if_warn',x.if_warn));
    end
else
    x.connect_sets_list=[];
end
%set up labels
if ~isfield(x,'set_labels')
    x.set_labels=cell(nsets,1);
    for k=1:nsets
        x.set_labels{k}=sprintf('set %1.0f',k);
    end
end
if ~isfield(x,'set_tags')
    x.set_tags=cell(nsets,1);
    for k=1:nsets
        x.set_tags{k}=sprintf('set %1.0f',k);
    end
end
%ensure that certain options are cells
for imc=1:length(make_cell)
    mc=make_cell{imc};
    if ~iscell(x.(mc))
        x.(mc)={x.(mc)};
    end
end
%set_labels and set_tags cannot be empty
for k=1:length(x.set_labels)
    if isempty(x.set_labels{k})
        x.set_labels{k}=sprintf('set %1.0f',k);
    end
end
for k=1:length(x.set_tags)
    if isempty(x.set_tags{k})
        x.set_tags{k}=sprintf('set %1.0f',k);
    end
end
%use set colors for callout colors if requested
if strmatch(x.callout_colors{1},'set_colors')
    x.callout_colors=x.set_colors;
end
%
naxis_handles=length(x.axis_handles);
if naxis_handles>0 & naxis_handles~=ngroups_aug
    wmsg=sprintf('number of axes (subplots) supplied (%3.0f) does not match number of axes needed (%3.0f)',naxis_handles,ngroups_aug);
    aux_out=rs_warning(wmsg,double(naxis_handles<ngroups_aug),setfield(aux_out,'if_warn',x.if_warn));
end
%
if aux_out.warn_bad==0
    %set up styles for each component:  dataset, connections between data in a set, callouts, connections between sets, perpendiculars from data
    set_styles=struct;
    set_styles.colors=x.set_colors;
    set_styles.markers=x.set_markers;
    set_styles.markersizes=x.set_markersizes;
    set_styles.linestyles={'none'};
    set_styles.linewidths=1;
    set_styles.colors_filled=x.set_colors_filled;
    set_styles.filled=x.set_filled;
    set_styles.alphas=x.set_alphas;
    %
    connect_data_styles=struct;
    connect_data_styles.colors=x.set_colors;
    connect_data_styles.markers={'none'};
    connect_data_styles.markersizes=8;
    connect_data_styles.linestyles=x.connect_data_linestyles;
    connect_data_styles.linewidths=x.connect_data_linewidths;
    %
    callout_styles=struct;
    callout_styles.colors=x.callout_colors;
    callout_styles.markers={'none'};
    callout_styles.markersizes=8;
    callout_styles.linestyles=x.callout_linestyles;
    callout_styles.linewidths=x.callout_linewidths;
    %
    connect_set_styles=struct;
    connect_set_styles.colors={'k'};
    connect_set_styles.markers={'none'};
    connect_set_styles.markersizes=8;
    connect_set_styles.linestyles=x.connect_sets_linestyles;
    connect_set_styles.linewidths=x.connect_sets_linewidths;
    %
    if isempty(x.fig_handle)
        x.fig_handle=figure;
    else
        if x.fig_handle~=gcf
            figure(x.fig_handle);
        end
    end
    set(gcf,'Position',x.fig_position);
    set(gcf,'NumberTitle','off');
    set(gcf,'Name',x.fig_name);
    if naxis_handles==0
        fig_posit=get(gcf,'Position');
        [nrows,ncols]=nicesubp(ngroups_aug,fig_posit(4)/fig_posit(3)); %find an arrangement of rows and columns that fits the aspect ratio
        for igp=1:ngroups_aug
            x.axis_handles{igp}=subplot(nrows,ncols,igp);
        end
    end
    callout_center_ok=0;
    if isnumeric(x.callout_center)
        if length(x.callout_center)==x.dim_select
            callout_center_ok=1;
        end
    else
        switch x.callout_center
            case 'centroid'
                callout_center_ok=1;
            case 'zero'
                callout_center_ok=1;
        end
    end
    if callout_center_ok==0
        wmsg='callout_center specification not recognized, zero used';
        aux_out=rs_warning(wmsg,0,setfield(aux_out,'if_warn',x.if_warn));
        x.callout_center='zero';
    end
    %
    for igp_aug=1:ngroups_aug
        haxis=x.axis_handles{igp_aug};
        igp=mod(igp_aug-1,ngroups)+1; %if igp_aug=ngroup+1 (if_legend=-1) then igp=1 but it is plotted in a new subplot
        subplot(haxis);
        set(gca,'FontSize',x.axis_font_size);
        cg=x.coord_groups(igp,:);
        %plot points
        for isetptr=1:length(x.set_select)
            %
            [z,z_all,k]=rs_disp_coordsets_tuples(data_in,isetptr,x,igp); %get the tuples of all the points and the plotted ponts
            %
            [hline,plotstyle_used,opts_plotstyle_used]=rs_disp_doplot(z,k,set_styles);
            disp_msgs=strvcat(disp_msgs,opts_plotstyle_used.msgs);
            set(hline,'Tag',cat(2,x.set_tags{1+mod(k-1,length(x.set_tags))},' ',datapoint_tag)); %so that we can use it to drop perpendiculars when finalized
            set(hline,'DisplayName',x.set_labels{1+mod(k-1,length(x.set_labels))});
            %connect requested points
            if ~isempty(x.connect_data_chains)
                for ichain=1:length(x.connect_data_chains)
                    [hline,plotstyle_used,opts_plotstyle_used]=rs_disp_doplot(z_all(x.connect_data_chains{ichain},:),k,connect_data_styles);
                    disp_msgs=strvcat(disp_msgs,opts_plotstyle_used.msgs);
                    set(hline,'Tag',sprintf('ds %2.0f chain %2.0f',k,ichain));
                    set(hline,'DisplayName',x.set_labels{1+mod(k-1,length(x.set_labels))});
                end
            end
            %label?
            if ismember(k,x.data_label_setsel_list)
                zcallout=z; 
                if x.callout_amount>0 %compute position of call-out for every data point shown
                    callout_center=zeros(1,x.coord_group_size);
                    if isnumeric(x.callout_center)
                        callout_center=x.callout_center(1,cg);
                    else
                        switch x.callout_center
                            case 'centroid'
                                callout_center=mean(z_all,1,'omitnan');
                        end
                    end
                    dists=sqrt(sum((z_all-repmat(callout_center,size(z_all,1),1)).^2,2,'omitnan')); %distances from callout_center
                    rmsdist=sqrt(mean(dists.^2)); %rms distances from callout_center
                    dists(dists==0)=1;
                    for lab=1:size(x.data_show_list,1)
                        zcallout(lab,:)=callout_center+(zcallout(lab,:)-callout_center)*(1+x.callout_amount*rmsdist/dists(x.data_show_list(lab)));
                    end
                end
                typenames=data_in.sas{k}.typenames;
                for ipt_ptr=1:length(x.data_label_list)
                    ipt=x.data_label_list(ipt_ptr);
                    ipt_rel=find(x.data_show_list==ipt); %which of the selected points is being labelled
                    switch x.coord_group_size
                        case 2
                            ht=text(zcallout(ipt_rel,1),zcallout(ipt_rel,2),typenames{ipt});
                        case 3
                            ht=text(zcallout(ipt_rel,1),zcallout(ipt_rel,2),zcallout(ipt_rel,3),typenames{ipt});
                    end %coord group size
                    set(ht,'FontSize',x.data_label_font_size);
                    if ~isempty(x.data_label_interpreter)
                        set(ht,'Interpreter',x.data_label_interpreter);
                    end
                    if x.callout_amount>0
                        [hcallout,plotstyle_used,opts_plotstyle_used]=rs_disp_doplot(cat(1,z(ipt_rel,:),zcallout(ipt_rel,:)),k,callout_styles);
                        disp_msgs=strvcat(disp_msgs,opts_plotstyle_used.msgs);
                    end
                end %ipt
            end %set to label?
        end %isetptr
        %set up view and axis labels
        n_axis_labels=length(x.axis_labels);
        ax_labels=cell(1,x.coord_group_size);
        for ix=1:x.coord_group_size
            if isempty(x.axis_labels) | n_axis_labels==0;
                ax_labels{ix}=sprintf('%s %1.0f',x.axis_label_prefix,cg(ix));
            else
                ax_labels{ix}=x.axis_labels{1+mod(ix-1,n_axis_labels)};
            end
        end
        if x.if_finalize
            if x.coord_group_size<=3
                hl=xlabel(ax_labels{1});
                set(hl,'FontSize',x.axis_label_font_size);
                hl=ylabel(ax_labels{2});
                set(hl,'FontSize',x.axis_label_font_size);
            end
            if (x.coord_group_size==3)
                hl=zlabel(ax_labels{3});
                set(hl,'FontSize',x.axis_label_font_size);
                axis vis3d;
                index_view=1+mod(igp-1,length(x.axis_view));
                view(x.axis_view{index_view});
            end
        end
        %connections between sets
        for ic=1:size(x.connect_sets_list,1)
            cset=x.connect_sets_list(ic,:);
            if all(ismember(cset,x.set_select))
                data_connect_list=intersect(x.data_show_list,x.connect_sets_data_list); %find the points that are shown and also those selected for inter-set connection
                endpoints=zeros(length(data_connect_list),x.coord_group_size,2);
                for iz=1:2
                    endpoints(:,:,iz)=data_in.ds{cset(iz)}{x.dim_select}(data_connect_list,cg);
                    ko=mod(cset(iz)-1,size(x.set_offsets,1))+1;
                    endpoints(:,:,iz)=endpoints(:,:,iz)+repmat(x.set_offsets(ko,cg).*x.offsets_select(igp,cg),size(endpoints,1),1,1); %add the offset
                end
                midpoints=mean(endpoints,3);
                if ~strcmp(x.connect_sets_color_mode,'split')
                    connect_set_styles.colors=x.connect_sets_colors;
                    for istim=1:length(data_connect_list)
                        [hconnect,plotstyle_used,opts_plotstyle_used]=rs_disp_doplot([endpoints(istim,:,1);endpoints(istim,:,2)],ic,connect_set_styles);
                        disp_msgs=strvcat(disp_msgs,opts_plotstyle_used.msgs);
                    end
                else
                    for istim=1:length(data_connect_list)
                        for iseg=1:2
                            [hconnect,plotstyle_used,opts_plotstyle_used]=rs_disp_doplot([endpoints(istim,:,iseg);midpoints(istim,:)],ic,setfield(connect_set_styles,'colors',x.connect_sets_colors(:,iseg)));
                            disp_msgs=strvcat(disp_msgs,opts_plotstyle_used.msgs);
                        end %each segment
                    end %each stimulus
                end %split or not
            end %both sets are plotted
        end %each connection pair
        %box, view, axis scaling, legend
        if  x.if_finalize
            if (x.coord_group_size==3)
                if x.if_box
                    box on;
                else
                    box off;
                end
            end
            if x.if_grid
                grid on;
            else
                grid off;
            end
            if x.axis_equal
                axis equal;
            else
                axis normal;
            end
            switch x.axis_range
                case 'tight'
                    axis tight;
                case 'auto'
                    axis auto;
                case 'list'
                    for ic=1:x.coord_group_size
                        set(gca,xyzlim{ic},x.axis_range_list(1+mod(x.coord_groups(igp,ic)-1,size(x.axis_range_list,1)),:));
                    end
            end
            %perpendiculars: need to be plotted after axis range is established
            if (x.coord_group_size==3)
                for ic=1:x.coord_group_size
                    if_perp=x.perp_data_dims(1+mod(cg(ic)-1,length(x.perp_data_dims)));
                    axis_lims=get(gca,xyzlim{ic});
                    if if_perp~=0
                        hc=get(gca,'Children'); %look for data points via tags
                        z_foot=axis_lims((3-if_perp)/2); %foot of perp is min if if_perp=1, max if if_perp=-1
                        for ichild=1:length(hc)
                            if contains(hc(ichild).Tag,datapoint_tag)
                                xyz_data=[hc(ichild).XData;hc(ichild).YData;hc(ichild).ZData]';
                                %
                                perp_data_style=struct;
                                perp_data_style.linewidths=x.perp_data_linewidths;
                                %color taken from data
                                perp_data_style.colors={hc(ichild).Color};
                                %marker optionally used
                                perp_data_style.markersizes=hc(ichild).MarkerSize;
                                if x.perp_data_usemarkers
                                    perp_data_style.markers={hc(ichild).Marker};
                                else
                                    perp_data_style.markers={'none'};
                                end
                                if strcmp(x.perp_data_linestyles{1},'use_data')
                                    perp_data_style.linestyles={hc(ichild).LineStyle};
                                else
                                    perp_data_style.linestyles=x.perp_data_linestyles;
                                end
                                for iperp=1:size(xyz_data,1)
                                    z_to_perp=repmat(xyz_data(iperp,:),2,1);
                                    z_to_perp(2,ic)=z_foot;
                                    [hperp,plotstyle_used,opts_plotstyle_used]=rs_disp_doplot(z_to_perp,k,perp_data_style);
                                end %each point
                            end %each line with data
                        end
                    end %if_perp
                end %coordinate
            end
            %legend
            if (x.if_legend==1)
                need_legend=1;
            elseif (x.if_legend==-1)
                need_legend=(igp_aug==ngroups_aug);
            else
                need_legend=0;
            end
            if need_legend
                hc=get(haxis,'Children');
                tags_all=cell(length(hc),1);
                for ich=1:length(hc)
                    tags_all{ich}=get(hc(ich),'Tag');
                end
                hc_show=[];
                for itag=1:length(x.legend_tags)
                    hc_show=union(hc_show,strmatch(x.legend_tags{itag},tags_all)); %select the objects whose tags start with x.legend_tags
                end
                if ~isempty(hc_show)
                    h_legend=legend(hc(flipud(hc_show)),'Location',x.legend_location,'FontSize',x.legend_font_size);  %flipud since children appear to be added in reverse order
                    if ~isempty(x.legend_interpreter)
                        set(h_legend,'Interpreter',x.legend_interpreter);
                    end
                end
            end
        end %if_finalize
    end %igp_aug
end
%
aux_out=rs_warning(unique(disp_msgs,'rows'),0,setfield(aux_out,'if_warn',x.if_warn));
aux_out.opts_disp=x;
return
end