{"id":1277,"date":"2015-12-14T09:06:26","date_gmt":"2015-12-14T14:06:26","guid":{"rendered":"https:\/\/blogs.mathworks.com\/loren\/?p=1277"},"modified":"2021-04-16T10:08:41","modified_gmt":"2021-04-16T14:08:41","slug":"axes-limits-scream-louder-i-cant-hear-you","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/loren\/2015\/12\/14\/axes-limits-scream-louder-i-cant-hear-you\/","title":{"rendered":"Axes Limits &#8211; Scream Louder, I Can&#8217;t Hear You!"},"content":{"rendered":"<p style=\"background-color:#87CEEB;text-align:center;vertical-align:middle;\"><span style=\"font-weight:bold;\">NOTE: <\/span><span>This functionality was added as the <\/span><a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/matlab.graphics.axis.decorator.numericruler-properties.html#bun6izd-1_sep_mw_99ab072e-14fa-4c74-99c1-45f63970d74e\"><span>LimitsChangedFcn<\/span><\/a><span> in R2021a.<\/span><\/p>\r\n\r\n<div class=\"content\"><!--introduction--><p><i>Today's guest post comes from <a href=\"https:\/\/www.mathworks.com\/matlabcentral\/profile\/authors\/3208495\">Sean de Wolski<\/a>, one of Loren's fellow Application Engineers.  You might recognize him from <a href=\"https:\/\/www.mathworks.com\/matlabcentral\/answers\/\">MATLAB answers<\/a> and the <a href=\"https:\/\/blogs.mathworks.com\/pick\/\">pick of the week<\/a> blog!<\/i><\/p><!--\/introduction--><p>I arrived at work early one day and immediately got a call from <a href=\"https:\/\/www.mathworks.com\/matlabcentral\/profile\/authors\/845693-brett-shoelson\">Brett<\/a>, who doesn't face the same commute I do, wondering why his <a href=\"https:\/\/www.mathworks.com\/help\/releases\/R2015b\/matlab\/matlab_oop\/events-and-listeners--concepts.html\">listeners<\/a> were not working on axes' <i>'XLim'<\/i>, <i>'YLim'<\/i> and <i>'ZLim'<\/i>.<\/p><p>This seemed a little surprising, surely a listener pointed at the wrong property?  Here's a minimal working example<\/p><pre class=\"codeinput\"><span class=\"comment\">% Plot something<\/span>\r\nax = gca;\r\nplot(humps);\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/loren\/2015\/listenerblogpost_01.png\" alt=\"\"> <pre class=\"codeinput\"><span class=\"comment\">% Add listener to axes' 'XLim' 'PostSet' event (so it fires after axes<\/span>\r\n<span class=\"comment\">% change).  Update the title so it's a visible change.<\/span>\r\naddlistener(ax,<span class=\"string\">'XLim'<\/span>,<span class=\"string\">'PostSet'<\/span>,@(~,~)title(<span class=\"string\">'Listener Fired'<\/span>));\r\n\r\n<span class=\"comment\">% Change Plot<\/span>\r\nplot(sin(1:0.1:100))\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/loren\/2015\/listenerblogpost_02.png\" alt=\"\"> <p>Huh?  No Title!  What happened?<\/p><p>What's interesting is that it allowed me to set the listener on the <i>'XLim'<\/i>.  Usually, if a property is not <a href=\"https:\/\/www.mathworks.com\/help\/releases\/R2015b\/matlab\/matlab_oop\/listening-for-changes-to-property-values.html\"><i>'SetObservable'<\/i><\/a>, it would error.<\/p><pre class=\"codeinput\"><span class=\"keyword\">try<\/span>\r\n    <span class=\"comment\">% Add listener to non-SetObservable property.<\/span>\r\n    addlistener(ax,<span class=\"string\">'TightInset'<\/span>,<span class=\"string\">'PostSet'<\/span>,@(~,~)disp(<span class=\"string\">'hello world'<\/span>))\r\n<span class=\"keyword\">catch<\/span> ME\r\n    fprintf(2,<span class=\"string\">'\\n%s\\n'<\/span>,ME.message);\r\n<span class=\"keyword\">end<\/span>\r\n<\/pre><pre class=\"codeoutput\">\r\nWhile adding a PostSet listener, property 'TightInset' in class 'matlab.graphics.axis.Axes' is not defined to be SetObservable.\r\n<\/pre><p>So what's happening?<\/p><p>When MATLAB versions R2014b and newer are automatically calculating the limits, the limits frequently change several times as MATLAB inspects each member of the axes and updates the limits.  Allowing listeners to be triggered during the automatic calculation (even if no listener was attached) would have caused performance degradation for all plot updates even if there are no listeners.  Thus the ability to trigger listeners with automatically calculated property value changes was disabled for performance reasons.<\/p><p>So how do we listen for limit changes?<\/p><p>The answer I provided to Brett was to write my own events class that has events for each of the limits changing.<\/p><pre class=\"language-matlab\">\r\n<span class=\"keyword\">classdef<\/span> LimitsChangedNotifier &lt; handle\r\n<span class=\"comment\">% This class has events of limits changes to be used for updating when axes<\/span>\r\n<span class=\"comment\">% limits change.<\/span>\r\n\r\n    <span class=\"keyword\">events<\/span>\r\n        <span class=\"comment\">% Events for each axes limit property<\/span>\r\n        XLimChanged;\r\n        YLimChanged;\r\n        ZLimChanged;\r\n    <span class=\"keyword\">end<\/span>\r\n<span class=\"keyword\">end<\/span>\r\n\r\n\r\n<\/pre><p>Now every time I update the plot, or call <tt>x\/y\/zlim('auto')<\/tt>, I would notify afterward.<\/p><pre class=\"codeinput\"><span class=\"comment\">% Build the events class<\/span>\r\nlimnotifier = LimitsChangedNotifier;\r\n\r\n<span class=\"comment\">% Attach a listener to it<\/span>\r\naddlistener(limnotifier,<span class=\"string\">'XLimChanged'<\/span>,@(~,~)title(<span class=\"string\">'Listener Fired'<\/span>));\r\n\r\n<span class=\"comment\">% Draw a new plot and let any listeners know you did<\/span>\r\nplot(sin(linspace(-2*pi,2*pi,100)));\r\nnotify(limnotifier,<span class=\"string\">'XLimChanged'<\/span>)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/loren\/2015\/listenerblogpost_03.png\" alt=\"\"> <p><b>Note:<\/b> By doing this, I retain control of letting the listeners know the limits changed.  This wouldn't work if the user did this on their own, say within <a href=\"https:\/\/www.mathworks.com\/help\/releases\/R2015b\/matlab\/ref\/plottools.html\"><tt>plottools<\/tt><\/a>.<\/p><p>For a more detailed and advanced explanation of events and listeners, please see <a href=\"https:\/\/www.mathworks.com\/help\/releases\/R2015b\/matlab\/matlab_oop\/example--using-events-to-update-graphs.html\">this documentation page<\/a>.<\/p><script language=\"JavaScript\"> <!-- \r\n    function grabCode_219650d2ed3a4145ba6f5aaf9824d576() {\r\n        \/\/ Remember the title so we can use it in the new page\r\n        title = document.title;\r\n\r\n        \/\/ Break up these strings so that their presence\r\n        \/\/ in the Javascript doesn't mess up the search for\r\n        \/\/ the MATLAB code.\r\n        t1='219650d2ed3a4145ba6f5aaf9824d576 ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' 219650d2ed3a4145ba6f5aaf9824d576';\r\n    \r\n        b=document.getElementsByTagName('body')[0];\r\n        i1=b.innerHTML.indexOf(t1)+t1.length;\r\n        i2=b.innerHTML.indexOf(t2);\r\n \r\n        code_string = b.innerHTML.substring(i1, i2);\r\n        code_string = code_string.replace(\/REPLACE_WITH_DASH_DASH\/g,'--');\r\n\r\n        \/\/ Use \/x3C\/g instead of the less-than character to avoid errors \r\n        \/\/ in the XML parser.\r\n        \/\/ Use '\\x26#60;' instead of '<' so that the XML parser\r\n        \/\/ doesn't go ahead and substitute the less-than character. \r\n        code_string = code_string.replace(\/\\x3C\/g, '\\x26#60;');\r\n\r\n        copyright = 'Copyright 2015 The MathWorks, Inc.';\r\n\r\n        w = window.open();\r\n        d = w.document;\r\n        d.write('<pre>\\n');\r\n        d.write(code_string);\r\n\r\n        \/\/ Add copyright line at the bottom if specified.\r\n        if (copyright.length > 0) {\r\n            d.writeln('');\r\n            d.writeln('%%');\r\n            if (copyright.length > 0) {\r\n                d.writeln('% _' + copyright + '_');\r\n            }\r\n        }\r\n\r\n        d.write('<\/pre>\\n');\r\n\r\n        d.title = title + ' (MATLAB code)';\r\n        d.close();\r\n    }   \r\n     --> <\/script><p style=\"text-align: right; font-size: xx-small; font-weight:lighter;   font-style: italic; color: gray\"><br><a href=\"javascript:grabCode_219650d2ed3a4145ba6f5aaf9824d576()\"><span style=\"font-size: x-small;        font-style: italic;\">Get \r\n      the MATLAB code <noscript>(requires JavaScript)<\/noscript><\/span><\/a><br><br>\r\n      Published with MATLAB&reg; R2015b<br><\/p><\/div><!--\r\n219650d2ed3a4145ba6f5aaf9824d576 ##### SOURCE BEGIN #####\r\n%% Axes Limits - Scream Louder, I Can't Hear You!\r\n%\r\n% _Today's guest post comes from\r\n% <https:\/\/www.mathworks.com\/matlabcentral\/profile\/authors\/3208495 Sean de\r\n% Wolski>, one of Loren's fellow Application Engineers.  You might\r\n% recognize him from <https:\/\/www.mathworks.com\/matlabcentral\/answers\/ MATLAB\r\n% answers> and the <https:\/\/blogs.mathworks.com\/pick\/ pick of the week>\r\n% blog!_\r\n\r\n%%\r\n% I arrived at work early one day and immediately got a call from\r\n% <https:\/\/www.mathworks.com\/matlabcentral\/profile\/authors\/845693-brett-shoelson\r\n% Brett>, who doesn't face the same commute I do, wondering why his\r\n% <https:\/\/www.mathworks.com\/help\/releases\/R2015b\/matlab\/matlab_oop\/events-and-listenersREPLACE_WITH_DASH_DASHconcepts.html\r\n% listeners> were not working on axes' _'XLim'_, _'YLim'_ and _'ZLim'_.\r\n%\r\n% This seemed a little surprising, surely a listener pointed at the wrong\r\n% property?  Here's a minimal working example\r\n\r\n% Plot something\r\nax = gca;\r\nplot(humps);\r\n\r\n%%\r\n\r\n% Add listener to axes' 'XLim' 'PostSet' event (so it fires after axes\r\n% change).  Update the title so it's a visible change.\r\naddlistener(ax,'XLim','PostSet',@(~,~)title('Listener Fired'));\r\n\r\n% Change Plot\r\nplot(sin(1:0.1:100))\r\n\r\n%%\r\n% Huh?  No Title!  What happened?\r\n%\r\n% What's interesting is that it allowed me to set the listener on the\r\n% _'XLim'_.  Usually, if a property is not\r\n% <https:\/\/www.mathworks.com\/help\/releases\/R2015b\/matlab\/matlab_oop\/listening-for-changes-to-property-values.html\r\n% _'SetObservable'_>, it would error.\r\n\r\ntry\r\n    % Add listener to non-SetObservable property.\r\n    addlistener(ax,'TightInset','PostSet',@(~,~)disp('hello world'))\r\ncatch ME\r\n    fprintf(2,'\\n%s\\n',ME.message);\r\nend\r\n\r\n%% \r\n% So what's happening?\r\n%\r\n% When MATLAB versions R2014b and newer are automatically calculating the\r\n% limits, the limits frequently change several times as MATLAB inspects\r\n% each member of the axes and updates the limits.  Allowing listeners to be\r\n% triggered during the automatic calculation (even if no listener was\r\n% attached) would have caused performance degradation for all plot updates\r\n% even if there are no listeners.  Thus the ability to trigger listeners\r\n% with automatically calculated property value changes was disabled for\r\n% performance reasons.\r\n%\r\n% So how do we listen for limit changes?\r\n%\r\n% The answer I provided to Brett was to write my own events class that\r\n% has events for each of the limits changing.\r\n%\r\n% <include>LimitsChangedNotifier<\/include>\r\n%\r\n% Now every time I update the plot, or call |x\/y\/zlim('auto')|, I would notify\r\n% afterward.\r\n\r\n% Build the events class\r\nlimnotifier = LimitsChangedNotifier;\r\n\r\n% Attach a listener to it\r\naddlistener(limnotifier,'XLimChanged',@(~,~)title('Listener Fired'));\r\n\r\n% Draw a new plot and let any listeners know you did\r\nplot(sin(linspace(-2*pi,2*pi,100)));\r\nnotify(limnotifier,'XLimChanged')\r\n\r\n%%\r\n% *Note:* By doing this, I retain control of letting the listeners know the\r\n% limits changed.  This wouldn't work if the user did this on their own,\r\n% say within\r\n% <https:\/\/www.mathworks.com\/help\/releases\/R2015b\/matlab\/ref\/plottools.html\r\n% |plottools|>.\r\n%\r\n% For a more detailed and advanced explanation of events and listeners,\r\n% please see\r\n% <https:\/\/www.mathworks.com\/help\/releases\/R2015b\/matlab\/matlab_oop\/exampleREPLACE_WITH_DASH_DASHusing-events-to-update-graphs.html\r\n% this documentation page>.\r\n##### SOURCE END ##### 219650d2ed3a4145ba6f5aaf9824d576\r\n-->","protected":false},"excerpt":{"rendered":"<div class=\"overview-image\"><img decoding=\"async\"  class=\"img-responsive\" src=\"https:\/\/blogs.mathworks.com\/images\/loren\/2015\/listenerblogpost_03.png\" onError=\"this.style.display ='none';\" \/><\/div><!--introduction--><p><i>Today's guest post comes from <a href=\"https:\/\/www.mathworks.com\/matlabcentral\/profile\/authors\/3208495\">Sean de Wolski<\/a>, one of Loren's fellow Application Engineers.  You might recognize him from <a href=\"https:\/\/www.mathworks.com\/matlabcentral\/answers\/\">MATLAB answers<\/a> and the <a href=\"https:\/\/blogs.mathworks.com\/pick\/\">pick of the week<\/a> blog!<\/i>... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/loren\/2015\/12\/14\/axes-limits-scream-louder-i-cant-hear-you\/\">read more >><\/a><\/p>","protected":false},"author":39,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[21,39],"tags":[],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/posts\/1277"}],"collection":[{"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/users\/39"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/comments?post=1277"}],"version-history":[{"count":3,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/posts\/1277\/revisions"}],"predecessor-version":[{"id":4125,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/posts\/1277\/revisions\/4125"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/media?parent=1277"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/categories?post=1277"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/tags?post=1277"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}