Matlab print -dpdf produces fuzzy lines - matlab

I have a problem when printing a 2D plot to pdf in matlab. I'm trying to print the following plot to a file (pdf, eps, svg, doesn't matter):
The problem is that at some points the line is very "jiggly" (sorry for the lack of a better word). I zoomed in on the upper part so you can see what I mean:
This is obviously not a problem for the matlab figure window. But when I print it to pdf, this is what it looks like:
The result is identical for pdf, svg and eps. I guess the problem is that matlab is creating a vectorized path (that is good!) but the path line is too thick and then every little spike can be seen.
Here's the code I'm using to produce the pdf:
sTitle = 'trajectory';
sFile = 'Data/trajectory.mat';
sPdfFile = 'pdfs/trajectory.pdf';
linewidth = 1;
fontsize1 = 18;
fig = figure;
% Adjust figure window size
set(fig, 'Position', [100 100 1400 800]);
% Set title
title(sTitle);
% Get states
[s, t] = load_data(some_data);
% Draw trajectory
plot(s(1,:), s(2,:), 'linewidth', linewidth);
% Labels and stuff
xlabel('x^W [m]', 'fontsize', fontsize1);
ylabel('y^W [m]', 'fontsize', fontsize1);
set(gca, 'fontsize', fontsize1)
% Axis font
set( gca , ...
'FontName' , 'Helvetica' );
set(gca, ...
'Box' , 'on' , ...
'TickDir' , 'out' , ...
'TickLength' , [.02 .02] , ...
'XMinorTick' , 'on' , ...
'XGrid' , 'on' , ...
'XMinorGrid' , 'off' , ...
'YMinorTick' , 'on' , ...
'YGrid' , 'on' , ...
'XColor' , [.3 .3 .3], ...
'YColor' , [.3 .3 .3], ...
'XTick' , -5:1:5, ...
'XTickLabelMode', 'auto', ...
'YTick' , -5:1:5, ...
'LineWidth' , 1 );
% Adjust view
axis([-2.5 2.5, -2.7 0.5]);
% Correct data aspect ratio
daspect([1,1,1])
% Print to PDF
width = 10;
height = 5;
set(gcf, 'PaperPosition', [0 0 width height]); %Position plot at left hand corner with width 5 and height 5.
set(gcf, 'PaperSize', [width height]); %Set the paper to have width 5 and height 5.
print('-dpdf', '-r600', sPdfFile);

According to this answer, this is an acknowledged bug, and the answerer provided a function to correct the issue for EPS files.
Since you are creating a PDF, I'd suggest using export_fig (requires a Ghostscript install) which, on the test script below, creates a smooth line in the produced PDF.
clc();
clear();
figure(1);
% Get states
n = 800;
x = linspace(0,2*pi,n);
s = [x.*cos(x);x.*sin(x)] + 0.3*exp(-0.3*[x;x]).*(rand(2,n)-0.5) ;
% Draw trajectory
plot(s(1,:), s(2,:), 'linewidth', 1);
axis([-20,20,-20,20]);
daspect([1,1,1])
% Print to PDF
print('traj.pdf','-dpdf', '-r600');
export_fig('traj2.pdf','-dpdf','-r600');
print PDF output:
export_fig PDF output:

Related

Cannot place an image just above a bar plot in matlab [duplicate]

