<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>getundoc &#8211; Undocumented Matlab</title>
	<atom:link href="https://undocumentedmatlab.com/articles/tag/getundoc/feed" rel="self" type="application/rss+xml" />
	<link>https://undocumentedmatlab.com</link>
	<description>Professional Matlab consulting, development and training</description>
	<lastBuildDate>Wed, 12 Dec 2012 18:00:51 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.7.3</generator>
	<item>
		<title>Pinning annotations to graphs</title>
		<link>https://undocumentedmatlab.com/articles/pinning-annotations-to-graphs?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=pinning-annotations-to-graphs</link>
					<comments>https://undocumentedmatlab.com/articles/pinning-annotations-to-graphs#comments</comments>
		
		<dc:creator><![CDATA[Yair Altman]]></dc:creator>
		<pubDate>Wed, 12 Dec 2012 18:00:51 +0000</pubDate>
				<category><![CDATA[Figure window]]></category>
		<category><![CDATA[Handle graphics]]></category>
		<category><![CDATA[High risk of breaking in future versions]]></category>
		<category><![CDATA[Stock Matlab function]]></category>
		<category><![CDATA[Undocumented feature]]></category>
		<category><![CDATA[Undocumented function]]></category>
		<category><![CDATA[getundoc]]></category>
		<category><![CDATA[Optical illusion]]></category>
		<category><![CDATA[Pure Matlab]]></category>
		<category><![CDATA[scribe]]></category>
		<category><![CDATA[UDD]]></category>
		<category><![CDATA[UIInspect]]></category>
		<category><![CDATA[Undocumented property]]></category>
		<guid isPermaLink="false">http://undocumentedmatlab.com/?p=3398</guid>

					<description><![CDATA[<p>Annotation object can be programmatically set at, and pinned-to, plot axes data points. </p>
<p>The post <a rel="nofollow" href="https://undocumentedmatlab.com/articles/pinning-annotations-to-graphs">Pinning annotations to graphs</a> appeared first on <a rel="nofollow" href="https://undocumentedmatlab.com">Undocumented Matlab</a>.</p>
<div class='yarpp-related-rss'>
<h3>Related posts:</h3><ol>
<li><a href="https://undocumentedmatlab.com/articles/plotly-graphs" rel="bookmark" title="Plotly graphs">Plotly graphs </a> <small>Plotly charts can be created and customized in Matlab. ...</small></li>
<li><a href="https://undocumentedmatlab.com/articles/jfreechart-graphs-and-gauges" rel="bookmark" title="JFreeChart graphs and gauges">JFreeChart graphs and gauges </a> <small>JFreeChart is an open-source charting library that can easily be integrated in Matlab...</small></li>
<li><a href="https://undocumentedmatlab.com/articles/plotly-graphs-in-ipython-notebook" rel="bookmark" title="Plotly graphs in IPython Notebook">Plotly graphs in IPython Notebook </a> <small>Plotly graphs can be embedded in an IPython Notebook directly from Matlab. ...</small></li>
<li><a href="https://undocumentedmatlab.com/articles/bug-and-workaround-in-timeseries-plot" rel="bookmark" title="Bug and workaround in timeseries plot">Bug and workaround in timeseries plot </a> <small>Matlab's internal hgconvertunits function has a bug that affects timeseries plots. Luckily there is a simple workaround....</small></li>
</ol>
</div>
]]></description>
										<content:encoded><![CDATA[<p>Many Matlab users are aware of Matlab&#8217;s <a target="_blank" rel="nofollow" href="http://www.mathworks.com/help/matlab/creating_plots/how-to-annotate-graphs.html">annotation functionality</a>, which enables us to assign graphic elements such as arrows, lines, ellipses and text labels to Matlab figures. Matlab has a corresponding built-in function, <i><b>annotation</b></i>, that enables creation of annotation objects. Through the handle returned by <i><b>annotation</b></i> we can customize the annotation&#8217;s appearance (for example, line width/style or text font properties).</p>
<h3 id="limitations">Limitations of Matlab annotations</h3>
<p>Unfortunately, <i><b>annotation</b></i> has several major deficiencies, that are in fact related:<br />
<figure style="width: 406px" class="wp-caption alignright"><img fetchpriority="high" decoding="async" alt="A Matlab text-arrow annotation (unpinned)" src="https://undocumentedmatlab.com/images/Annotation_unpinned_animated.gif" title="A Matlab text-arrow annotation (unpinned)" width="406" height="298" /><figcaption class="wp-caption-text">A Matlab text-arrow annotation (unpinned)</figcaption></figure></p>
<ol>
<li><i><b>annotation</b></i> requires us to specify the annotation&#8217;s position in normalized <u>figure</u> units. Often, we are interested in an annotation on a plot axes that does NOT span the entire figure&#8217;s content area. To correctly convert the position from plot axes data coordinates to figure coordinates requires non-trivial calculations.</li>
<li>The created annotation is NOT pinned to the plot axes by default. This means that the annotation retains its relative position in the figure when the plot is zoomed, panned or rotated. This results in unintelligible and misleading annotations. We can indeed pin the annotation to the graph, but this requires delicate manual interaction (click the Edit Plot toolbar icon, then right-click the relevant annotation end-point, then select &#8220;Pin to Axes&#8221; from context menu). Unfortunately, the annotation handle does not provide a documented way to do this programmatically.</li>
<li>Finally, the annotation objects are only displayed on top of plot axes &#8211; they are obscured by any GUI uicontrols that may happen to be present in the figure.</li>
</ol>
<p>All of these limitations originate from the underlying implementation of annotation objects in Matlab. This is based on a transparent hidden axes that spans the entire figure&#8217;s content area, on which the annotations are being drawn (also called the <i>scribe layer</i>). The annotations may appear to be connected to the plot axes, but this is merely a visual illusion. In fact, they are located in a separate axes layer. For this reason, <i><b>annotation</b></i> requires figure position &#8211; in fact, the annotation has no information about the axes beneath it. Since plot axes are always obscured by uicontrols, so too is the annotation layer.<br />
Matlab&#8217;s implementation of annotation is an attempt to replicate Java&#8217;s standard <a target="_blank" rel="nofollow" href="http://docs.oracle.com/javase/tutorial/uiswing/components/rootpane.html">glass-pane mechanism</a>. But whereas the Java glass-pane is a true transparent layer, on top of all other window components (<a target="_blank" rel="nofollow" href="http://www.codebeach.com/2008/03/introduction-to-glass-panes-in-swing.html">examples</a>), Matlab&#8217;s implementation only works for axes.<br />
Oh well, it&#8217;s better than nothing, I guess. But still, it would be nice if we could specify the annotation in graph (plot axes) data units, and have it pinned automatically without requiring manual user interaction.<br />
<span id="more-3398"></span></p>
<h3 id="Debugging">Debugging the problem</h3>
<p>The obvious first place to start debugging this issue is to go to the annotation handle&#8217;s context-menu (accessible via the <b>UIContextMenu</b> property), drill down to the &#8220;Pin&#8221; menu item and take a look at its callback. We could then use the <i><b><a target="_blank" href="/articles/hgfeval/">hgfeval</a></b></i> function to execute this callback programmatically. Unfortunately, this does not work well, because the context-menu is empty when the annotation is first created. A context-menu is only assigned to the annotation after the Edit Plot toolbar button and then the annotation object are clicked.<br />
Being too lazy in nature to debug this all the way through, I opted for an easier route: I started the Profiler just prior to clicking the context-menu&#8217;s &#8220;Pin to Axes&#8221;, and stopped it immediately afterwards. This showed me the code path (beneath <i>%matlabroot%/toolbox/matlab/scribe/</i>), and placing breakpoints in key code lines enabled me to debug the process step-by-step. This in turn enabled me to take the essence of the pinning code and implement it in my stand-alone application code.<br />
Believe me when I say that the scribe code is complex (anyone say convoluted?). So I&#8217;ll spare you the gruesome details and skip right to the chase.</p>
<h3 id="solution">The solution</h3>
<h5 id="positioning">Positioning the annotation in axes data units</h5>
<p>The first step is to ensure that the initial annotation position is within the figure bounds. Otherwise, the <i><b>annotation</b></i> function will shout. Note that it is ok to move the annotation outside the figure bounds later on (via panning/zooming) &#8211; it is only the initial annotation creation that must be within the figure bounds (i.e., between 0.0-1.0 in normalized X and Y units):</p>
<pre lang='matlab'>
% Prepare the annotation's X position
% Note: we need 2 X values: one for the annotation's head, another for the tail
x = [xValue, xValue];
xlim = get(hAxes,'XLim');
% Prepare the annotation's Y position
% Note: we need 2 Y values: one for the annotation's head, another for the tail
% Note: we use a static Y position here, spanning the center of the axes.
% ^^^^  We could have used some other Y data value for this
yLim = get(hAxes,'YLim');
y = yLim(1) + 0*sum(yLim) + [0.1,0]*diff(ylim);  % TODO: handle reverse, log Y axes
% Ensure that the annotation fits in the window by enlarging
% the axes limits as required
if xValue < xlim(1) || xValue > xlim(2)
    hold(hAxes,'on');
    plot(hAxes,xValue,y(2),'-w');
    drawnow;
    % YLim may have changed, so recalculate y
    yLim = get(hAxes,'YLim');
    y = yLim(1) + 0*sum(yLim) + [0.1,0]*diff(ylim);  % TODO: handle reverse, log Y-axes
end
</pre>
<p>Next, we convert our plot data units, in order to get the annotation&#8217;s requested position in the expected figure units. For this we use <i>%matlabroot%/toolbox/matlab/scribe/@scribe/@scribepin/topixels.m</i>. This is an internal method of the <code>scribepin</code> UDD class, so in order to use it we need to create a dummy <code>scribepin</code> object. <i>topixels</i> then converts the dummy object&#8217;s position from axes data units to pixel units. We then use the undocumented <i><b><a target="_blank" href="/articles/bug-and-workaround-in-timeseries-plot/">hgconvertunits</a></b></i> function to convert from pixel units into normalized figure units:</p>
<pre lang='matlab'>
% Convert axes data position to figure normalized position
% uses %matlabroot%/toolbox/matlab/scribe/@scribe/@scribepin/topixels.m
scribepin = scribe.scribepin('parent',hAxes,'DataAxes',hAxes,'DataPosition',[x;y;[0,0]]');
figPixelPos = scribepin.topixels;
hFig = ancestor(hAxes,'figure');
figPos = getpixelposition(hFig);
figPixelPos(:,2) = figPos(4) - figPixelPos([2,1],2);
figNormPos = hgconvertunits(hFig,[figPixelPos(1,1:2),diff(figPixelPos)],'pixels','norm',hFig);
annotationX = figNormPos([1,1]);
annotationY = figNormPos([2,2]) + figNormPos(4)*[1,0];
</pre>
<h5 id="pinning">Pinning the annotation to the axes data</h5>
<p>Finally, we use the annotation handle&#8217;s <i>pinAtAffordance()</i> method and set the <b>Pin.DataPosition</b> property to the requested X,Y values (we need to do both of these, otherwise the annotation will jump around when we zoom/pan):<br />
<center><figure style="width: 406px" class="wp-caption alignright"><img decoding="async" alt="A Matlab text-arrow annotation (pinned)" src="https://undocumentedmatlab.com/images/Annotation_pinned_animated.gif" title="A Matlab text-arrow annotation (pinned)" width="406" height="298" /><figcaption class="wp-caption-text">A Matlab text-arrow annotation (pinned)</figcaption></figure></center></p>
<pre lang='matlab'>
% Ensure that the annotation is within the axes bounds, then display it
if any([annotationX,annotationY] < 0) || any([annotationX,annotationY] > 1)
    % Annotation position is outside axes boundaries, so bail out without drawing
    hAnnotation = handle([]);
elseif ~isempty(annotationObj)
    % Create a text-arrow annotation with the requested string at the requested position
    hAnnotation = handle(annotation('textarrow', annotationX, annotationY, ...
                                    'String',annotationStr, 'TextColor','b', 'Tag','annotation'));
    % Example for setting annotation properties
    hAnnotation.TextEdgeColor = [.8,.8,.8];
    % Pin the annotation object to the required axes position
    % Note: some of the following could fail in certain cases - never mind
    try
        hAnnotation.pinAtAffordance(1);
        hAnnotation.pinAtAffordance(2);
        hAnnotation.Pin(1).DataPosition = [xValue, y(1), 0];
        hAnnotation.Pin(2).DataPosition = [xValue, y(2), 0];
    catch
        % never mind - ignore (no error)
    end
end
</pre>
<p>p.s. Notice that all this relies on pure Matlab code (i.e., no mention of the dreaded J-word&#8230;). In fact, practically the entire scribe code is available in m-file format in the base Matlab installation. Masochistic readers may find many hours of pleasure sifting through the scribe code functionality for interesting nuggets such as the one above. If you ever find any interesting items, please drop me an email, or post a comment below.</p>
<h3 id="undocumented">Undocumented annotation properties</h3>
<p>Annotation objects have a <u>huge</u> number of undocumented properties. In fact, they have more undocumented properties than documented ones. You can see this using my <i><b><a target="_blank" href="/articles/uiinspect/">uiinspect</a></b></i> or <i><b><a target="_blank" href="/articles/getundoc-get-undocumented-object-properties/">getundoc</a></b></i> utilities. Here is the list for a simple text-arrow annotation, such as the one that we used above:</p>
<pre lang='matlab'>
>> getundoc(hAnnotation)
ans =
              ALimInclude: 'on'
                   Afsize: 6
          ApplicationData: [1x1 struct]
                 Behavior: [1x1 struct]
              CLimInclude: 'on'
               ColorProps: {5x1 cell}
     EdgeColorDescription: 'Color'
        EdgeColorProperty: 'Color'
                  Editing: 'off'
                EraseMode: 'normal'
     FaceColorDescription: 'Head Color'
        FaceColorProperty: 'HeadColor'
             FigureResize: 0
            HeadBackDepth: 0.35
                HeadColor: [0 0 0]
            HeadColorMode: 'auto'
            HeadEdgeColor: [0 0 0]
            HeadFaceAlpha: 1
            HeadFaceColor: [0 0 0]
               HeadHandle: [1x1 patch]
         HeadHypocycloidN: 3
            HeadLineStyle: '-'
            HeadLineWidth: 0.5
               HeadRosePQ: 2
                 HeadSize: 10
             HelpTopicKey: ''
          IncludeRenderer: 'on'
                 MoveMode: 'mouseover'
                    NormX: [0.2 0.4]
                    NormY: [0.5 0.7]
                      Pin: [0x1 double]
                   PinAff: [1 2]
           PinContextMenu: [2x1 uimenu]
                PinExists: [0 0]
              PixelBounds: [0 0 0 0]
        PropertyListeners: [8x1 handle.listener]
        ScribeContextMenu: [9x1 uimenu]
                 Selected: 'off'
             Serializable: 'on'
                ShapeType: 'textarrow'
                    Srect: [2x1 line]
           StoredPosition: []
                TailColor: [0 0 0]
               TailHandle: [1x1 line]
            TailLineStyle: '-'
            TailLineWidth: 0.5
     TextColorDescription: 'Text Color'
            TextColorMode: 'auto'
        TextColorProperty: 'TextColor'
        TextEdgeColorMode: 'manual'
            TextEraseMode: 'normal'
               TextHandle: [1x1 text]
         UpdateInProgress: 0
    VerticalAlignmentMode: 'auto'
              XLimInclude: 'on'
              YLimInclude: 'on'
              ZLimInclude: 'on'
</pre>
<p>The post <a rel="nofollow" href="https://undocumentedmatlab.com/articles/pinning-annotations-to-graphs">Pinning annotations to graphs</a> appeared first on <a rel="nofollow" href="https://undocumentedmatlab.com">Undocumented Matlab</a>.</p>
<div class='yarpp-related-rss'>
<h3>Related posts:</h3><ol>
<li><a href="https://undocumentedmatlab.com/articles/plotly-graphs" rel="bookmark" title="Plotly graphs">Plotly graphs </a> <small>Plotly charts can be created and customized in Matlab. ...</small></li>
<li><a href="https://undocumentedmatlab.com/articles/jfreechart-graphs-and-gauges" rel="bookmark" title="JFreeChart graphs and gauges">JFreeChart graphs and gauges </a> <small>JFreeChart is an open-source charting library that can easily be integrated in Matlab...</small></li>
<li><a href="https://undocumentedmatlab.com/articles/plotly-graphs-in-ipython-notebook" rel="bookmark" title="Plotly graphs in IPython Notebook">Plotly graphs in IPython Notebook </a> <small>Plotly graphs can be embedded in an IPython Notebook directly from Matlab. ...</small></li>
<li><a href="https://undocumentedmatlab.com/articles/bug-and-workaround-in-timeseries-plot" rel="bookmark" title="Bug and workaround in timeseries plot">Bug and workaround in timeseries plot </a> <small>Matlab's internal hgconvertunits function has a bug that affects timeseries plots. Luckily there is a simple workaround....</small></li>
</ol>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://undocumentedmatlab.com/articles/pinning-annotations-to-graphs/feed</wfw:commentRss>
			<slash:comments>13</slash:comments>
		
		
			</item>
	</channel>
</rss>
