How to Output Accurate PDF from Matlab figure

조회 수: 22 (최근 30일)
Frank
Frank 2014년 3월 18일
댓글: Frank 2014년 3월 20일
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
lvn
lvn 2014년 3월 19일
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 2014년 3월 19일
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.

댓글을 달려면 로그인하십시오.

채택된 답변

lvn
lvn 2014년 3월 20일
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
lvn
lvn 2014년 3월 20일
Glad it works! No particular reason for eps I guess (I never use pdf).
Frank
Frank 2014년 3월 20일
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.

댓글을 달려면 로그인하십시오.

추가 답변 (4개)

Chad Greene
Chad Greene 2014년 3월 18일
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
Frank
Frank 2014년 3월 18일
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 2014년 3월 18일
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?

댓글을 달려면 로그인하십시오.


Chad Greene
Chad Greene 2014년 3월 18일
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
Frank
Frank 2014년 3월 18일
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 2014년 3월 19일
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.

댓글을 달려면 로그인하십시오.


Chad Greene
Chad Greene 2014년 3월 19일
Frank,
Follow the circles command with axis equal to ensure the circles don't get squashed.
  댓글 수: 2
Frank
Frank 2014년 3월 19일
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 2014년 3월 19일
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?

댓글을 달려면 로그인하십시오.


Jan
Jan 2014년 3월 19일
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
Frank
Frank 2014년 3월 20일
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.

댓글을 달려면 로그인하십시오.

카테고리

Help CenterFile Exchange에서 Graphics Performance에 대해 자세히 알아보기

Community Treasure Hunt

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

Start Hunting!

Translated by