Skip to content

Commit d75c2c1

Browse files
committed
Adds some other functionality to StatisticalPlots.pl
- Ability to change the outlier marks in a boxplot - Adds a whisker cap option to a boxplot. - Adds a cap_width option for these whiskers. - Adds custom tick labels for the x-axis.
1 parent 4f88339 commit d75c2c1

5 files changed

Lines changed: 71 additions & 15 deletions

File tree

htdocs/js/Plots/plots.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,9 +375,17 @@ const PGplots = {
375375
options.xAxis.overrideOptions ?? {}
376376
)
377377
));
378-
xAxis.defaultTicks.generateLabelText = plot.generateLabelText;
378+
379379
xAxis.defaultTicks.formatLabelText = plot.formatLabelText;
380380

381+
if (options.xAxis.ticks?.customLabels) {
382+
xAxis.defaultTicks.generateLabelText = function (tick) {
383+
return options.xAxis.ticks.customLabels[tick.usrCoords[1]/options.xAxis.ticks.distance-1];
384+
}
385+
} else {
386+
xAxis.defaultTicks.generateLabelText = plot.generateLabelText;
387+
}
388+
381389
if (options.xAxis.location !== 'middle' && options.xAxis.name !== '') {
382390
plot.xLabel = board.create(
383391
'text',

lib/Plots/Axes.pm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ sub axis_defaults {
313313
tick_labels => 1,
314314
tick_label_format => 'decimal',
315315
tick_label_digits => 2,
316+
tick_label_custom => undef, # NEW: Array of custom labels
316317
tick_distance => 0,
317318
tick_scale => 1,
318319
tick_scale_symbol => '',

lib/Plots/JSXGraph.pm

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -122,21 +122,29 @@ sub HTML {
122122
$options->{mathJaxTickLabels} = $axes->style('mathjax_tick_labels') if $xvisible || $yvisible;
123123

124124
if ($xvisible) {
125-
$options->{xAxis}{name} = $axes->xaxis('label');
126-
$options->{xAxis}{ticks}{show} = $axes->xaxis('show_ticks');
127-
$options->{xAxis}{ticks}{labels} = $axes->xaxis('tick_labels');
128-
$options->{xAxis}{ticks}{labelFormat} = $axes->xaxis('tick_label_format');
129-
$options->{xAxis}{ticks}{labelDigits} = $axes->xaxis('tick_label_digits');
125+
$options->{xAxis}{name} = $axes->xaxis('label');
126+
$options->{xAxis}{ticks}{show} = $axes->xaxis('show_ticks');
127+
$options->{xAxis}{ticks}{labels} = $axes->xaxis('tick_labels');
128+
if ($axes->xaxis('tick_label_custom')) {
129+
$options->{xAxis}{ticks}{customLabels} = $axes->xaxis('tick_label_custom');
130+
} else {
131+
$options->{xAxis}{ticks}{labelFormat} = $axes->xaxis('tick_label_format');
132+
$options->{xAxis}{ticks}{labelDigits} = $axes->xaxis('tick_label_digits');
133+
}
130134
$options->{xAxis}{ticks}{scaleSymbol} = $axes->xaxis('tick_scale_symbol');
131135
$options->{xAxis}{arrowsBoth} = $axes->xaxis('arrows_both');
132136
$options->{xAxis}{overrideOptions} = $axes->xaxis('jsx_options') if $axes->xaxis('jsx_options');
133137
}
134138
if ($yvisible) {
135-
$options->{yAxis}{name} = $axes->yaxis('label');
136-
$options->{yAxis}{ticks}{show} = $axes->yaxis('show_ticks');
137-
$options->{yAxis}{ticks}{labels} = $axes->yaxis('tick_labels');
138-
$options->{yAxis}{ticks}{labelFormat} = $axes->yaxis('tick_label_format');
139-
$options->{yAxis}{ticks}{labelDigits} = $axes->yaxis('tick_label_digits');
139+
$options->{yAxis}{name} = $axes->yaxis('label');
140+
$options->{yAxis}{ticks}{show} = $axes->yaxis('show_ticks');
141+
$options->{yAxis}{ticks}{labels} = $axes->yaxis('tick_labels');
142+
if ($axes->yaxis('tick_label_custom')) {
143+
$options->{yAxis}{ticks}{customLabels} = $axes->yaxis('tick_label_custom');
144+
} else {
145+
$options->{yAxis}{ticks}{labelFormat} = $axes->yaxis('tick_label_format');
146+
$options->{yAxis}{ticks}{labelDigits} = $axes->yaxis('tick_label_digits');
147+
}
140148
$options->{yAxis}{ticks}{scaleSymbol} = $axes->yaxis('tick_scale_symbol');
141149
$options->{yAxis}{arrowsBoth} = $axes->yaxis('arrows_both');
142150
$options->{yAxis}{overrideOptions} = $axes->yaxis('jsx_options') if $axes->yaxis('jsx_options');

lib/Plots/Plot.pm

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,8 @@ sub add_rectangle {
399399
unless ref($pt0) eq 'ARRAY' && scalar(@$pt0) == 2;
400400
Value::Error('The second point must be an array ref of length 2')
401401
unless ref($pt2) eq 'ARRAY' && scalar(@$pt2) == 2;
402+
# If the fill_color option is set, set the fill to 'self'.
403+
$options{fill} = 'self' if $options{fill_color} && !defined($options{fill});
402404
return $self->add_dataset($pt0, [ $pt2->[0], $pt0->[1] ], $pt2, [ $pt0->[0], $pt2->[1] ], $pt0, %options);
403405
}
404406

macros/graph/StatisticalPlots.pl

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,21 @@ =head3 Options
270270
271271
If multiple box plots are defined, this should only be a single value.
272272
273+
=item whisker_cap
274+
275+
Value of 0 (default) or 1. If 1, his will add a short line perpendicular to the whiskers
276+
on the boxplot with relative size C<cap_width>
277+
278+
=item cap_width
279+
280+
The width of the cap as a fraction of the box height (if C<< orientation => 'vertical' >>)
281+
or box width (if C<< orientation => 'horizontal' >>). Default value is 0.2.
282+
283+
=item outlier_mark
284+
285+
The shape of the mark to use for outliers. Default is 'plus'. See L<Options for add_dataset|plots.pl/DATASET OPTIONS>
286+
for other mark options.
287+
273288
=back
274289
275290
As with other methods in the macro, other options can be passed along to C<add_rectangle>
@@ -411,7 +426,10 @@ sub add_boxplot {
411426
my ($self, $data, %opts) = @_;
412427

413428
my %options = (
414-
orientation => 'horizontal',
429+
orientation => 'horizontal',
430+
whisker_cap => 0,
431+
cap_width => 0.2,
432+
outlier_mark => 'plus',
415433
%opts
416434
);
417435

@@ -463,12 +481,10 @@ sub _add_boxplot {
463481
$count{$_}++ for ('min', 'q1', 'median', 'q3', 'max');
464482
$count{$_}-- for (keys %$data);
465483
for (keys %count) {
466-
# warn "$_: $count{$_}";
467484
Value::Error("The parameter $_ is missing from the boxplot attributes.") if $count{$_} > 0;
468485
}
469486
$params = $data;
470487
}
471-
# warn "$_: $options{$_}" for (keys %options);s
472488

473489
# if fill_color is passed as an option, set the 'fill' to 'self'.
474490
$options{fill} = 'self' if $options{fill_color};
@@ -484,9 +500,17 @@ sub _add_boxplot {
484500
$self->add_dataset([ $params->{median}, $box_center - 0.5 * $box_width ],
485501
[ $params->{median}, $box_center + 0.5 * $box_width ], %options);
486502

503+
# add whisker caps
504+
if ($options{whisker_cap}) {
505+
$self->add_dataset([ $params->{max}, $box_center - 0.5 * $options{cap_width} * $box_width ],
506+
[ $params->{max}, $box_center + 0.5 * $options{cap_width} * $box_width ], %options);
507+
$self->add_dataset([ $params->{min}, $box_center - 0.5 * $options{cap_width} * $box_width ],
508+
[ $params->{min}, $box_center + 0.5 * $options{cap_width} * $box_width ], %options);
509+
}
510+
487511
if ($params->{outliers}) {
488512
my @points = map { [ $_, $box_center ] } @{ $params->{outliers} };
489-
$self->add_dataset(@points, linestyle => 'none', marks => 'plus', marksize => 3);
513+
$self->add_dataset(@points, linestyle => 'none', marks => $options{outlier_mark}, marksize => 3);
490514
}
491515
} elsif ($orientation eq 'vertical') {
492516

@@ -499,6 +523,19 @@ sub _add_boxplot {
499523
$self->add_dataset([ $box_center, $params->{q3} ], [ $box_center, $params->{max}, ], %options);
500524
$self->add_dataset([ $box_center - 0.5 * $box_width, $params->{median} ],
501525
[ $box_center + 0.5 * $box_width, $params->{median} ], %options);
526+
527+
if ($params->{outliers}) {
528+
my @points = map { [ $box_center, $_ ] } @{ $params->{outliers} };
529+
$self->add_dataset(@points, linestyle => 'none', marks => $options{outlier_mark}, marksize => 3);
530+
}
531+
532+
# add whisker caps
533+
if ($options{whisker_cap}) {
534+
$self->add_dataset([ $box_center - 0.5 * $options{cap_width} * $box_width, $params->{max} ],
535+
[ $box_center + 0.5 * $options{cap_width} * $box_width, $params->{max}, ], %options);
536+
$self->add_dataset([ $box_center - 0.5 * $options{cap_width} * $box_width, $params->{min} ],
537+
[ $box_center + 0.5 * $options{cap_width} * $box_width, $params->{min} ], %options);
538+
}
502539
}
503540
}
504541

0 commit comments

Comments
 (0)