Skip to content

Commit a5b1e29

Browse files
author
Rik
committed
colorbar.m: Overhaul function for Matlab compatibility.
* NEWS.11.md: Announce change to position of "location" parameter in function. Announce implementation of "AxisLocation", "Direction", and "TickLabels" properties. * colorbar.m: Document that "location" parameter must now be first function parameter. Remove @deftypefnx for calling form using "peer". Move documentation for "peer" calling form to Implementation Note. Print unrecognized "location" parameter when erroring out. Change input validation for "location" to check that it is the first parameter. Add new properties "ticklabels", "ticklabelsmode", "ticks", "ticksmode". Add listener functions for new properties. Adjust BIST tests for "location" parameter to pass. * colorbar.m (cb_axislocation, cb_direction, cb_ticks, cb_ticksmode, cb_ticklabels, cb_ticklabelsmode): New callback listener functions. * colorbar.m (cb_restore_axes): Delete "colormap" and "clim" listeners from axes. * colorbar.m (calc_cbar_position): Rename variable "mirr" to "mirror" for clarity.
1 parent bd27715 commit a5b1e29

File tree

2 files changed

+133
-43
lines changed

2 files changed

+133
-43
lines changed

etc/NEWS.11.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,11 @@ Summary of important user-visible changes for version 11 (yyyy-mm-dd):
8282
- The function `fill` now handles all input combination of vector and matrix
8383
vertex data and color data in a Matlab-compatible way.
8484

85+
- The function `colorbar` now requires the `location` input to be the first
86+
argument rather than the last argument. This may require updating existing
87+
Octave scripts. The graphics properties `AxisLocation`, `Direction`, and
88+
`TickLabels` have been implemented.
89+
8590
### Alphabetical list of new functions added in Octave 11
8691

8792
* `corrcov`

scripts/plot/draw/colorbar.m

Lines changed: 128 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,20 @@
2525

2626
## -*- texinfo -*-
2727
## @deftypefn {} {} colorbar
28-
## @deftypefnx {} {} colorbar (@dots{}, @var{loc})
28+
## @deftypefnx {} {} colorbar (@var{loc}, @dots{})
2929
## @deftypefnx {} {} colorbar (@var{delete_option})
3030
## @deftypefnx {} {} colorbar (@var{hcb}, @dots{})
3131
## @deftypefnx {} {} colorbar (@var{hax}, @dots{})
32-
## @deftypefnx {} {} colorbar (@dots{}, "peer", @var{hax}, @dots{})
3332
## @deftypefnx {} {} colorbar (@dots{}, "location", @var{loc}, @dots{})
3433
## @deftypefnx {} {} colorbar (@dots{}, @var{prop}, @var{val}, @dots{})
3534
## @deftypefnx {} {@var{h} =} colorbar (@dots{})
3635
## Add a colorbar to the current axes.
3736
##
38-
## A colorbar displays the current colormap along with numerical rulings
39-
## so that the color scale can be interpreted.
37+
## A colorbar displays the current colormap along with numerical rulings so
38+
## that the color scale can be interpreted.
4039
##
4140
## The optional input @nospell{@var{loc}} determines the location of the
42-
## colorbar. If present, it must be the last argument to @code{colorbar}.
41+
## colorbar. If present, it must be the first argument to @code{colorbar}.
4342
## Valid values for @nospell{@var{loc}} are
4443
##
4544
## @table @asis
@@ -73,25 +72,24 @@
7372
##
7473
## If the first argument @var{hax} is an axes handle, then the colorbar is
7574
## added to this axes, rather than the current axes returned by @code{gca}.
76-
## Alternatively, If the argument @qcode{"peer"} is given, then the following
77-
## argument is treated as the axes handle in which to add the colorbar. The
78-
## @qcode{"peer"} calling syntax may be removed in the future and is not
79-
## recommended.
8075
##
8176
## If the first argument @var{hcb} is a handle to a colorbar object, then
8277
## operate on this colorbar directly.
8378
##
8479
## Additional property/value pairs are passed directly to the underlying axes
85-
## object. The full list of properties is documented at
86-
## @ref{Axes Properties}.
80+
## object. The full list of properties is documented at @ref{Axes Properties}.
8781
##
8882
## The optional return value @var{h} is a graphics handle to the created
8983
## colorbar object.
9084
##
91-
## Implementation Note: A colorbar is created as an additional axes object
92-
## with the @qcode{"tag"} property set to @qcode{"colorbar"}. The created
93-
## object has the extra property @qcode{"location"} which controls the
94-
## positioning of the colorbar.
85+
## Implementation Note: A colorbar is created as an additional axes object with
86+
## the @qcode{"tag"} property set to @qcode{"colorbar"}. The created object
87+
## has the extra property @qcode{"location"} which controls the positioning of
88+
## the colorbar.
89+
##
90+
## If the argument @qcode{"peer"} is given, then the following argument is
91+
## treated as the axes handle in which to add the colorbar. The @qcode{"peer"}
92+
## calling syntax may be removed in the future and is not recommended.
9593
## @seealso{colormap}
9694
## @end deftypefn
9795

