I am plotting some maps using Matlab that use mapshow to plot the country border from a shapefile. I then export them to both a PDF and EPS format using the export_fig package. This worked completely fine using Matlab 2014a, but I have just upgraded to Matlab 2014b to take advantage of something else that has improved, and now my country border is all jagged. The border only looks jagged on the saved versions of the file. If I zoom in on the figure window, the outline isn't like that.
Here are the snippets of code that are important. It is a custom shapefile, so I don't know how to put it on here so people can replicate it.
This bit reads in the shapefile and plots it. The display type is 'polygon' if that is relevent, hence getting rid of the 'FaceColor' so I can see what I am plotting underneath (the green bits in the background of the images, plotted using pcolor).
thaiborder=shaperead('Thailandborder');
mapshow(thaiborder,'FaceColor','none');
This bit is how I am exporting the figure.
export_fig test.eps -r600 -painters
export_fig test.pdf -r600 -painters
This is the version with a smooth border from Matlab 2014a:
This is roughly the same area of the image, with the jagged border from Matlab 2014b:
Does anyone know why these differences are occurring? I want the border to be like it is in the first image, but I need the "improved" functionality of Matlab 2014b for another thing in the same image. What do I need to change?
Edit to add: I have been in contact with the creator of export_fig and he thinks it is caused by Matlab now using mitred joins rather than round ones. Apparently I have to write to MathWorks to complain. I didn't put this as an answer because someone else may be able to provide a solution for me.
Matlab acknowledged that this is known bug. For me the first fix worked.
The issue of jagged lines on the figures while exporting in the vector format is a known bug in MATLAB R2014b. It is associated with the combination of linejoins and meterlimits used in vector format.
To work around this issue, use the attached function fixeps to post process the EPS file.
You can use one of the following ways to call this fixeps function.
fixeps('input.eps','output.eps','LJ') % Will change the linejoins to round
fixeps('input.eps','output.eps','ML') % Will correct the miterlimit
function fixeps(inname,outname,fixmode)
if nargin==2
fixmode = 'LJ';
end
fi = fopen(inname,'r');
fo = fopen(outname,'w');
tline = fgets(fi);
while ischar(tline)
if (strcmp(tline,['10.0 ML' 10])) % Replace 10.0 miterlimit
switch (fixmode)
case 'LJ'
fwrite(fo,['1 LJ' 10]); % With round linejoin
case 'ML'
fwrite(fo,['2.5 ML' 10]); % With smaller miterlimit
end
else
fwrite(fo,tline);
end
tline = fgets(fi);
end
fclose(fo);
fclose(fi);
I had a similar problem that I found to be caused by the 'MarkerSize' option. It seems that in version 2014b it inherits the units of the figure. For example, if I have a figure in centimeters and I ask for ('MarkerSize', 10), the 10 will not be interpreted as points (as in 2014a) but as cm. I fixed this by changing the figure units to pt.
Related
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:
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:
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?
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:
With hack:
Without %// important! line:
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');
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.
I am trying to export filled contour plots from Matlab as vector graphics to include in a Latex file. My current methodology is:
contourf(x,y,v_mag,20), axis([0,width,0,height]),daspect('manual') ;
grid off
colormap jet
h = colorbar;
caxis([0 v_lid])
h.Label.String = 'Velocity Magnitude (m/s)';
set(gcf,'renderer','painters')
export_fig('-painters', '-transparent', 'pdf', 'filename.pdf');
The problem with this method is that it produces artefacts (the white lines) which look like the following:
I understand that these white lines are the polygons defining the shaded areas which have invisible edges, and don't quite overlap (according to here). The problem is caused by the pdf viewer itself which tries to smooth the lines displayed on the screen (according to here). My problem is that most people viewing the document will not know this and will not know how to prevent the viewer doing this. So my questions is:
Is it possible to create a vector graphic of a filled contour plot from Matlab without these artefacts?
Eps produces the same problems. I have tried to use the SVG function but have not had any luck. I am trying to avoid using raster graphics due to the pixelation caused by zooming in. Any advice would be much appreciated.
EDIT - Additional info - Using Matlab v.2014b and Ghostscript v.9.15
This is an extremely frustrating issue for which there seems to be no solution (or even, few attempts at a solution), and it has been many years now. In summary, Matlab cannot cope with outputting artefact-free contour or surface plots (anything with complicated meshes or transparencies).
I can suggest a simple workaround that will work in most cases, where the colours or details of the underlying contour plot do not need to be preserved perfectly.
Output a version of the figure without lines in png format with high enough resolution.
Output a version of the figure without colours in pdf format. This should be free of any artefacts. If your figure it complicated and has many transparencies, you may need to output multiple versions building up the 'levels'.
Use Adobe Illustrator (or some equivalent) to perform a vectorized trace of the raster image. You may lose some detail here, but for simple contour plots with limited details, it will be converted easily to vectorized form.
Overlay the two images within Illustrator. Output in vector format.
This also allows you to use things like Illustrator's ability to compress pdfs.
If you don't want to toy with vectorizing the raster output, you can also simply replace steps 3-4 and combine a raster colour image with a vectorized line image. This would work well for complicated contour plots giving you crisp lines, but the ability to compress the underlying colours.
Eventually, MatLab 2013b doesn't have this problem. Furthermore the files it produces has much less volume. That is because MatLab 2013b composes vectorized image of big overlapping figures, while MatLab 2014b makes that awful meshing.
Here the first file was got with 2013b and the second with MatLab 2014b (I highlighted one of the polygons with red stroke to show the difference). The volumes differ in approximately 22 times (38 Kb vs. 844 Kb).
So it is not the viewer problem, it's how the image is exported from MatLab.
The issue is also discussed here Triangular split patches with painters renderer in MATLAB 2014b and above, but still no direct solution.
As MATLAB has changed its figure engine in R2014b I decided to rerun some of my code for getting better looking figures out of them. Unfortunately, the last one I have is a code that takes ages to run, and I would like to highly avoid to rerun the code for a nicer figure.
I saved the result in a .fig file in R2013b. However, if I open it in R2014b, it still has the old format.
Is it possible to redraw the figure using the MATLAB R2014b plotting engine? If it is, how could I do it?
NOTE: Literally, the figure is opened and drawn with the new engine, however, it retains its old format. While a new figure with a title() command would plot a nice big, bold title, if a redraw this figure using "drawnow" or I generate code for it, the format remains the same.
Example: This figure was created in 2013b, and redrawn in 2014b. You can see that the title does not plot in the same format as a title('whatever') would plot in the new graphic handles. It looks like that a '.fig' saves and sets the default values for the version it has been generated. Thus plot colors, titles, labels etc will look like the old graphic handles when redrawn.
This can be tested with the following code. Note that this is an overly simplified problem, the question is not explicitly about titles or labels, but all graphic stuff in general.
rng(1)
figure()
x = 1:50;
y = rand(1, 50);
plot(x,y)
title('this NICE Title')
xlabel('labels!')
ylabel('some other labels','Interpreter','Latex')
If this code is run in 2013b and 2014b, saved as fig in both and then opened as fig in both, the next 2 figures appear:
The 2013b fig file: http://s000.tinyupload.com/index.php?file_id=02053933004513599550
There is a roundabout way for doing this -- just using hgopen for loading the figure and then extracting the data to re-plot it in 2014b:
h1=hgopen('test.fig'); % h1 = handle to the figure
allaxes=get(h1,'children'); % allaxes = array with axes handles
for a=1:length(allaxes)
ax=allaxes(a);
allines=get(ax,'children'); % all lines in current axes
for l=1:length(allines)
lin=allines(l);
values=get(lin,'ydata'); % values of the current line
subplots{a}{l}=values;
end
end
You can then use the subplots cell array to make the plots again by hand. It is a boring way to do it, but may be worth trying if re-generating the output takes very long.
Do you know a simple way to draw arbitrary splines or lines in a plot-figure? I've got the following figure which I created in powerpoint with more or less arbitrary spline-curve (blue) but I'd like to do the same in MATLAB now because of a better look in the final plot-output.
I'm now wondering if I've got to manually "find" data-values to draw some sort of spline (which looks roughly like the blue one below) myself or if there's maybe a tool where I can simply insert some points into a plot interactively and there's a curve fitted though it to create something similar!?
The green and red lines I can figure out myself (probably also have to plot them manually, do I)?!?
Thanks in advance!
EDIT
Okay I found a way myself doing it in MATLAB to gnerate a nice spline: Use splinetool, then either use an example or import some data and then you can interactively add and delete points until your spline looks roughly like it should. Then file->print to figure and then tools->edit plot! You can then delete everything you don't need, add title, xlabel and ylabel etc. and then export it to latex with e.g. matlab2tikz :-) Very nice stuff!!
According the purpose, print nice plots for the thesis, I have some out-of-Matlab recommendations.
1) plot everything as usual, you get a figure handle and an axes handle
h = figure( ... )
a = gca
2) use the data cursor function of the figure window and interactively insert the base points for your later splines. You can additional points by right-click.
t = linspace(0,2*pi,1000);
[x y] = deal(sin(t),cos(t))
Later you delete the "visual" part of the data tip inside Illustrator/Inkscape, if you just want to keep the anchor point of the vector graphic to snap your splines.
There is also the possibility of custom data tips: Tutorial at Matlab Central
3) I once wrote a function to nicely plot Matlab figures as vector graphic based PDFs. You can specify height, width and how much white margin around you want. You just need to pass figure and axes handle and the name:
function saveFigure( fig_handle, axes_handle, name , height , width , margin)
set(axes_handle,'LooseInset',get(gca,'TightInset'));
set(fig_handle, 'Units','centimeters','PaperUnits','centimeters')
% the last two parameters of 'Position' define the figure size
set(fig_handle,'Position',[-margin -margin width height],...
'PaperPosition',[0 0 width+margin height+margin],...
'PaperSize',[width+margin height+margin],...
'PaperPositionMode','auto',...
'InvertHardcopy', 'on',...
'Renderer','painters'... %recommended if there are no alphamaps
);
saveas(fig_handle,name,'pdf')
end
4) You get a PDF you could directly use for Latex - for use in MS Office use 'emf' (
Enhanced metafile) rather than 'pdf'. Open this file with Adobe Illustrator (preferable as it offers layers) or Inkskape (Open Source).
5) The datatips are recognized as graphical objects, you can catch them and draw a spline on them. For Illustrator I'd recommend to put the spline in another layer than the actual figure. Later you can just swap the figure and give the spline new anchor points. In Inkscape you could use the grouping function to keep everything together.
6) I'd say you save a lot of time over a only-Matlab-solution. Good look!
I'm analyzing some sound clips using the spectrogram() function in MATLAB. I would like to save the spectrogram as an image (jpg, png, etc). But regardless of what image format I save the figure in, the resulting image always looks different ("spotty") from what I see in the figure.
Here's an example of the spectrograms: Matlab Figure vs. Saved Image
All I want is to save exactly what I see in the figure as an image. I've already tried saving the figure in all the image formats possible but all of them are producing the same "spotting" effect. I've also tried both manual saving (click on file -> save as) and programmatically using the print() and the saveas() functions. Same result every time.
Any help would be appreciated!
What is the data range of your spectrogram?
One of reasons might be that your spectrogram range is out of the [0,1] region for double images or [0,255] for uint* images (your white spots on saved image are suspiciously close to the local minima on MatLab figure).
Another guess might be that you are using imwrite function, in particular its imwrite(X,map,filename,fmt) syntax. MatLab documentation explains:
imwrite(X,map,filename,fmt) writes the indexed image in X and its associated colormap map to filename in the format specified by fmt. If X is of class uint8 or uint16, imwrite writes the actual values in the array to the file. If X is of class double, imwrite offsets the values in the array before writing, using uint8(X–1). map must be a valid MATLAB colormap. Note that most image file formats do not support colormaps with more than 256 entries.
so the uint8(X–1) might be the source of the white spots.
Though have no idea why they appear after print()'ing.
I found a work-around for this problem by using the pcolor() function, which is essentially a rotated surf() function plotted in a grid format (doc). After tinkering with the spectrogram() function more, I'm convinced that these "spotting" artifacts have nothing to do with the data format, property, or scale. The problem seems to lie in the way MATLAB plots and visualizes 3D plots. I tried plotting with the mesh() function as well and it produced a different kind of "spotting" effect. pcolor() works because it's a 2D visualization of a 3D plot.
This is how spectrogram() plots the image using surf() (adapted from the doc):
[S,T,F,P] = spectrogram(X,256,250,256,2000);
surf(T,F,abs(S),'EdgeColor','none');
axis tight; view(0,90);
... and this is how to use pcolor() to plot a save-friendly image:
[S,T,F,P] = spectrogram(X,256,250,256,2000);
h = pcolor(T,F,abs(S));
set(h,'EdgeColor','none');
The white spots are an OpenGL issue, which is the renderer used in spectrogram()'s internal call to surf().
Since you are interested in plotting a 2D visualization, change the renderer for the current figure to zbuffer:
set(gcf, 'renderer', 'zbuffer');
where gcf means "get current figure". The white spots are now gone.
Note that you can also select the zbuffer renderer when you create the figure, before calling spectrogram():
myNewFig = figure('renderer','zbuffer');