Search code examples
matlabopenglrenderfloating-point-precision

Incorrect plots using OpenGL renderer in MATLAB


I'm trying to plot a large amount of data on a graph using OpenGL. I want to use this renderer because it's the only one that supports transparency. The data is being plotted fine, but once you zoom in the lines connecting the points of data don't line up properly, As seen here:enter image description here I've tested plotting the data using Painters and Zbuffer and the lines connect the data properly when zoomed in the same amount. This is what Zbuffer generates (Painters looks the exact same, but with heavier grid lines):enter image description here

You can recreate the problem using the code below. Note that this doesn't create the exact same plots as shown but still clearly demonstrates the issue.

t = [735480.784722222 735480.826388889 735480.868055556 735480.909722222 735480.951388889 735481 735481.034722222 735481.076388889 735481.118055556 735481.159722222 735481.201388889 735481.243055556 735481.284722222 735481.326388889 735481.368055556 735481.409722222 735481.451388889 735481.493055556 735481.5 735481.534722222 735481.576388889];
d = [10.0799999237061 10.0799999237061 10.0799999237061 10.0699996948242 10.0699996948242 10.0799999237061 10.0699996948242 10.0699996948242 10.0699996948242 10.0699996948242 10.0699996948242 10.0600004196167 10.0600004196167 10.0600004196167 10.0699996948242 10.0699996948242 10.0600004196167 10.0600004196167 10.0600004196167 10.0600004196167 10.0500001907349];
figure;
plot(t, d, '.-');
set(gcf, 'renderer', 'opengl');

Solution

  • I found a similar question on MATLAB Answers to which the MathWorks Support Team responded:

    The OpenGL renderer uses only single precision. As a result, and the numbers that are being plotted are not able to be resolved using OpenGL. The Painters and ZBuffer renderers use double precision[...]

    The data you provide is of higher accuracy than can be represented by a single precision float. Therefore it won't display properly.

    A workaround could be to really plot only the least significant digits of your data (e.g. via subtraction of the leading digits) and play with the XTick/YTick and XTickLabel/YTickLabel properties of the plot to get proper axis tick labels. In your case something like this might suffice:

    LSD = @(x) x-single(x(1));
    plot(LSD(t), LSD(d), '.-');