This question already has answers here:
How can I modify my subplot positions to stop them overwriting each other?
(2 answers)
Closed 2 years ago.
I'm trying to print an image above a bar plot in the same figure, manually changing their position using the set command with the OuterPosition option.
This works only if the vertical coordinate of the image is at least 0.42, in fact if it is below this value then the image disappears.
How can I place the image below 0.42?
subplot(2,1,1)
imshow( imread('https://i.imgur.com/TVlQhpj.jpg') )
set(gca, 'OuterPosition', [.3 .42 .4 .4]);
subplot(2,1,2)
bar(1:10)
set(gca, 'OuterPosition', [.3 0 .35 .23]);
Assuming that your MATLAB version is recent (>= R2019b), you could use tiledlayout instead of subplot:
tiledlayout(2,1)
nexttile
imshow( imread('https://i.imgur.com/TVlQhpj.jpg') )
nexttile
bar(1:10)
which will place the map above the chart.
If you wish for the map to be directly above the chart, you will have to modify the dimensions manually as follows:
pos1 = [0.2 0.1 0.6 0.3];
subplot('Position',pos1)
bar(1:10)
pos2 = [0.2 0.41 0.6 0.3];
subplot('Position',pos2)
imshow( imread('https://i.imgur.com/TVlQhpj.jpg') )
The code you display does not match the animated image you link so we cannot know what is wrong in the code you actually used.
Setting the position of an axes is normally as straightforward as you were doing it. Worst case is the axes can move outside of visible area or be hidden behind other object. Consider the following example, the image never magically disapear, it just move where I tell it to:
function demo_move_image
% The code as provided -----------------------------------------------
ax1 = subplot(2,1,1) ;
imshow( imread('https://i.imgur.com/TVlQhpj.jpg') )
set(ax1, 'OuterPosition', [.3 .42 .4 .4]);
ax2 = subplot(2,1,2) ;
bar(1:10)
set(ax2, 'OuterPosition', [.3 0 .35 .23]);
% END - The code as provided -----------------------------------------
% Make a slider to control the vertical position of the image
uisld = uicontrol('Style','slider','Min',0,'Max',1,'Value',.42,...
'Unit','norm','Position',[.95 0 .05 1],'Callback',#slidercb) ;
title(ax1,num2str(get(uisld,'Value')))
% Callback for the slider
function slidercb(~,~)
set(ax1, 'OuterPosition', [.3 get(uisld,'Value') .4 .4])
title(ax1,num2str(get(uisld,'Value')))
end
end
Due to some reason, the subplot() command deletes the axes behind it, so it is better to use axes().
ax1 = axes('OuterPosition', [.3 .35 .4 .4]);
imshow( imread('https://i.imgur.com/TVlQhpj.jpg') )
ax2 = axes('OuterPosition', [.3 0 .35 .23]);
bar(1:10)

MATLAB slice functionality without using meshgrid

I have a 3D big matrix of size 2001 , 2001 , 30. I want to show its 30 slices in a 3D plot. I try to do it using matlab 'slice' command. However, since 'slice' needs to get the X Y Z locations as 3D arrays from the 'meshgrid' command, I get an 'out of memory error'.
My code is presented below.
How can I get over the 'Out of Memory' error without having to shrink
my 3D matrix, and with using my x,y,z locations of the matrix data ??
function presentFig4_ver4
close all; clc;
%im3 is of size of im3 = 201 201 30
load('img3D_shrinked.mat' , 'im3' , 'y_n_mm' , 'x_n_mm')
% next code until the mesh grid is in order to have the axes arranged
% so that the slices are shown one after the other in the depth
% direction of the figure and not from the bottom of the figure to the top of the figure
x_len=length(x_n_mm);
y_len=length(y_n_mm);
im3_reshaped=zeros(y_len , x_len , y_len);
for (ind_slice=1:30)
im3_reshaped(:,ind_slice,:)=im3(:,:,ind_slice);
end
[X,Y,Z]=meshgrid(x_n_mm,y_n_mm,y_n_mm);
slices=x_n_mm %= 0.23:0.1:(0.23+((30-1)*0.1)); %This is the same as x_n_mm
shownSlices=[1:30];
h=slice(X,Y,Z, im3_reshaped, [slices(shownSlices)],[],[]);
set(h,'EdgeColor','none','FaceColor','interp');
set( h , 'FaceAlpha', 'interp','AlphaData',im3*10^3)
dcm_obj = datacursormode(gcf); %datacursor mode on
set(dcm_obj,'enable','on','updatefcn',{#updateMe X Y Z im3_reshaped}) %update, need X,Y,Z, im3-values
set(gca,'FontName', 'Arial' ,'FontSize',14)
set(gca,'Position',[.32 .19 .41 0.9]) % [horizontal distance, vertical distance, width, height]
hold on
%camproj perspective
c_h=colorbar('horiz');
set( c_h, 'XDir', 'reverse' , 'Position' , [0.2 0.2 0.7 0.04],'FontSize',12);
opengl software
daspect([ 1 10 10])
axis tight
view(-49,16)
maxAxisLim=2; %mm
ylim([-maxAxisLim maxAxisLim])
zlim([-maxAxisLim maxAxisLim])
xlim([0.23 3.13])
camzoom(2)
xlabel('X [mm]','FontName', 'Arial' , 'FontSize',14)
ylabel('Y[mm]','FontName', 'Arial' ,'FontSize',14)
zlabel('Z [mm]','FontName', 'Arial' , 'FontSize',14)
x_h=get(gca,'XLabel');
y_h=get(gca,'YLabel');
z_h=get(gca,'ZLabel');
set(y_h, 'Units','normalized','Position', [0.03 -0.08 ] );
set(x_h, 'Units','normalized','Position', [0.6 0.12] );
set(z_h, 'Units','normalized','Position', [-0.08 0.27] );
set(get(gca,'YLabel'),'Rotation',-20);
set(get(gca,'XLabel'),'Rotation',12);
set(gca,'XTick',[0.23 0.5:0.5:3 3.13])
set(gca,'XTickLabel',{'0.23' '0.5' '1' '1.5' '2' '2.5' '3' '3.1' })
end % of presentFig4_ver4 function
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function msg = updateMe(src,evt,X,Y,Z,f)
evt = get(evt); %what's happenin'?
pos = evt.Position; %position
fval = f(X==pos(1)&Y==pos(2)&Z==pos(3)); %where?
msg = num2str(fval); %create msg
end

How to make xTicks fit into all the plot window?

In the plot below how can I make the xTicks fit into all the x axis? I can not understand where the problem is and I will appreciate any advice as a new MATLAB user.
here is the part of code where I plot this graph :
f=figure();
plot(time, C, 'b*');
hold on
plot(time, L_Tilde, 'g-.');
plot(time, U_Tilde, 'g-.');
tickStep = 1 ;
tickDates = datenum( 1996:tickStep:2007 ,1,1) ;
set(gca, 'XTick' , tickDates , 'XTickLabel' , datestr(tickDates,'yyyy') )
Try
axis tight
This will will set the limits of both axes to exactly the limits of the data.
Just define the ylimit:
set(gca,'Xlim',[1996,2007])
set(gca, 'XTick' , tickDates , 'XTickLabel' , datestr(tickDates,'yyyy') )
Danny's suggestion is the automized way. To ge the 1996 back, you can add some days of margin to both sides:
%// example data
time = datenum( linspace(1996,2007),1,1);
L_Tilde = randi(10,[1,numel(time)]);
figure(1);
plot(time, L_Tilde, 'g-.');
tickStep = 1 ;
tickDates = datenum( 1996:tickStep:2007 ,1,1) ;
xlimms = get(gca,'Xlim');
axis tight
set(gca, 'XLim', get(gca,'XLim')+[-100,+100])
set(gca, 'XTick' , tickDates , 'XTickLabel' , datestr(tickDates,'yyyy') )
Adjust the 100 according to your needs.

matlab bar colormap returns the same color for all bars

I have a problem with using bar and colormap.
I have a csv file like this which contains completion time for six tasks:
34,22,103,22,171,26
24,20,41,28,78,28
37,19,60,23,141,24
...
and I create a bar chart with of the means, and add the std variation errorbar.
res = csvread('sorting_results.csv');
figure();
y = mean(res)';
e = std(res);
hold on;
bar(y);
errorbar(y,e,'.r');
title('Sorting completion time');
ylabel('Completion time (seconds)');
xlabel('Task No.');
hold off;
colormap(summer(size(y,2)));
Why is the output like this? Why do the bars have the same color? And how do I put legends to the six bars?
A piece of code that does the magic. It doesn't use the canonical technique mentioned by #am304, as you will have a hard time setting up the legend with it. Here, for each one of the 6 input values, we plot a full 6 bars: one bar with the value and the remaining five set to zero.
x = rand(1,6); %create data
x_diag = diag(x); %zero matrix with diagonal filled with x
cmap = summer(6); %define colors to use (summer colomap)
figure('color','w','Render','Zbuffer'); %create figure
%bar plot for each x value
for ind_data = 1:length(x)
h_bar = bar( x_diag(ind_data, :)); %bar plot
set( get(h_bar,'children'), 'FaceVertexCData', cmap(ind_data,:) ) ; %color
hold on;
end
colormap('summer');
%legend-type info
hleg = legend( ('a':'f')' );
set(hleg, 'box', 'off');
%xticks info
set(gca, 'XTickLabel', ('a':'f')' );
%plot errors
e = ones(1,6) * 0.05;
errorbar(x, e,'.r');
set(gca, 'FontSize', 14, 'YLim', [ 0 (max(x) + max(e) + 0.1) ]);
See Coloring 2-D Bars According to Height in the MATLAB documentation. Only the first colour of the colormap is used to colour the faces, you need a bit of hack (as per code on that doc page) to do what you want.

Distance between axis label and axis in MATLAB figure

I'm plotting some data with MATLAB and I'd like to adjust the distance between axis label and the axis itself. However, simply adding a bit to the "Position" property of the label makes the label move out of the figure window. Is there a "margin" property or something similar?
In the above figure, I'd like to increase the distance between the numbers and the label "Time (s)" while automatically extending the figures size so that the label does not move out of bounds.
This is how I set up the figure / axis.
figure;
set(gca, ...
'Box' , 'off' , ...
'LooseInset' , get(gca, 'TightInset') * 1.5 , ...
'TickDir' , 'in' , ...
'XMinorTick' , 'off' , ...
'YMinorTick' , 'off' , ...
'TickLength' , [.02 .02] , ...
'LineWidth' , 1 , ...
'XGrid' , 'off' , ...
'YGrid' , 'off' , ...
'FontSize' , 18 );
I wrote a function that should do exactly what you want. It keeps the axes at the exact same size and position, it moves the x-label down and increases the figure size to be large enough to show the label:
function moveLabel(ax,offset,hFig,hAxes)
% get figure position
posFig = get(hFig,'Position');
% get axes position in pixels
set(hAxes,'Units','pixels')
posAx = get(hAxes,'Position');
% get label position in pixels
if ax=='x'
set(get(hAxes,'XLabel'),'Units','pixels')
posLabel = get(get(hAxes,'XLabel'),'Position');
else
set(get(hAxes,'YLabel'),'Units','pixels')
posLabel = get(get(hAxes,'YLabel'),'Position');
end
% resize figure
if ax=='x'
posFigNew = posFig + [0 -offset 0 offset];
else
posFigNew = posFig + [-offset 0 offset 0];
end
set(hFig,'Position',posFigNew)
% move axes
if ax=='x'
set(hAxes,'Position',posAx+[0 offset 0 0])
else
set(hAxes,'Position',posAx+[offset 0 0 0])
end
% move label
if ax=='x'
set(get(hAxes,'XLabel'),'Position',posLabel+[0 -offset 0])
else
set(get(hAxes,'YLabel'),'Position',posLabel+[-offset 0 0])
end
% set units back to 'normalized' and 'data'
set(hAxes,'Units','normalized')
if ax=='x'
set(get(hAxes,'XLabel'),'Units','data')
else
set(get(hAxes,'YLabel'),'Units','data')
end
end
In this case offset should be the absolute offset in pixels. If you want relative offsets, I think this function could easily be rewritten. hFig is the figure handle and hAxes the axes handle.
EDIT: create the figure using hFig = figure; and the axes by hAxes = axes; (then set up the axes like you did in the question: set(hAxes,...)) before calling the function.
EDIT2: added the lines where the 'Units' of hAxes and the XLabel are changed back to 'normalized' and 'data' respectively. That way the figure stays the way you want it after resizing.
EDIT3: modified the function to work for both X and Y labels. Additional input ax should be 'x' or 'y'.
You can accomplish this by adjusting the position of the axis an xlabel. I also suggest using "normalized" units so your positioning does not depend on the data range. Here's an example:
figure
plot(rand(1,10))
set(gca, 'Units', 'Normalized');
pos = get(gca, 'Position');
offset = 0.1;
set(gca, ...
'Box' , 'off' , ...
'LooseInset' , get(gca, 'TightInset') * 1.5 , ...
'TickDir' , 'in' , ...
'XMinorTick' , 'off' , ...
'YMinorTick' , 'off' , ...
'TickLength' , [.02 .02] , ...
'LineWidth' , 1 , ...
'XGrid' , 'off' , ...
'YGrid' , 'off' , ...
'FontSize' , 18 , ...
'Position' , pos + [0, offset, 0, -offset]);
h = xlabel('Time (s)');
set(h, 'Units', 'Normalized');
pos = get(h, 'Position');
set(h, 'Position', pos + [0, -offset, 0]);
I know this has been answered and all, but this is (to some extent) a simpler way:
relative_offset = 1.5;
close all;
figure(99);clf
plot(rand(1,10))
xlabel('The x-axis')
xh = get(gca,'XLabel'); % Handle of the x label
pause(0.2)
set(xh, 'Units', 'Normalized')
pause(0.2)
pos = get(xh, 'Position');
set(xh, 'Position',pos.*[1,relative_offset,1])
I have included the pause commands, since my system will get ahead of itself in some weird way otherwise.
/Niels