@@ -120,8 +118,8 @@
120118
switch (lower (arg))
121119
case {"north", "south", "east", "west", ...
122120
"northoutside", "southoutside", "eastoutside", "westoutside"}
123-
if (i <= nargin)
124-
error ("colorbar: LOC specification must occur as final argument");
121+
if (i != 2)
122+
error ("colorbar: LOC specification must occur as first argument");
125123
endif
126124
loc = lower (arg);
127125

@@ -165,7 +163,7 @@
165163
if (! any (strcmp (loc, {"eastoutside"; "east"; "westoutside"; "west";
166164
"northoutside"; "north"; "southoutside"; "south";
167165
"manual"})))
168-
error ("colorbar: unrecognized colorbar location");
166+
error ("colorbar: unrecognized colorbar location '%s'", loc);
169167
endif
170168
endif
171169

@@ -268,14 +266,13 @@
268266

269267
if (isempty (cbpos))
270268
## auto positioning
271-
## FIXME: Should handle user-specified "AxisLocation" property (mirror).
272269
[axpos, cbpos, vertical, mirror] = ...
273270
calc_cbar_position (loc, props, ancestor (hpar, "figure"));
274271
set (hax, "position", axpos);
275272
else
276273
## colorbar position specified.
277274
## 1) Don't shrink existing plot axes,
278-
## 2) Assume "EastOutside" orientation (vertical=true, mirror=true)
275+
## 2) Use default "EastOutside" orientation
279276
vertical = true;
280277
mirror = true;
281278
endif
@@ -290,14 +287,18 @@
290287

291288
addproperty ("axislocation", hcb, "radio", "{out}|in");
292289
addproperty ("axislocationmode", hcb, "radio", "{auto}|manual");
293-
addproperty ("label", hcb, "handle", get (hcb, "ylabel"));
294290
addproperty ("direction", hcb, "AxesYdir", "normal");
291+
addproperty ("label", hcb, "handle", get (hcb, "ylabel"));
295292
addproperty ("limits", hcb, "AxesYlim");
296293
addproperty ("limitsmode", hcb, "AxesYlimMode", "auto");
297294
addproperty ("location", hcb, "radio",
298295
"{eastoutside}|east|westoutside|west|northoutside|north|southoutside|south|manual",
299296
loc);
300297
addproperty ("tickdirection", hcb, "AxesTickdir", "in");
298+
addproperty ("ticklabels", hcb, "AxesYtickLabel");
299+
addproperty ("ticklabelsmode", hcb, "AxesYtickLabelMode", "auto");
300+
addproperty ("ticks", hcb, "AxesYtick");
301+
addproperty ("ticksmode", hcb, "AxesYtickMode", "auto");
301302
## FIXME: Matlab uses just a scalar for ticklength, but axes already
302303
## has a 2-element ticklength property which cannot be overridden.
303304
## addproperty ("ticklength", hcb, "double", 0.01);
@@ -328,13 +329,13 @@
328329
"ytickmode", "auto", "ylim", cext,
329330
"yaxislocation", "right", "label", get (hcb, "ylabel"),
330331
"__vertical__", vertical,
331-
"layer", "top", args{:});
332+
"layer", "top");
332333
else
333334
set (hcb, "xtick", [], "xlim", [-0.5, 1.5],
334335
"ytickmode", "auto", "ylim", cext,
335336
"yaxislocation", "left", "label", get (hcb, "ylabel"),
336337
"__vertical__", vertical,
337-
"layer", "top", args{:});
338+
"layer", "top");
338339
endif
339340
else
340341
set (hi, "xdata", [cmin, cmax], "ydata", [0,1], "cdata", [1 : clen]);
@@ -343,13 +344,13 @@
343344
"xtickmode", "auto", "xlim", cext,
344345
"xaxislocation", "top", "label", get (hcb, "xlabel"),
345346
"__vertical__", vertical,
346-
"layer", "top", args{:});
347+
"layer", "top");
347348
else
348349
set (hcb, "ytick", [], "ylim", [-0.5, 1.5],
349350
"xtickmode", "auto", "xlim", cext,
350351
"xaxislocation", "bottom", "label", get (hcb, "xlabel"),
351352
"__vertical__", vertical,
352-
"layer", "top", args{:});
353+
"layer", "top");
353354
endif
354355
endif
355356

