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.
Related
I=imread('ft.jpg');
[a b]=size(I);
figure;imshow(I);
j=rgb2ycbcr(I);
[m n]=size(j);
figure;
imshow(j);
ca=mat2cell(j,8*ones(1,size(j,1)/8),8*ones(1,size(j,2)/8),3);
p = 1;
figure;
figure;
X=ones(m,n,8,8);
for c=1:size(ca,1)
for r=1:size(ca,2)
temp=zeros(8,8,'uint8');
temp(:,:)=X(c,r,:,:);
temp=temp-128;
temp=dct2(temp);
subplot(size(ca,1),size(ca,2),temp(:,:)); %// Change
imshow(ca{c,r});
p=p+1;
end
end
the error is:
Error using ==> subplot at 309
Illegal plot number.
Error in ==> project at 22
subplot(size(ca,1),size(ca,2),temp(:,:)); %// Change
That's because you're not calling subplot properly. It needs p as the parameter for the third argument, not temp. p determines which slot you want to place your figure in. You putting in a doublevector as the third parameter makes no sense. Also, ca contains 8 x 8 pixel blocks, and you'd like to show the DCT of each block. Your current code does not do this. Actually, X is what you're trying to find the DCT of, and it's all ones.... doesn't make much sense.
You probably want to show the DCT of each block inside the figure as well, not ca.... and so you need to do this:
for c=1:size(ca,1)
for r=1:size(ca,2)
temp = double(ca{c,r}); %// Change - cast to double for precision
temp=temp-128;
temp=dct2(temp);
subplot(size(ca,1),size(ca,2),p); %// Change
imshow(temp,[]); %// Change here too
p=p+1;
end
end
Note that I did imshow(temp,[]); so that we can contrast stretch the block so that the minimum value gets mapped to black while the maximum value gets mapped to white. Everything else is a shade of gray in between. Be advised that this doesn't change the image itself. It only changes it for display.
Suggestion
You should read up on my post on how subplot works here: How does subplot work and what is the difference between subplot(121) and subplot(1,2,1) in MATLAB?
Once you read through this post, you'll have a better understanding of how each parameter works for subplot, and how you can display graphs / images in a figure.
Minor Note
Looks like you took that code from this post but you didn't copy and paste properly :) That %// Change comment, as well as the variable name ca looked oddly familiar.
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.
In the past, there has been asked a question about customizing the linewidth in gplot (see In MatLab, how to adjust the line width drawn by the function 'gplot'?). I am dealing with a slightly more complicated version, which prevents me from using the solution given there. Therefore, I would like to ask how to do the following: I would like to adapt the line width of some of the calls of gplot, and not of others. I am namely calling gplot several times and using hold on to plot them in one figure. I am trying to draw a graph, with multiple types of edges (A and A2). And k paths in it. I am currently using the following code:
figure
hold on
gplot(A,coor,'k*:')
gplot(A2,coor,'k-')
plot(coor(T,1),coor(T,2),'k.','MarkerSize',20)
plot(coor(T,1),coor(T,2),'bo','MarkerSize',20)
% a line where I define my own colors (not shown, since not relevant)
set(gca,'ColorOrder',colors)
hold all
for i=1:k
gplot(Path,coor)
end
hold off
But I would like to draw the paths with a larger line width, while keeping the A and A2 at the standard line width 1.
Can someone help me? Thank you very much!
You can get the children of the axis before and after adding the extra lines, and only set the new ones to have a larger linewidth:
figure
hold on
gplot(A,coor,'k*:')
gplot(A2,coor,'k-')
plot(coor(T,1),coor(T,2),'k.','MarkerSize',20)
plot(coor(T,1),coor(T,2),'bo','MarkerSize',20)
ChildrenBefore=get(gca,'children');
% a line where I define my own colors (not shown, since not relevant)
set(gca,'ColorOrder',colors)
hold all
for i=1:k
gplot(Path,coor)
end
hold off
ChildrenAfter=get(gca,'children');
NewChildren=setdiff(ChildrenAfter,ChildrenBefore);
set(intersect(findall(gcf,'type','line'),NewChildren),'LineWidth',5)
I'm plotting two pcolors on top of each other (using the m_map algorithm m_pcolor). The reason for this is that the second pcolor has transparency in it, and so shows the pcolor underneath. The first plot consists of just ones and zeroes, and I would like it to be just black and white. I would like the second to use the colormap jet, but I can't work out how to set one colormap without changing the other. My code at the moment is:
h1 = m_pcolor(Lon', Lat', black_background);
hold on;
h = m_pcolor(Lon', Lat', input_matrix);
Thanks in advance,
Adam
For this limited application, the easiest way is probably to append a row of zeros onto the colormap, deal with scaling (the clim property) yourself so that each plot takes advantage of the appropriate part of the colormap.
cm=colormap('jet'); %# Nx3
cm = [cm; 0 0 0]; %# append black row: (N+1)x3
h1 = m_pcolor(Lon',Lat',black_background);
set(h1,'clim',[length(colormap),length(colormap)])
hold on
h2 = m_pcolor(Lon', Lat', input_matrix);
set(h2,'clim',[length(colormap)-1, length(colormap)-1])
This should get you close, but I haven't tested it since I'm not on my matlab machine.
Another option is freezeColors from the file exchange (but this may only work for different axes within the same figure window, I'm not sure about different plots in the same axes object).
I would like to plot a vertical line (I'd prefer any orientation, but I'd be happy with just vertical right now) with two-color dashes, say red-blue-red-blue-...
I know I could do it like this:
plot([1,1],[0,1],'r'),
hold on,
plot([1,1],[0,1],'--b')
However, since I need to be able to move the line, among others, it should only have a single handle. How could I do this?
EDIT
Thank you for your answers. I guess I should indeed give some more information.
I have some data that is classified into different parts. I want to be able to manually adjust the boundaries between classes. For this, I'm drawing vertical lines at the classification boundaries and use draggable to allow moving the lines.
For the boundary between the red and the blue class, I'd like to have a red/blue line.
plot(ones(10,1),linspace(0,1,10),'-bs','MarkerFaceColor','r','MarkerEdgeColor','none','linewidth',6)
is what I'm actually using at the moment. However, it's not so pretty (if I want equal spacing, it becomes a real pain, and I want to give both colors the same weight), and I would like to have the possibility to use three colors (and not with marker edge and face being different, because it makes my eyes bleed).
Unfortunately, draggable does not allow me to use multiple handles, and grouping the lines with hggroup does not seem to create a draggable object.
cline looks like a promising approach, but rainbow colors won't work for my application.
You can use the code you have, and just concatenate the handles from each line into a vector of handles. When you want to change the properties of both lines simultaneously, the SET function is able to accept the vector of handles as an argument. From the documentation for SET:
set(H,'PropertyName',PropertyValue,...)
sets the named properties to the
specified values on the object(s)
identified by H. H can be a vector of
handles, in which case set sets the
properties' values for all the
objects.
Here's an example:
h1 = plot([1 1],[0 1],'r'); %# Plot line 1
hold on;
h2 = plot([1 1],[0 1],'--b'); %# Plot line 2
hVector = [h1 h2]; %# Vector of handles
set(hVector,'XData',[2 3]); %# Shifts the x data points for both lines
UPDATE: Since you mention you are using draggable from the MathWorks File Exchange, here's an alternate solution. From the description of draggable:
A function which is called when the
object is moved can be provided as an
optional argument, so that the
movement triggers further actions.
You could then try the following solution:
Plot your two lines, saving the handle for each (i.e. h1 and h2).
Put the handle for each in the 'UserData' property of the other:
set(h1,'UserData',h2);
set(h2,'UserData',h1);
Create the following function:
function motionFcn(hMoving) %# Currently moving handle is passed in
hOther = get(hMoving,'UserData'); %# Get the other plot handle
set(hOther,'XData',get(hMoving,'XData'),... %# Update the x data
'YData',get(hMoving,'YData')); %# Update the y data
end
Turn on draggable for both lines, using the above function as the one called when either object is moved:
draggable(h1,#motionFcn);
draggable(h2,#motionFcn);
I've never used it, but there's a submission by Sebastian Hölz called CLINE on the Mathworks File Exchange that seems related.
I don't know how to do exactly what you want, but presumably the reason you want to do this is to have some way of distinguishing this line from other lines. Along those lines, take a look at MathWorks' documentation on 2-D line plots. Specifically, this example:
plot(x,y,'--rs','LineWidth',2,...
'MarkerEdgeColor','k',...
'MarkerFaceColor','g',...
'MarkerSize',10)
should give you plenty of ideas for variation. If you really need the two-color dashes, it might help to specify why. That way, even if we can't answer the question, perhaps we can convince you that you don't really need the two-color dashes. Since you've already ruled out the over-lapping solution, I'm fairly certain there's no solution that answers all of your needs. I'm assuming the two-colorness is the most fluid of those needs.