Ignoring markers and lines in legend

I want to ignore markers in my legend but do not know how to do this properly. k in this code is the variable in the for loop that is being incremented.
C = {'k','b','r','g','y',[.5 .6 .7],[.8 .2 .6]};
Plot1 = loglog(Discret,L2err,'.r', 'MarkerSize',15);
hold on
Plot2 = loglog(Discret,L2err,'color',C{k}, 'LineWidth', 2);
legendInfo{k} = ['Factor = ' num2str(k)];
legend(Plot2,legendInfo)
legend(legendInfo)
triang_x = [Discret(2), Discret(5)];
triang_y = interp1(Discret, L2err, triang_x);
hold on
z = loglog(triang_x([1,2,2]), triang_y([1,1,2]), 'k', 'LineWidth', 2);
grid on
Problem is also that the lines of the triangle also goes into the legend. Any ideas on how to fix this? Really appreciate it!

 Accepted Answer

dpb
dpb on 28 Jun 2018
Edited: dpb on 29 Jun 2018
...
legendInfo{k} = ['Factor = ' num2str(k)];
legend(Plot2,legendInfo)
legend(legendInfo)
...
If you want only certain lines to be in the legend, then use the first form but with the subset array of only the line handles (and labels to match) in the call to legend.
figure
hold on
...
legendInfo={num2str([1:N].','Factor = %d')};
for k=1:N
...
hL1(k) = loglog(Discret,L2err,'.r', 'MarkerSize',15);
hL2(k) = loglog(Discret,L2err,'color',C{k}, 'LineWidth', 2);
triang_x = [Discret(2), Discret(5)];
triang_y = interp1(Discret, L2err, triang_x);
hLz = loglog(triang_x([1,2,2]), triang_y([1,1,2]), 'k', 'LineWidth', 2);
end
grid on
legend(hL2,legendInfo)
should come close if I interpret what you want correctly.
ADDENDUM
To emulate your loop with fake data but to only label the lines...salt to suit.
% dummy data to emulate lines on plot
x=[1:10];
y=-0.1*x+2; y=repmat(y,5,1)+linspace(0,-0.8,5).';
x=x.'; y=y.';
nc=size(y,2);
C = {'k','b','r','g','y',[.5 .6 .7],[.8 .2 .6]};
legendInfo=num2str([1:nc].','Factor = %d');
hL=zeros(nc,1);
figure, hold on
for k=1:nc
hL(k)= plot(x,y(:,k), 'color',C{k}, 'LineWidth', 2, ...
'markeredgecolor','r', 'markerfacecolor','r', ...
'marker','.', 'MarkerSize',15);
tx=[x(2), x(5)];
ty=interp1(x,y(:,k),tx);
plot(tx([1,2,2]), ty([1,1,2]), 'k', 'LineWidth',0.5);
end
legend(hL,legendInfo)
grid on
The chosen data makes the triangles overlap but the effect is what is shown in your figure and note there are no labels excepting for the lines...I did combine the characteristics into the one line object so it does reflect the marker as well as color; if you don't want that effect, then you can revert to the two lines but again, just pass the one set of handles to legend and those are all you'll get.
Also notice there's a fair amount of stuff that can be moved out of the loop and vectorized and done before/afterwards to simplify the loop itself...
ADDENDUM 2
tx=[x(2), x(5)];
ty=interp1(x,y(:,k),tx);
plot(tx([1,2,2]), ty([1,1,2]), 'k', 'LineWidth',0.5);
If the points are going to be existing ones, there's no need for interp1 here;, just build ty the same was as tx. Perhaps began or will be going to use other points???
i1=2; i2=5; % Set the desired points; could be variable...
itx=[i1 i2 i2]; % Build the addressing vector from them
plot(x(itx), y(itx), 'k', 'LineWidth',0.5); % and use the indexing vector

19 Comments

I only want one plot to be assigned to a color and legend entry. Problem is as I said that each marker and line from the interpolation triangle will be shown inside the legend.
dpb
dpb on 28 Jun 2018
Edited: dpb on 28 Jun 2018
Sorry, don't follow the specifics of what you expect. Show us a working example of what you get and what is wrong, specifically.
What's wrong with the above solution; it'll only label the actual lines, not the interpolation. It won't have the markers on the lines, either, of course as you don't have a line handle with the combination of line and marker.
Ameer's Answer is the same thing illustrated for just one case; mine simply attempts to infer what is inside your loop from the incomplete code snippet but all you'll have in the legend is the linestyle of the solid line.
If the issue is that the legend linestyle doesn't match the combo linestyle you artificially created by using two lines; the simplest answer is to "don't do that!" but specify the properties as you want for the single line:
hL=plot(x,y,'k', ...
'Marker','.', ...
'MarkerFaceColor','r', ...
'MarkerEdgeColor','r', ...
'MarkerSize',15);
legend('Combo Line/Marker')
results in
Thanks for getting back to me. The attached pic shows what I actually get. The actual code is quite long to post here. But I can show what I have done for the legend which unfortunately did not work.
legendInfo{k} = num2str(mattemp2);
legend(Plot2,legendInfo);
Do I need another for-loop in order to keep the previous or following legend entries? I have a mistake in my plan which I could not identify up until now. Maybe you can see that.
Well, we can't debug what we can't see.. :(
That can't be the only legend call you have; in the original snippet you had a general legend as well which is (guessing here, remember can't see your terminal from here) likely the culprit because it sets the 'update' status to 'auto' which means legend adds to itself every time a new line is created; that is NOT what you want here; as the examples Ameer and I showed, if you only write legends for the line handles for which you actually want legend entries, that's all the entries you'll get.
It shouldn't take much effort to create some dummy data and a working loop that creates one of the above type plots for a couple of lines -- it only takes one or two and doesn't have to be anything except dummy data -- that you can attach that mimics the loop structure. With that it shouldn't be hard to finish up what I started initially.
Thanks for the hint dpb!
I will try it out and let you know if I can ship a fix for myself ;-)
See the updated Answer with a sample that creates a plot that looks much like yours...and which is virtually the original Answer...
Thanks a lot for your efforts dpb! Having a look at it and will get back to you!
Detox
Detox on 2 Jul 2018
Edited: Detox on 2 Jul 2018
Problem I have now is that it still shows the triangles in the legend with the legendInfo. Any option I can ignore them? That's really weird that you cannot skip one element so that would help also gave legend the Parameter Plot1 in my case which did not help.
And I need the interp function as I need the slope of each individual line.
You can supress graphics objects from appearing in a legend by setting:
hasbehavior( hObject, 'legend', false );
where hObject is the graphics object you don't want to appear in the legend.
"... it still shows the triangles in the legend with the legendInfo"
Only if you're still doing so; they don't show in the Answer code which duplicates your graphic in essence.
Show the code; we can't debug what we can't see, but the problem in the original snippet you posted is that you included a call to legend that wasn't just for the desired objects; undoubtedly that's the problem still. Duplicate the logic I showed...
"need the interp function as I need the slope of each individual line."
??? Not to do what is in the code snippet and the slope isn't anywhere to be seen and interp1 doesn't return slope. Please explain.
@Adam: Thanks a lot for the hint!
@dpb: It worked writing the same line legend(Plot1,...) again !? So the legend looks as I want now but the format specifier is still something I want to change.
legendInfo=num2str([1:k].','Factor = %d');
for me I want to change it by adding the factor read from the file title "Factor0.5Test" and I already extracted the char "0.5" and can easily convert that of course with str2num but how can I now tell the legend to change that inside the loop? Thanks a lot for your efforts so far!
Again, we can't debug what we can't see...the legend will be exactly what you provide for the handles that are passed. If you have to write it twice, you've done something wrong the first time and, as shown, there should be only one call per handle.
There's no variable for "factor" shown anywhere in the code snippet so to have picked up on that would have been a job for the Crystal Ball Toolbox.
Simply build the appropriate legendInfo array based on the variable and the string you want to write instead of using the loop indices as does the existing code.
And, yet again, the easier/better way is to draw the plots, then write the legend and other overall annotations/enhancements afterwards--it's continuing to try to fight doing things inside the loop itself that is probably the bulk of the difficulty you're having.
legendInfo=num2str(factor,'Factor = %0.1f Test');
>> factor=[0.5:0.1:1].';
>> legendInfo=num2str(factor,'Factor = %0.1f Test');
>> legendInfo
legendInfo =
6×17 char array
'Factor = 0.5 Test'
'Factor = 0.6 Test'
'Factor = 0.7 Test'
'Factor = 0.8 Test'
'Factor = 0.9 Test'
'Factor = 1.0 Test'
>>
where factor is the (column) array of the test factors read from the files. Salt to suit...
Sure dpb! Thanks for your impetus. I have sent you a private message with a link to the full code. Any advice would really be appreciated! :)
dpb
dpb on 2 Jul 2018
Edited: dpb on 2 Jul 2018
Attach the section of the code with the plotting here so everybody has access...have you taken the suggestions of saving the appropriate handles (had done originally, good!) and moving all the legend stuff to after the loop? That should make virtually all your problems go away, almost like magic.
ADDENDUM
I did glance over the code--it has the same structural issue of the legend and other plot-wide elements are still inside the loop over k instead of outside and after the various lines have been added. Move everything that is global context to the overall figure outside of the loop per the example I showed earlier.
Save the various factor values in an array for use as illustrated above to create the legend text labels.
It's possible to do stuff inside the loop but the way legend works it's a lot simpler to just give it everything at once unless there's a really compelling reason otherwise and here everything you need is quite simple; just an array of values over a half-dozen files.
As soon as I fixed the issue with the Legend name I will post it here. That's the last problem though. How to change the name and not using the iterator as a place holder but the extracted char in each loop or run.
Again I showed that above...to work inside the loop, it's better to store the legend text for the line in the 'DisplayName' property; then when the loop is done call
legend('show')
hL(i)=plot(x,y, ...
'DisplayName',legendInfo(k,:), ...
...);
Use the above syntax to build the legend including the factor.
Thanks again. I got what you mean but writing it outside the loop does not make much sense to me because the file will be called inside the loop as the factors and values will all be extracted from the file I sent you ergo writing it outside the loop would not work in my case as the factors change.
Of course it will with the simple expedient of just saving the single factor required while going through the loop or, more expeditiously, building the info array.
Saving a half-dozen floating point values in the day of many-GBytes of memory is nothing if it simplifies other code; you're already reading it, just make it an array. There appears to be a lot of unnecessary machinations on the data that cleaning up could probably also make things "much more simpler" than they now seem.
But, again, if inside the loop, I'd recommend the 'DisplayName' property to your attention vs legend() multiple times in the loop.

Sign in to comment.

More Answers (1)

Ameer Hamza
Ameer Hamza on 28 Jun 2018
Edited: Ameer Hamza on 28 Jun 2018
From legend documentation, it appears that MATLAB does not support direct control over legend markers. They are decided automatically by the corresponding plot() markers shape. However, you can get the required effect by making two plots, one with markers and another without the marker and displaying only one in the legend. For example, try this
hold on
p1 = plot(1:10, '+-', 'Color', 'r');
p2 = plot(1:10, '-', 'Color', 'r');
l = legend(p2, {'legend without marker'});
p2 is a dummy plot, just for displaying the legend. You might consider plotting only a few points if the dataset is large to save space.

2 Comments

Thanks for the answer! Sounds good and that's what I have done so far but it will be in a for-loop so I have to find a workaround for this. Very unfortunate I wasted 3 days already trying to play with the settings :/
Oh! I failed to notice that you are already doing this in your code. For code with for-loop please refer to dbp's answer.

Sign in to comment.

Asked:

on 28 Jun 2018

Commented:

dpb
on 2 Jul 2018

Community Treasure Hunt

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

Start Hunting!