@@ -364,9 +365,15 @@
364365

365366
set (hcb, "deletefcn", {@cb_restore_axes, hax, props});
366367

368+
addlistener (hcb, "axislocation", {@cb_axislocation});
369+
addlistener (hcb, "direction", {@cb_direction});
370+
addlistener (hcb, "tickdirection", @cb_tickdirection);
371+
addlistener (hcb, "ticks", {@cb_ticks});
372+
addlistener (hcb, "ticksmode", {@cb_ticksmode});
373+
addlistener (hcb, "ticklabels", {@cb_ticklabels});
374+
addlistener (hcb, "ticklabelsmode", {@cb_ticklabelsmode});
367375
addlistener (hcb, "xscale", {@cb_error_on_logscale, "xscale"});
368376
addlistener (hcb, "yscale", {@cb_error_on_logscale, "yscale"});
369-
addlistener (hcb, "tickdirection", @cb_tickdirection);
370377

371378
if (strcmp (get (hpar, "type"), "figure"))
372379
addlistener (hpar, "colormap", {@cb_colormap, ...
@@ -382,9 +389,14 @@
382389
hcb, props});
383390
addlistener (hax, "position", {@cb_colorbar_axis, hcb, props});
384391

385-
## FIXME: Need listeners for colorbar: axislocation, axislocationmode,
386-
## direction, limits, limitsmode, location.
392+
## FIXME: Need listeners for limits, limitsmode, location.
387393
endif
394+
395+
## Called after listeners have been installed
396+
if (! isempty (args))
397+
set (hcb, args{:});
398+
endif
399+
388400
unwind_protect_cleanup
389401
set (hfig, "currentaxes", origaxes);
390402
if (! isempty (origfig))
@@ -400,15 +412,13 @@
400412

401413
## Axes to which colorbar was attached is being deleted/reset. Delete colorbar.
402414
function cb_axes_deleted (~, ~, hax, hcb)
403-
404415
if (isaxes (hcb))
405416
if (strcmp (get (hax, "beingdeleted"), "on"))
406417
## Axes are being deleted. Disable call to cb_restore_axes.
407418
set (hcb, "deletefcn", []);
408419
endif
409420
delete (hcb);
410421
endif
411-
412422
endfunction
413423

414424
## Error on attempt to set logscale on colorbar axes
@@ -419,7 +429,81 @@ function cb_error_on_logscale (hcb, ~, scale)
419429
endif
420430
endfunction
421431

