How to Output Accurate PDF from Matlab figure

30 views (last 30 days)
Hi everyone:
For some reason, I need to plot the mask of a microfluid device in Matlab, which consists of many posts separated by certain distance The plotting process is easy but when I tried to 'print' it into PDF file, the image was distorted (circles are not round, and they have obvious defect on them), and the spacing was not right(shortened).
I've tried function 'rectangle', code like:
function drawFilledCircle (center_x, center_y, radius)
%%Draw a filled circle
xc = center_x; yc = center_y;
r = radius;
x = r*sin(-pi:0.01*pi:pi) + xc;
y = r*cos(-pi:0.01*pi:pi) + yc;
fill(x, y, [0,0,0]);
and even a function called 'filledCircle' which I found on fileexchange.
But I always got the wrong thing. I don't know what I can do to fix it.
Please help.
P.S. I attached the original matlab figure and the printed PDF for references.
P.S.2 I've also tried to output them into other formats like EPS, but even EPS doesn't look right.
  4 Comments
lvn
lvn on 19 Mar 2014
Could you post the complete code that would reproduce test.fig? I would like to see if I manage to export it correctly.
Frank
Frank on 19 Mar 2014
No problem. Here you go, thanks. (Please let me know how to do it if you manage to do so)
%%Hexagon in Hexagons
%%if we want to do size of 7 (hexagon in a hexagon array)
x_num = 30;
y_num = 30;
diameter = 100*7 + 100*6;
distance = diameter;
margin = 100;
% Define the long distance in the hexagonal lattice
long_distance = sqrt(3)*(distance + diameter) - diameter;
xlimit = 2*margin + diameter*x_num + (x_num-1)*(distance - diameter)/2;
display(xlimit);
ylimit = 2*margin + diameter*y_num + (y_num-1)*(sqrt(3)*(diameter + distance)/2 - distance);
display(ylimit);
figure;set(gca,'position',[0 0 1 1]);
set(gca,'DataAspectRatio',[1,1,1]);
% set(gca,'XColor',[1,1,1],'YColor',[1,1,1]);
set(gca,'XTick',[],'YTick',[]);
set(gca,'xlim',[0,xlimit],'ylim',[0,ylimit]);
box on;
% for x = 0:x_num-1
% for y = 0:y_num-1
% rectangle('position',[margin+(x*(diameter+distance)),margin+(y*(diameter+distance)),diameter,diameter],'curvature',[1,1],'FaceColor',[0,0,0]);
% end
% end
%Try to plot the posts by even and odd
if mod(x_num,2) == 0
odd_num_x = x_num/2;
even_num_x = x_num/2;
else
odd_num_x = (x_num - 1)/2 + 1;
even_num_x = (x_num - 1)/2;
end
if mod(y_num,2) == 0
odd_num_y = y_num/2;
even_num_y = y_num/2;
else
odd_num_y = (y_num - 1)/2 + 1;
even_num_y = (y_num - 1)/2;
end
for x = 0:odd_num_x-1
for y =0:odd_num_y-1
% rectangle('position',[margin+ x*(diameter + distance) , margin+(y*(diameter+long_distance)),diameter,diameter],'curvature',[1,1],'FaceColor',[0,0,0]);
draw_hexagon (margin+ x*(diameter + distance) + 250, margin + (y*(diameter+long_distance)),7,100,100);
end
end
for x = 0:even_num_x-1
for y = 0:even_num_y-1
% rectangle('position',[margin+ (distance + diameter)/2 + x*(diameter + distance) , margin + sqrt(3)*(diameter + distance)/2 + (y*(diameter+long_distance)),diameter,diameter],'curvature',[1,1],'FaceColor',[0,0,0]);
draw_hexagon (margin+ (distance + diameter)/2 + x*(diameter + distance) + 250, margin + sqrt(3)*(diameter + distance)/2 + (y*(diameter+long_distance)),7,100,100);
end
end
The function draw_hexagon I use above is:
%%Function to print hexagonal shaped island in a blank area
function draw_hexagon (position_x, position_y, size, diameter, distance)
% Size must be odd.
% Size is the number of posts on the longest diagonal of the hexagon.
if mode(size,2) == 0
error('Please input an odd number for the size parameter!');
end
side_num = (size - 1)/2 + 1;
% The strategy is to plot the lower half of hexagon, and then plot the top
% half of the hexagon.
% define a distance parameter that can switch between top and bottom
up_down = (side_num - 1)*sqrt(3)*(distance + diameter);
while side_num <= size
for index = 0:side_num - 1
rectangle('position',[position_x + index*(diameter + distance), position_y, diameter, diameter],'curvature',[1,1],'FaceColor',[0,0,0]);
rectangle('position',[position_x + index*(diameter + distance), position_y + up_down, diameter, diameter],'curvature',[1,1],'FaceColor',[0,0,0]);
end
side_num = side_num + 1;
up_down = up_down - sqrt(3)*(diameter + distance);
position_x = position_x - (distance + diameter)/2;
position_y = position_y + sqrt(3)*(distance + diameter)/2;
end
% positions are the lower left corner of the hexagon
end
Sorry It's not well commented. I was not intended to be distributed. Please let me know if you have any problem reading it.

