Triangular split patches with painters renderer in MATLAB 2014b and above

1.4k views Asked by At

MATLABs new graphics engine, HG2, fails to properly print patches using the painters renderer:

hist(randn(1,1000)); 
colorbar('Location','SouthOutside');
print('test.pdf','-dpdf');

The resulting patches, whether generated by hist or colorbar, have triangular splits:

Triangular splits in patches

The issue has been discussed on MATLAB Central here and here, where it was suggested that disabling the "smooth line art" option in the pdf-viewer should solve it. This conceals the problem in some readers (e.g. in Adobe Reader but not in Apple Preview), but it is hardly a solution to ask collaborators and readers to use a specific pdf-viewer with non-default settings for graphics to appear correctly. Looking at the resulting file in Inkscape, it is clear that the split is present in the output vector graphics. Here, I moved one half of the colorbar, proving that it is in fact split in half, and not just misinterpreted by the pdf-viewer:

enter image description here

The problem is not present using the OpenGL renderer (print('test.pdf','-opengl'), but then the output is not vectorized). The problem persists in MATLAB 2015a.

Is there a way to export artifact-free vector graphics in MATLAB 2014b or later?

3

There are 3 answers

0
Carlos On

Depending on what version of Matlab you are using, you might try to use epsclean. It doesn’t seem to work with very recent versions of Matlab like 2017a.

Otherwise, epsclean can be run on an existing eps file (not pdf) exported with the -painters option to generate a vectorized figure, and it will rewrite (or create another file) with those white lines removed.

0
Jonathan Abbott On

In R2015b, histogram seemed to not show the white lines, but fill did.

For simple plots just paste the data again:

x = 0:pi/100:pi;
y = sin(x);
f = fill(x,y,'r');
hold on;
f2 = fill(x,y,'r'); %// Worked like magic

If the magic fails try similar to Geoff's answer: f2 = fill(x+0.0001,y,'r');

0
Geoff On

Here's a questionable work-around until the actual problem is solved:

The diagonal lines are simply the empty space between the triangles, so what we are seeing is the white space behind the patches peek through. Silly idea: Let's fill that space with matching colors instead of white.

To do so, we'll copy all objects and offset the new ones by just a tiiiiny bit.

Code:

hist(randn(1,1000));
colorbar('Location','SouthOutside');
print('test.pdf','-dpdf');               %// print original for comparison

f1 = gcf;
g  = get(f1,'children');
n  = length(g);
copyobj(g,f1);                           %// copy all figure children

The copied objects are now the first n elements in the 2*n f1.Children array. They are exactly on top of the old objects.

g=get(f1,'children');
for i=1:n;
    if strcmpi(g(i).Type,'axes');
        set(g(i),'color','none','position',g(i).Position+[0.0001 0 0 0]);
        set(g(i+n),'position',g(i+n).Position);                            %// important!
    end;
end;
print('test2.pdf','-dpdf');

Explanation:

g = get(f1,'children'); gets all axes, colorbars, etc., within the current figure.

colorbar objects are linked to an axes, which is why we'll only have to move the axes type children.

Setting the color to none makes the background of the new axes transparent (since they are on top of the old ones).

g(i).Position+[0.0001 0 0 0] shifts the new axes by 0.0001 normalized units to the right.

set(g(i+n),'position',g(i+n).Position); This line seems unnecessary, but the last image below shows what happens when printing if you don't include it.

Depending on the types of graphics objects you have plotted, you may need to tweak this to fit your own needs, but this code should work if you have only colorbar and axes objects.

Original:

original

With hack:

enter image description here

Without %// important! line:

enter image description here