422-
## Colorbar "TickDirection" callback which just maps to axes "TickDir"
432+
## colorbar property "AxisLocation" which maps to axes "[X|Y]AxisLocation".
433+
function cb_axislocation (hcb, ~)
434+
vertical = strcmp (get (hcb, '__vertical__'), 'on');
435+
location = get (hcb, 'axislocation');
436+
if (vertical)
437+
location = ifelse (strcmp (location, 'in'), 'left', 'right');
438+
set (hcb, 'yaxislocation', location);
439+
else
440+
location = ifelse (strcmp (location, 'in'), 'top', 'bottom');
441+
set (hcb, 'xaxislocation', location);
442+
endif
443+
endfunction
444+
445+
## colorbar property "Direction" which maps to axes "YDir" or "XDir".
446+
function cb_direction (hcb, ~)
447+
vertical = strcmp (get (hcb, '__vertical__'), 'on');
448+
direction = get (hcb, 'direction');
449+
if (vertical)
450+
set (hcb, 'ydir', direction);
451+
else
452+
set (hcb, 'xdir', direction);
453+
endif
454+
endfunction
455+
456+
## colorbar property "Ticks" which maps to axes "YTick" or "XTick".
457+
function cb_ticks (hcb, ~)
458+
vertical = strcmp (get (hcb, '__vertical__'), 'on');
459+
ticks = get (hcb, 'ticks');
460+
if (vertical)
461+
set (hcb, 'YTick', ticks);
462+
else
463+
set (hcb, 'XTick', ticks);
464+
endif
465+
set (hcb, 'ticksmode', 'manual');
466+
endfunction
467+
468+
## colorbar property "TicksMode" which maps to axes "[Y|X]TickMode".
469+
function cb_ticksmode (hcb, ~)
470+
mode = get (hcb, 'ticksmode');
471+
if (strcmp (mode, 'auto'))
472+
vertical = strcmp (get (hcb, '__vertical__'), 'on');
473+
if (vertical)
474+
set (hcb, 'YTickMode', 'auto');
475+
else
476+
set (hcb, 'XTickMode', 'auto');
477+
endif
478+
endif
479+
endfunction
480+
481+
## colorbar property "TickLabels" which maps to axes "[Y|X]TickLabel".
482+
function cb_ticklabels (hcb, ~)
483+
vertical = strcmp (get (hcb, '__vertical__'), 'on');
484+
ticklabels = get (hcb, 'ticklabels');
485+
if (vertical)
486+
set (hcb, 'YTickLabel', ticklabels);
487+
else
488+
set (hcb, 'XTickLabel', ticklabels);
489+
endif
490+
set (hcb, 'ticklabelsmode', 'manual');
491+
endfunction
492+
493+
## colorbar property "TickLabelsMode" which maps to axes "[Y|X]TickLabelMode".
494+
function cb_ticklabelsmode (hcb, ~)
495+
mode = get (hcb, 'ticklabelsmode');
496+
if (strcmp (mode, 'auto'))
497+
vertical = strcmp (get (hcb, '__vertical__'), 'on');
498+
if (vertical)
499+
set (hcb, 'YTickLabelMode', 'auto');
500+
else
501+
set (hcb, 'XTickLabelMode', 'auto');
502+
endif
503+
endif
504+
endfunction
505+
506+
## colorbar property "TickDirection" which maps to axes property "TickDir".
423507
function cb_tickdirection (hcb, ~)
424508
set (hcb, "tickdir", get (hcb, "tickdirection"));
425509
endfunction
@@ -437,6 +521,8 @@ function cb_restore_axes (hcb, ~, hax, orig_props)
437521
## FIXME: It is wrong to delete every listener for colormap on figure,
438522
## but we don't have a way of deleting just this instance.
439523
dellistener (hf, "colormap");
524+
dellistener (hax, "colormap");
525+
dellistener (hax, "clim");
440526
dellistener (hax, "dataaspectratio");
441527
dellistener (hax, "dataaspectratiomode");
442528
dellistener (hax, "plotboxaspectratio");
@@ -514,7 +600,7 @@ function cb_colorbar_axis (hax, ~, hcb, orig_props)
514600
props.position = orig_props.position;
515601
props.outerposition = orig_props.outerposition;
516602
[axpos, cbpos, vertical, mirror] = ...
517-
calc_cbar_position (loc, props, ancestor (hax, "figure"));
603+
calc_cbar_position (loc, props, ancestor (hax, "figure"));
518604

