Borrar filtros
Borrar filtros

how to place a legend in best corner?

55 visualizaciones (últimos 30 días)
meghannmarie
meghannmarie el 6 de Mzo. de 2019
Comentada: dpb el 8 de Mzo. de 2019
Is there a way to place legend in the best corner of subplot. I do not like it when the legend is in middle of whitespace.

Respuesta aceptada

dpb
dpb el 6 de Mzo. de 2019
Editada: dpb el 7 de Mzo. de 2019
Give this a try as a first cut...written for a one-line plot as is and takes the legend, axis handles.
Generalized, it could handle simply a figure handle and find the axes and legend from it and retrieve all the X,YData.
But, illustrates the logic idea of above; seemed to work here for a test case where drew the legend on a line and then moved the legend to not clash, but that's the extent of testing.
function flag=legendclash(hAx,hLg,x,y)
% Returns T if data in line x,y cross legend box in axes hAx
AxPosn=hAx.Position; % get axis position vector
Axbot=AxPosn(2); Axtop=Axbot+AxPosn(4); % compute bounding box
Axlft=AxPosn(1); Axrgt=Axlft+AxPosn(3); % dimensions for axis
LgPosn=hLg.Position; % and same for the legend
LGbot=LgPosn(2); LGtop=LGbot+LgPosn(4);
LGlft=LgPosn(1); LGrgt=LGlft+LgPosn(3);
if strfind(hAx.YDir,'normal')
yscaled=interp1(hAx.YLim,[Axbot Axtop],y); % compute scaled plotted values
else
yscaled=interp1(hAx.YLim,[Axtop Axbot],y); % compute scaled plotted values
end
if strfind(hAx.XDir,'normal')
xscaled=interp1(hAx.xlim,[Axlft Axrgt],x); % in the axis bounding box
else
xscaled=interp1(hAx.xlim,[Axrgt Axlft],x); % in the axis bounding box
end
% test if data intersects inside the legend bounding box
flag=any(iswithin(yscaled(:),LGbot,LGtop) & iswithin(xscaled(:),LGlft,LGrgt));
end
iswithin is my oft-used utlity function that is just "syntax sugar" but makes for simpler high-level code...
function flg=iswithin(x,lo,hi)
% returns T for values within range of input
% SYNTAX:
% [log] = iswithin(x,lo,hi)
% returns T for x between lo and hi values, inclusive
flg= (x>=lo) & (x<=hi);
NOTA BENE: ERRATUM
Corrected swapped indices in axis position calculation and inserted missing function keyword
ADDENDUM
Added logic to handle reversed axes
  12 comentarios
meghannmarie
meghannmarie el 7 de Mzo. de 2019
Just updated my code and ready to run it on big dataset!
lgd = gobjects(4,1);
for sp = 1:length(subplots)
gdem = plot(means{sp},gdem_depths,'-r','Parent',subplots(sp),'LineWidth',2);
lgd(sp) = legend([obs(sp) gdem std],'MOODS','GDEM','95% of time');
count = 1; loc = {'northeast', 'southeast','northwest','southwest','best'};
flag = true;
while flag && count <= numel(loc)
set(lgd(sp),'Location', loc{count});
flag = legendclash(subplots(sp),lgd(sp));
count = count + 1;
end %while flag && count <= numel(loc)
end %for sp = 1:length(subplots)
dpb
dpb el 8 de Mzo. de 2019
Let us know how it goes...

Iniciar sesión para comentar.

Más respuestas (1)

dpb
dpb el 6 de Mzo. de 2019
Try
legend(___,'Location','best')
ML tries to avoid the most data it can if it can find a location that the legend doesn't occlude anything.
It generally is "ok", but may not be what one might choose visually; the logic certainly isn't perfect.
Other than that, it's "pick a spot and go!" in that all other named choices are fixed locations relative to the axes or you set the actual position yourself programmatically (and then the "best" logic reverts to your own devices so you can test your skills against those of TMW :) )..
  2 comentarios
meghannmarie
meghannmarie el 6 de Mzo. de 2019
Editada: meghannmarie el 6 de Mzo. de 2019
I am using best right now, but I want the legend in the corner.
What I need to do is place the legend in a fixed corner and check for conficts with data. If there is a conflict, then move to next corner. If conflicts with all four corners, then use 'best'.
I cannot figure out how to check for the conficts with the plotted lines and the legend in the subplots.
I am about to plot 1000+ graphics, so it would be nice to get this to work. Picking a spot manually is out of the question.
dpb
dpb el 6 de Mzo. de 2019
I know of no builtin functionality, sorry.
Best I can think of is that you can retrieve the position of the legend where you choose to put it. Those are, by default, normalized dimensions within the axes object.
Then you would have to scale the plotted data to the same set of normalized position values of the axis and check if there is an intersection of values of the x,y normalized data within that area of the legend.
I have meetings in town here shortly so don't have time to try to see if can think of just what such code would look like at the moment, but I think that's the general idea.
I don't know if you can see the internals of the legend function any more or not; seems like TMW has made it almost totally opaque now so you may not be able to go look at what code for collision avoidance is inside it any longer.
Probably at least worth of a look to see if you can find anything on the FEX that somebody else may have already done...

Iniciar sesión para comentar.

Categorías

Más información sobre Graphics Object Programming en Help Center y File Exchange.

Etiquetas

Productos


Versión

R2017b

Community Treasure Hunt

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

Start Hunting!

Translated by