Sign in to comment.

Accepted Answer

lvn
lvn on 20 Mar 2014
The problem with the spacing is in fact a problem of the line around the circle. Because you work on such small scales, it determines the size of the circle! This solves it I think. In your code change the rectangle functions to
rectangle('position',[position_x + index*(diameter + distance), position_y, diameter, diameter],'curvature',[1,1],'FaceColor',[0,0,0],'LineStyle','none');
and then Jan Simon's export print(gcf, 'test.eps', '-dpsc2', '-r1200', '-noui').
After conversion to pdf, the result looks ok to me (see attached).
  3 Comments
lvn
lvn on 20 Mar 2014
Glad it works! No particular reason for eps I guess (I never use pdf).
Frank
Frank on 20 Mar 2014
Add one thing to whom may concern:
In my case, I want to output nearly 10^5 posts on one figure, it's important to set the resolution to at least '-r1600' to obtain undistorted image.

Sign in to comment.

More Answers (4)

Chad Greene
Chad Greene on 18 Mar 2014
I highly recommend switching to export_fig instead of using print. Here's export_fig: http://www.mathworks.com/matlabcentral/fileexchange/23629-exportfig
Oliver Woodford, the author of export_fig has a quite helpful and succinct site with plenty of picture examples and troubleshooting tips here: https://sites.google.com/site/oliverwoodford/software/export_fig
Does the attached pdf look correct?
  4 Comments
Frank
Frank on 18 Mar 2014
FYI, this is the PDF I output by export_fig. And it looks no better than what I attached above. Please check it out.
Frank
Frank on 18 Mar 2014
Let me put it in a clear way. In my matlab figure file attached above, the diameter of the post is 100um, and the spacing between two posts are 100um as well. Did any of the output file (PDF,PNG) has perfect round posts and right spacing?

Sign in to comment.


Chad Greene
Chad Greene on 18 Mar 2014
Oh, interesting. I see the problem now, but is this a pdf issue, or an issue with the filled circle function? Perhaps simply creating a scatter plot and setting the size of the markers would fix it? http://www.mathworks.com/matlabcentral/answers/101738
  2 Comments
Frank
Frank on 18 Mar 2014
Good idea, it's really smart. I'll try it out, but at this point I don't know whether this will solve the problem.
My intuitive guess is it has something to do with the rendering. I tried '-painters', '-zbuffer', and '-opengl', but none of them improve the quality. Also I've tried to play with the resolution '-r', but the distortion is still there even if I increase the resolution to very high.
Frank
Frank on 19 Mar 2014
I tried to output by scatter. The result is better since the circles are round. But the problem is the marker size on figure doesn't match the size on pdf. It seems that matlab automatically scale it when you output figure into pdf. Here are the figure and pdf I got.

Sign in to comment.


Chad Greene
Chad Greene on 19 Mar 2014
Frank,
Follow the circles command with axis equal to ensure the circles don't get squashed.
  2 Comments
Frank
Frank on 19 Mar 2014
Thanks for your code. I tried it out, and the result is weird because: not only the spacing is still not right, but also the circles are defected.
I my original script, I already use
set(gca,'DataAspectRatio',[1,1,1])
to set the axis scaling factor to 1 (which works the same as
axis equal)
BTW, I tried the scatter plot, the dots look better than plotting circles, but the size control (SizeData) method doesn't count for the PDF.
I think we may keep thinking about scatter plot, or consider if something is wrong with the rendering issue.
Frank
Frank on 19 Mar 2014
Hi Chad, the results of scatter plot is very promising except i don't know how to control the size of the marker.
According to the link you send to me,I use:
s = 100; %Marker width in units of X
currentunits = get(gca,'Units');
set(gca, 'Units', 'Points');
axpos = get(gca,'Position');
set(gca, 'Units', currentunits);
markerWidth = s/diff(xlim)*axpos(3); % Calculate Marker width in points
to get the size of the marker, and then use:
scatter(X,Y,makerWidth^2)
to plot. The circles are not distorted on the output pdf, however, the size is apparently wrong. Do you have any idea on size control?

Sign in to comment.


Jan
Jan on 19 Mar 2014
This creates a perfectly looking EPS and after a conversion the resulting PDF is fine also:
print(gcf, 'test.eps', '-dpsc2', '-r1200', '-noui')
Increasing the resolution to 1200 makes the difference.
  1 Comment
Frank
Frank on 20 Mar 2014
Hi Jan,
Thanks for your effort. The circles look perfectly round. But the other issue still exist : the spacing between posts are definitely not right. (if you look at my code, then you can see spacing = diameter)
I don't know if it has something to do with rendering. But I'm happy to discuss with you anytime if you are willing to do so.

Sign in to comment.

Categories

Find more on Specifying Target for Graphics Output in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!