519605
set (hcb, "position", cbpos);
520606
endif
@@ -524,8 +610,7 @@ function cb_colorbar_axis (hax, ~, hcb, orig_props)
524610
## FIXME: The algorithm for positioning in legend.m is much more sophisticated
525611
## and should be borrowed for colorbar. One problem is that colorbar
526612
## positioning does not take in to account multi-line axes labels.
527-
## FIXME: Should handle user-specified "AxisLocation" property (mirror var).
528-
function [axpos, cbpos, vertical, mirr] = calc_cbar_position (loc, props, cf)
613+
function [axpos, cbpos, vertical, mirror] = calc_cbar_position (loc, props, cf)
529614

530615
## This will always represent the position prior to adding the colorbar.
531616
axpos = props.position;
@@ -560,47 +645,47 @@ function cb_colorbar_axis (hax, ~, hcb, orig_props)
560645
origin = axpos(1:2) + [0., 0.9] .* sz + [1, -1] .* off;
561646
sz .*= [1.0, 0.06];
562647
axpos(4) = 0.8 * axpos(4);
563-
mirr = true;
648+
mirror = true;
564649
vertical = false;
565650
case "north"
566651
origin = axpos(1:2) + [0.05, 0.9] .* sz + [1, -1] .* off;
567652
sz .*= [1.0, 0.06] * 0.9;
568-
mirr = false;
653+
mirror = false;
569654
vertical = false;
570655
case "southoutside"
571656
origin = axpos(1:2) + off;
572657
sz .*= [1.0, 0.06];
573658
axpos(2) = axpos(2) + axpos(4) * 0.2;
574659
axpos(4) = 0.8 * axpos(4);
575-
mirr = false;
660+
mirror = false;
576661
vertical = false;
577662
case "south"
578663
origin = axpos(1:2) + [0.05, 0.05] .* sz + off;
579664
sz .*= [1.0, 0.06] * 0.9;
580-
mirr = true;
665+
mirror = true;
581666
vertical = false;
582667
case "eastoutside"
583668
origin = axpos(1:2) + [0.9, 0] .* sz + [-1, 1] .* off;
584669
sz .*= [0.06, 1.0];
585670
axpos(3) = 0.8 * axpos(3);
586-
mirr = true;
671+
mirror = true;
587672
vertical = true;
588673
case "east"
589674
origin = axpos(1:2) + [0.9, 0.05] .* sz + [-1, 1] .* off;
590675
sz .*= [0.06, 1.0] * 0.9;
591-
mirr = false;
676+
mirror = false;
592677
vertical = true;
593678
case "westoutside"
594679
origin = axpos(1:2) + off;
595680
sz .*= [0.06, 1.0];
596681
axpos(1) = axpos(1) + axpos(3) * 0.2;
597682
axpos(3) = 0.8 * axpos(3);
598-
mirr = false;
683+
mirror = false;
599684
vertical = true;
600685
case "west"
601686
origin = axpos(1:2) + [0.05, 0.05] .* sz + off;
602687
sz .*= [0.06, 1.0] .* 0.9;
603-
mirr = true;
688+
mirror = true;
604689
vertical = true;
605690
endswitch
606691

@@ -927,7 +1012,7 @@ function cb_colorbar_axis (hax, ~, hcb, orig_props)
9271012

9281013
## Test input validation
9291014
%!error <expected string argument at position 1> colorbar (-pi)
930-
%!error <LOC specification must occur as final arg> colorbar ("east", "p", "v")
1015+
%!error <LOC specification must occur as first arg> colorbar ("p", "v", "east")
9311016
%!error <missing value after "location"> colorbar ("location")
9321017
%!error <missing axes handle after "peer"> colorbar ("peer")
9331018
%!error <invalid axes handle following "peer"> colorbar ("peer", -1)

0 commit comments

Comments
 (0)