How to prevent the legend from updating in R2017a and newer? - matlab

Since MATLAB R2017a, figure legends update automatically when adding a plot to axes. Previously, one could do this:
data = randn(100,4);
plot(data)
legend('line1','line2','line3','line4')
hold on
plot([1,100],[0,0],'k-')
to plot four data lines with a legend, and then add a black line for y=0. However, since R2017a, this leads to the black line being added to the legend, with the name "data1".
How do I prevent this line from being added to the legend, so that the code behaves like it did in older versions of MATLAB?
The only solution I have found so far on Stack Overflow is to remove the legend item after it has been added. The syntax is not pretty:
h = plot([1,100],[0,0],'k-'); % keep a handle to the added line
set(get(get(h,'Annotation'),'LegendInformation'),'IconDisplayStyle','off');

The release notes for MATLAB R2017a mention this change, and provide 4 different ways of handling the situation. These two methods are easiest to put into existing code:
1: Turn off auto updating for the legend before adding the black line. This can be done at creation time:
legend({'line1','line2','line3','line4'}, 'AutoUpdate','off')
or after:
h = findobj(gcf,'type','legend');
set(h, 'AutoUpdate','off')
You can also change the default for all future legends:
set(groot,'defaultLegendAutoUpdate','off')
2: Turn off handle visibility for the black line that you don't want added to the legend:
plot([1,100],[0,0],'k-', 'HandleVisibility','off')
The IconDisplayStyle method is also shown here. However, they use the dot notation, which makes the syntax is a bit prettier:
h = plot([1,100],[0,0],'k-'); % keep a handle to the added line
h.Annotation.LegendInformation.IconDisplayStyle = 'off';

Related

How to get rid of blue line in regression plot in matlab?

I have a regression plot with a blue (lsline) which I want to eliminate it but I don't know how.
plotregression(y.testTargets, y.outputs)
If you want to remove just the blue line you can use findall to retrieve the handle to the line object and then delete it. Also based on #rayreng's feedback, I made it so that the line is automatically removed from the legend as well.
r = plotregression(rand(5,1), rand(5,1));
%// Make the legend dynamic before removing the line
legend('-DynamicLegend', 'Location', get(legend, 'Location'));
%// Remove the blue line (with the "Fit" label)
delete(findall(r, 'DisplayName', 'Fit'));

Triangular split patches with painters renderer in MATLAB 2014b and above

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.

Remove Objects from Legend When You Have Also Used Fit, Matlab

I've plotted data points and fitted an exponential curve between them using 'fit' in Matlab. The problem is that with the fit-function I got the fitted line I wanted to plot, but also extra markers on top of my regular markers. I solved this problem by plotting the wanted markers on top of the unwanted so that they couldn't be seen. Now to the problem. When I want to show the legends those dots are also in there. How can I remove the markers from the legend without removing the fitted line since both of them are hidden inside the fit-function? Can I stop 'fit' from plotting the unwanted markers? So, I want to remove the blue dot called 'hoff' in the picture below.
You can leave out legend-entries by manually leaving out the handles of the lines, that you dont want to be in the legend. Try this:
%if you plot something, that you want showing up in the legend, save its handle:
h_line = plot(x,y)
%you dont want to show up this line? dont do anything, just plot it:
plot(myMarker)
%then set the legend-> you can add the text for your legend-entries with
%a cell-array containing the strings you want to show up:
legend([h_line another_line],{'Text1' 'Text2'})
with the example (see comments) I came to this solution:
close all
X=[1:10];
Y=X*0.5+0.1;
ft = fittype('poly2');
f = fit(X', Y',ft);
ha=plot(f)
hold on
hc=plot(X,Y)
hb=errorbar(X, Y, X*0.1, 'squarek','MarkerFaceColor','k','markersize',5)
hleg1 = legend([ha hc],{'hnh','ghg'});
-> this is just about splitting the plot-command. Hope that helps...
the result should look like this:

Matlab, gplot custom linewidth for some lines, but not all

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)

How to change the axes labels on a boxplot

When using the boxplot command from Statistics toolbox, the axes properties change in a strange way. For example, one gets
XTick = []
XTickLabel =
XTickLabelMode = manual
XTickMode = manual
What is happening to the axes and how one can rename the labels, and/or drop some of the ticks?
Try calling boxplot using the optional labels parameter.
Edit - further information about what boxplot actually does.
boxplot does some complicated stuff - type edit boxplot to take a look through the code, and you'll see it's a very long and intricate function. Basically it makes a blank axis with no axis labels, which is why you're seeing empty values for XTick etc. Then it makes the boxplot elements out of individual lines, and it simulates fake axis labels by adding text elements. You can find them and modify them directly by plotting into a figure f, then getting the Children of f, then iterating through to get their Children. Eventually you'll find text elements with the label names.
Try this:
xtix = {'A','B','C'}; % Your labels
xtixloc = [1 2 3]; % Your label locations
set(gca,'XTickMode','auto','XTickLabel',xtix,'XTick',xtixloc);
For some reasons resetting XTickMode to auto seemed to be key.
Thank you, Sam Roberts, that was helpful.
I wrote the following to remove group labels based on this advice. However, it removes ALL the labels, including axis and data tips. There doesn't seem to be a way to remove a label on an axis but leave it on a data tip.
m = get(get(get(figH,'Children'),'Children'),'Children');
for ii = 1:numel(m)
if(strcmp(get(m(ii),'Type'),'text'))
set(m(ii),'String', '');
end
end
The variable figH is the handle to your figure. You can also try gcf if the boxplot is the active figure handle.