{"id":342,"date":"2015-12-01T14:52:13","date_gmt":"2015-12-01T19:52:13","guid":{"rendered":"https:\/\/blogs.mathworks.com\/graphics\/?p=342"},"modified":"2015-12-01T14:52:13","modified_gmt":"2015-12-01T19:52:13","slug":"contour-and-infinities","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/graphics\/2015\/12\/01\/contour-and-infinities\/","title":{"rendered":"Contour and Infinities"},"content":{"rendered":"<div class=\"content\"><p>In <a href=\"https:\/\/blogs.mathworks.com\/graphics\/2015\/11\/04\/on-the-edge\/\">a recent post<\/a>, I talked about an interesting edge case in the contour function. Today I'd like to talk about another one. This is how contour handles infinities.<\/p><p>Let's start with a simple example. Here I've got a 4x3 array of values.<\/p><pre class=\"codeinput\">[x,y] = meshgrid(4:7,4:6);\r\nz = x+y;\r\ncontourf(x,y,z,<span class=\"string\">'LevelList'<\/span>,[8 10 13])\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/contour_infinity_01.png\" alt=\"\"> <p>I'll make things a little easier to follow by using a variation on the labelcontourvalues function that I used in the earlier post to label the values at the vertices.<\/p><pre class=\"codeinput\">type <span class=\"string\">labelcontourvalues<\/span>\r\nlabelcontourvalues(x,y,z)\r\n<\/pre><pre class=\"codeoutput\">\r\nfunction labelcontourvalues(x,y,z)\r\n    for r=1:size(z,1)\r\n        for c=1:size(z,2)\r\n            v = z(r,c);\r\n            if (v&lt;-15 || v&gt;45 || isnan(v))\r\n                color = 'red';\r\n            else\r\n                color = [.5 .5 .5];\r\n            end\r\n            h = text(x(r,c),y(r,c),num2str(v));\r\n            h.HorizontalAlignment = 'center';\r\n            h.VerticalAlignment = 'middle';\r\n            h.Color = color;\r\n            h.FontSize = 10;\r\n            h.Margin = eps;\r\n        end\r\n    end\r\n    ax = gca;\r\n    xr = ax.XAxis;\r\n    xr.TickValues = unique(x(:));\r\n    xr.TickLabelFormat = 'X=%g';\r\n    xr.FontSize = 6;\r\n    yr = ax.YAxis;\r\n    yr.TickValues = unique(y(:));\r\n    yr.TickLabelFormat = 'Y=%g';\r\n    yr.FontSize = 6;\r\n    grid(ax,'on')\r\nend\r\n\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/contour_infinity_02.png\" alt=\"\"> <p>In this picture, the blue represents values between 8 and 10, while the teal represents values between 10 and 13. You can't see them, but yellow would represent values about 13, while a hole would represent values below 8.<\/p><p>If we stick an infinity at 6,5 we get the following.<\/p><pre class=\"codeinput\">tmp_z = z;\r\ntmp_z(2,3) = inf;\r\ncontourf(x,y,tmp_z,<span class=\"string\">'LevelList'<\/span>,[8 10 13])\r\nlabelcontourvalues(x,y,tmp_z)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/contour_infinity_03.png\" alt=\"\"> <p>Does that seem right? It seems wrong, because the yellow region is touching the blue region. Shouldn't there be a teal region in between them?<\/p><p>What happens if we use a large, but finite value instead?<\/p><pre class=\"codeinput\">tmp_z = z;\r\ntmp_z(2,3) = 50;\r\ncontourf(x,y,tmp_z,<span class=\"string\">'LevelList'<\/span>,[8 10 13])\r\nlabelcontourvalues(x,y,tmp_z)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/contour_infinity_04.png\" alt=\"\"> <p>You can see that the value of 50 is surrounded by a yellow area (&gt; 13) which reaches almost all the way to the neighboring values. On the side towards the blue region, the teal is just a thin sliver. In fact, it's 7.5% percent of the distance from the edge of the blue region to the vertex with value 50. That's because we're doing linear interpolation, and<\/p><p>$$(13-10)\/(50-10)$$<\/p><p>is 7.5%.<\/p><p>If that 50 is replaced by infinity the denominator in that equation becomes infinitely large. Therefore, the width of the teal region shrinks to be infinitely thin.<\/p><p>Now lets do the same exercise with a negative infinity.<\/p><pre class=\"codeinput\">tmp_z = z;\r\ntmp_z(2,2) = -inf;\r\ncontourf(x,y,tmp_z,<span class=\"string\">'LevelList'<\/span>,[8 10 13])\r\nlabelcontourvalues(x,y,tmp_z)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/contour_infinity_05.png\" alt=\"\"> <p>Does that seem right to you? We see that the area around the negative infinity is surrounded by a hole (&lt; 8). That seems correct. By why did the blue region at X=6 move up to Y=5? We can see the reason if we use a large, but finite negative value instead.<\/p><pre class=\"codeinput\">tmp_z = z;\r\ntmp_z(2,2) = -20;\r\ncontourf(x,y,tmp_z,<span class=\"string\">'LevelList'<\/span>,[8 10 13])\r\nlabelcontourvalues(x,y,tmp_z)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/contour_infinity_06.png\" alt=\"\"> <p>You can see that the blue region is actually going up and around the hole. It&#8217;s just that the negative infinity made that blue region infinitely narrow.<\/p><p>OK, now for the fun edge case. What happens when a positive infinity and a negative infinity are neighbors? I think that it should look something like this.<\/p><pre class=\"codeinput\">tmp_z = z;\r\ntmp_z(2,2) = -inf;\r\ntmp_z(2,3) = inf;\r\ncontourf(x,y,tmp_z,<span class=\"string\">'LevelList'<\/span>,[8 10 13])\r\nlabelcontourvalues(x,y,tmp_z)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/contour_infinity_07.png\" alt=\"\"> <p>Do you agree?<\/p><p>The idea is that there&#8217;s actually an infinitely thin blue border going around the top of the hole, and an infinitely thin teal border sneaking between the blue and the yellow.<\/p><p>Here&#8217;s the non-infinite version for comparison:<\/p><pre class=\"codeinput\">tmp_z = z;\r\ntmp_z(2,2) = -20;\r\ntmp_z(2,3) = 50;\r\ncontourf(x,y,tmp_z,<span class=\"string\">'LevelList'<\/span>,[8 10 13])\r\nlabelcontourvalues(x,y,tmp_z)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/contour_infinity_08.png\" alt=\"\"> <p>Although, if contour used a higher order interpolation function (as we talked about <a href=\"https:\/\/blogs.mathworks.com\/graphics\/2015\/09\/17\/what-is-a-contour\/\">in this post<\/a>), then it might look more like this:<\/p><pre class=\"codeinput\">[x2,y2] = meshgrid(linspace(4,7,150), <span class=\"keyword\">...<\/span>\r\n                   linspace(4,6,150));\r\nz2 = interp2(x,y,tmp_z, x2,y2, <span class=\"string\">'cubic'<\/span>);\r\ncontourf(x2,y2,z2,<span class=\"string\">'LevelList'<\/span>,[8 10 13])\r\nlabelcontourvalues(x,y,tmp_z)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/contour_infinity_09.png\" alt=\"\"> <p>As you can see, the curves cross the grid lines in the same place. It's just that contour's default interpolation has cut straight across the center of each of the 2x2 squares, while the higher order interpolation has gone way around the side away from the large values.<\/p><p>So that's positive and negative infinity. What about <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/nan.html\">NaN<\/a>? This one's a little different because a NaN there's no way to define which side of a contour level a NaN is on. For this reason, the portion of a 2x2 square which is closest to a NaN is simply left empty.<\/p><pre class=\"codeinput\">tmp_z = z;\r\ntmp_z(2,3) = nan;\r\ncontourf(x,y,tmp_z,<span class=\"string\">'LevelList'<\/span>,[8 10 13])\r\nlabelcontourvalues(x,y,tmp_z)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/contour_infinity_10.png\" alt=\"\"> <p>The portion that's not empty, continues to to linear interpolation, as we can see if we add more contour levels.<\/p><pre class=\"codeinput\">contourf(x,y,tmp_z,<span class=\"string\">'LevelList'<\/span>,[8 10 11 12.5 13])\r\nlabelcontourvalues(x,y,tmp_z)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/contour_infinity_11.png\" alt=\"\"> <p>Notice that there isn't a black line around the white hole. That's because this area is undefined, rather than being defined by a contour line.<\/p><p>It might be nice if the contour functions would do something different near NaNs. The problem is that there isn't one \"right answer\" that works well in all situations. You really need to choose a method that's appropriate for your situation. That means that we would have to add a bunch of options to the contour functions to control this, but those options would be useless for most users of contour.<\/p><p>Luckily there are plenty of good MATLAB tools which can be used with the contour functions to control how NaNs are handled. One of my favorites is John D'Errico's inpaint_nans function, which is available <a href=\"https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/4551-inpaint-nans\">on the File Exchange<\/a>. It provides a number of options. The default is fine for this case, where the data is very smooth, ...<\/p><pre class=\"codeinput\">tmp_z2 = inpaint_nans(tmp_z);\r\ncontourf(x,y,tmp_z2,<span class=\"string\">'LevelList'<\/span>,[8 10 11 12.5 13])\r\nlabelcontourvalues(x,y,tmp_z2)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/contour_infinity_12.png\" alt=\"\"> <p>... but you might need to try one of the other options if you have several NaNs near each other, or data which has sharp gradients.<\/p><p>And, of course, you can combine something like inpaint_nans with the interp2 I used earlier to create a very powerful contouring workflow.<\/p><script language=\"JavaScript\"> <!-- \r\n    function grabCode_42cec7d63644469a8db3efcb5492593d() {\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='42cec7d63644469a8db3efcb5492593d ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' 42cec7d63644469a8db3efcb5492593d';\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_42cec7d63644469a8db3efcb5492593d()\"><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\n42cec7d63644469a8db3efcb5492593d ##### SOURCE BEGIN #####\r\n%%\r\n% In <https:\/\/blogs.mathworks.com\/graphics\/2015\/11\/04\/on-the-edge\/ a recent post>, \r\n% I talked about an interesting edge case in the contour function. Today\r\n% I'd like to talk about another one. This is how contour handles\r\n% infinities.\r\n%\r\n% Let's start with a simple example. Here I've got a 4x3 array of values.\r\n%\r\n[x,y] = meshgrid(4:7,4:6);\r\nz = x+y;\r\ncontourf(x,y,z,'LevelList',[8 10 13])\r\n\r\n%%\r\n% I'll make things a little easier to follow by using a variation on the\r\n% labelcontourvalues function that I used in the earlier post to label the\r\n% values at the vertices.\r\n%\r\ntype labelcontourvalues\r\nlabelcontourvalues(x,y,z)\r\n\r\n%%\r\n% In this picture, the blue represents values between 8 and 10, while the \r\n% teal represents values between 10 and 13. You can't see them, but yellow \r\n% would represent values about 13, while a hole would represent values below 8.\r\n%\r\n% If we stick an infinity at 6,5 we get the following.\r\n%\r\ntmp_z = z;\r\ntmp_z(2,3) = inf;\r\ncontourf(x,y,tmp_z,'LevelList',[8 10 13])\r\nlabelcontourvalues(x,y,tmp_z)\r\n\r\n%%\r\n% Does that seem right? It seems wrong, because the yellow region is\r\n% touching the blue region. Shouldn't there be a teal region in between\r\n% them?\r\n%\r\n% What happens if we use a large, but finite value instead?\r\n%\r\ntmp_z = z;\r\ntmp_z(2,3) = 50;\r\ncontourf(x,y,tmp_z,'LevelList',[8 10 13])\r\nlabelcontourvalues(x,y,tmp_z)\r\n\r\n%%\r\n% You can see that the value of 50 is surrounded by a yellow area (> 13) \r\n% which reaches almost all the way to the neighboring values. On the side\r\n% towards the blue region, the teal is just a thin sliver. In fact, it's\r\n% 7.5% percent of the distance from the edge of the blue region to the\r\n% vertex with value 50. That's because we're doing linear interpolation,\r\n% and \r\n%\r\n% $$(13-10)\/(50-10)$$\r\n%\r\n% is 7.5%. \r\n%\r\n% If that 50 is \r\n% replaced by infinity the denominator in that equation becomes infinitely\r\n% large. Therefore, the width of the teal region shrinks to be infinitely\r\n% thin.\r\n%\r\n% Now lets do the same exercise with a negative infinity.\r\n%\r\ntmp_z = z;\r\ntmp_z(2,2) = -inf;\r\ncontourf(x,y,tmp_z,'LevelList',[8 10 13])\r\nlabelcontourvalues(x,y,tmp_z)\r\n\r\n%%\r\n% Does that seem right to you? We see that the area around the negative \r\n% infinity is surrounded by a hole (< 8). That seems correct. By why did \r\n% the blue region at X=6 move up to Y=5? We can see the reason if we use a \r\n% large, but finite negative value instead.\r\n%\r\ntmp_z = z;\r\ntmp_z(2,2) = -20;\r\ncontourf(x,y,tmp_z,'LevelList',[8 10 13])\r\nlabelcontourvalues(x,y,tmp_z)\r\n\r\n%%\r\n% You can see that the blue region is actually going up and around the hole. \r\n% It\u00e2\u20ac\u2122s just that the negative infinity made that blue region infinitely narrow.\r\n%\r\n% OK, now for the fun edge case. What happens when a positive infinity and \r\n% a negative infinity are neighbors? I think that it should look something \r\n% like this.\r\n%\r\ntmp_z = z;\r\ntmp_z(2,2) = -inf;\r\ntmp_z(2,3) = inf;\r\ncontourf(x,y,tmp_z,'LevelList',[8 10 13])\r\nlabelcontourvalues(x,y,tmp_z)\r\n\r\n%%\r\n% Do you agree?\r\n%\r\n% The idea is that there\u00e2\u20ac\u2122s actually an infinitely thin blue border going \r\n% around the top of the hole, and an infinitely thin teal border sneaking\r\n% between the blue and the yellow.\r\n%\r\n% Here\u00e2\u20ac\u2122s the non-infinite version for comparison:\r\n%\r\ntmp_z = z;\r\ntmp_z(2,2) = -20;\r\ntmp_z(2,3) = 50;\r\ncontourf(x,y,tmp_z,'LevelList',[8 10 13])\r\nlabelcontourvalues(x,y,tmp_z)\r\n\r\n%%\r\n% Although, if contour used a higher order interpolation function (as we \r\n% talked about <https:\/\/blogs.mathworks.com\/graphics\/2015\/09\/17\/what-is-a-contour\/ in this post>), \r\n% then it might look more like this:\r\n%\r\n[x2,y2] = meshgrid(linspace(4,7,150), ... \r\n                   linspace(4,6,150));\r\nz2 = interp2(x,y,tmp_z, x2,y2, 'cubic');\r\ncontourf(x2,y2,z2,'LevelList',[8 10 13])\r\nlabelcontourvalues(x,y,tmp_z)\r\n\r\n%%\r\n% As you can see, the curves cross the grid lines in the same place. It's\r\n% just that contour's default interpolation has cut straight across the\r\n% center of each of the 2x2 squares, while the higher order interpolation\r\n% has gone way around the side away from the large values.\r\n%\r\n\r\n%%\r\n% So that's positive and negative infinity. What about <https:\/\/www.mathworks.com\/help\/matlab\/ref\/nan.html NaN>? This one's a little\r\n% different because a NaN there's no way to define which side of a contour\r\n% level a NaN is on. For this reason, the portion of a 2x2 square which is\r\n% closest to a NaN is simply left empty.\r\n%\r\ntmp_z = z;\r\ntmp_z(2,3) = nan;\r\ncontourf(x,y,tmp_z,'LevelList',[8 10 13])\r\nlabelcontourvalues(x,y,tmp_z)\r\n\r\n%%\r\n% The portion that's not empty, continues to to linear interpolation, as we\r\n% can see if we add more contour levels.\r\ncontourf(x,y,tmp_z,'LevelList',[8 10 11 12.5 13])\r\nlabelcontourvalues(x,y,tmp_z)\r\n\r\n%%\r\n% Notice that there isn't a black line around the white hole. That's\r\n% because this area is undefined, rather than being defined by a contour\r\n% line.\r\n%\r\n% It might be nice if the contour functions would do something different\r\n% near NaNs. The problem is that there isn't one \"right answer\" that works\r\n% well in all situations. You really need to choose a method that's\r\n% appropriate for your situation. That means that we would have to add a\r\n% bunch of options to the contour functions to control this, but those\r\n% options would be useless for most users of contour. \r\n%\r\n% Luckily there are plenty of good MATLAB tools which can be used with the\r\n% contour functions to control how NaNs are handled.\r\n% One of my favorites is John D'Errico's inpaint_nans function, which is available\r\n% <https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/4551-inpaint-nans on\r\n% the File Exchange>. It provides a number of options. The default is fine\r\n% for this case, where the data is very smooth, ...\r\n%\r\ntmp_z2 = inpaint_nans(tmp_z);\r\ncontourf(x,y,tmp_z2,'LevelList',[8 10 11 12.5 13])\r\nlabelcontourvalues(x,y,tmp_z2)\r\n\r\n%%\r\n% ... but you might need to try one of the other options if you have several\r\n% NaNs near each other, or data which has sharp gradients.\r\n%\r\n% And, of course, you can combine something like inpaint_nans with the\r\n% interp2 I used earlier to create a very powerful contouring workflow.\r\n%\r\n##### SOURCE END ##### 42cec7d63644469a8db3efcb5492593d\r\n-->","protected":false},"excerpt":{"rendered":"<div class=\"overview-image\"><img src=\"https:\/\/blogs.mathworks.com\/graphics\/files\/feature_image\/contour_infinity_thumbnail.png\" class=\"img-responsive attachment-post-thumbnail size-post-thumbnail wp-post-image\" alt=\"\" decoding=\"async\" loading=\"lazy\" \/><\/div><p>In a recent post, I talked about an interesting edge case in the contour function. Today I'd like to talk about another one. This is how contour handles infinities.Let's start with a simple example.... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/graphics\/2015\/12\/01\/contour-and-infinities\/\">read more >><\/a><\/p>","protected":false},"author":89,"featured_media":344,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[5],"tags":[],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/posts\/342"}],"collection":[{"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/users\/89"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/comments?post=342"}],"version-history":[{"count":2,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/posts\/342\/revisions"}],"predecessor-version":[{"id":345,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/posts\/342\/revisions\/345"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/media\/344"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/media?parent=342"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/categories?post=342"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/tags?post=342"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}