# bug #52185: Make it possible to position annotations relative to axes or data

 Submitter: Etienne Dechamps Submitted: Sat 07 Oct 2017 08:00:13 PM UTC Category: Plotting Severity: 3 - Normal Priority: 5 - Normal Item Group: Feature Request Status: Confirmed Assigned to: None Originator Name: Open/Closed:  * Open Release:  * dev Operating System:  * Any Fixed Release: None Planned Release: None
* Mandatory Fields

Add a New Comment Rich Markup

## Discussion

Thu 04 Jan 2018 07:46:04 PM UTC, comment #3:

This is a known problem in Matlab as well and is related to how they chose to implement Annotation objects.  Try an Internet search for "matlab annotation data units" and you will see lots of solutions.  This Stack Overflow article was reasonable: https://stackoverflow.com/questions/11499370/how-to-plot-arrow-onto-a-figure-in-matlab

One of the solutions is the one suggested here of changing the parent to the axes.  The most general seems to be using a function that Matlab provides to convert between "data" coordinates and "normalized" coordinates.

Rik <rik5>
Mon 09 Oct 2017 11:24:52 AM UTC, comment #2:

Hi,

The simplest solution I can think of is to add listeners to the axes properties:

function [retval] = update_annot_pos (hax, ev, han, coord)
if (! ishandle (han))
return
endif
## Convert axes coordinates into normalized coordinates
xl = xlim (hax);
yl = ylim (hax);
x0 = (coord(1) - xl(1)) / diff(xl);
y0 = (coord(2) - yl(1)) / diff(yl);

## Assume axes units is normalized

pos = get (hax, "position");
x0 = x0*pos(3) + pos(1);
y0 = y0*pos(4) + pos(2);

pos = get (han, "position");
pos(3) = x0-pos(1);
pos(4) = y0-pos(2);
set (han, "position", pos);
drawnow ();
endfunction

plot (1:10, "-o")
h = annotation ("textarrow", [.2 .4], [.6 .6], "string", "toto");
addlistener (gca, "xlim", {@update_annot_pos, h, [5 5]})
addlistener (gca, "ylim", {@update_annot_pos, h, [5 5]})
addlistener (gca, "position", {@update_annot_pos, h, [5 5]})

Pantxo Diribarne <pantxo>
Sun 08 Oct 2017 10:37:33 AM UTC, comment #1:

I discovered the following workaround which (almost) does what I want:

a = annotation('arrow', [0 1], [0 1]);
set(a, 'parent', gca());

Indeed, by default, annotations get created in a separate "implicit" axes object that spans the entire figure. Changing the annotation to use a different axes as its parent changes its coordinate system to the data coordinate system of the specified axes, and voilà.

The downside is, when using arrows (for example), everything becomes relative to the data coordinate system, including the drawing of the arrowhead. This means, for example, that if the axes are non-square (or worse, use a log scale), the arrowhead will be deformed. This is probably not a problem for line annotations, however.

Etienne Dechamps <edechamps>
Sat 07 Oct 2017 08:00:13 PM UTC, original submission:

This feature request is a spin-off from the discussion in https://savannah.gnu.org/bugs/index.php?52184

Currently, https://www.gnu.org/software/octave/doc/v4.0.3/Plot-Annotations.html#index-annotation states:

> coordinates are interpreted using the "units" property of the annotation object. The default is "normalized", which means the lower left hand corner of the figure has coordinates ‘[0 0]’ and the upper right hand corner ‘[1 1]’.

To me this makes this functionality annoying to use, because I use annotations to point to specific features in the data that I'm plotting (e.g. using arrows). There's no easy way to make that work in a clean, reliable way, because the annotation is positioned relative to the figure, not the axes, which means that any changes to the position of the axes (or other unrelated formatting changes) will invalidate the annotations, making them brittle.

(I tried to write a custom function to fill that gap, but it turns out that's more difficult than it sounds - see bug #52184 linked above.)

It would make sense to have a unit where [0 0] is the bottom left corner of the axes (not the figure), and [1 1] is the top right corner of the axes.

What would be even better (at least for my use case) is to have a unit which is relative to the actual data limits of the axes themselves (i.e. the coordinates are expressed in terms of the data itself). However, as Dan Sebald rightly pointed out in the other thread, that might be tricky when it comes to more complicated plots.

Strangely enough, as Dan also noticed, it turns out that there is an (undocumented) "data" unit type available (and set by default) for annotations, but only when the gnuplot toolkit is used:

octave:1> graphics_toolkit('gnuplot');
octave:2> h = annotation('arrow', [0 1], [0 1]);
octave:3> set(h, 'units')
[ centimeters | {data} | inches | normalized | pixels | points ]

It doesn't seem to work, however - it behaves the same as "normalized".

Etienne Dechamps <edechamps>

## Attached Files

(Note: upload size limit is set to 16384 kB, after insertion of the required escape characters.)

Attach Files:

Comment:

No files currently attached

## Dependencies

Depends on the following items: None found

Items that depend on this one: None found

Carbon-Copy List
• -email is unavailable- added by rik5 (Posted a comment)
• -email is unavailable- added by pantxo (Posted a comment)
• -email is unavailable- added by edechamps (Commentators from original bug #52184)
• -email is unavailable- added by edechamps (Commentators from original bug #52184)
• -email is unavailable- added by edechamps (Commentators from original bug #52184)
• -email is unavailable- added by edechamps (Submitted the item)
•

There are 0 votes so far. Votes easily highlight which items people would like to see resolved in priority, independently of the priority of the item set by tracker managers.

Only group members can vote.