Place MATLAB legend such that it does not overlap on the plot - matlab

I am generating multiple plots of different datasets in succession using MATLAB. I would like the legend positions to be such that they don't overlap on the plotted lines and it would be ideal if this placement could be done automatically.
I am aware of setting the 'Location' to 'best' to achieve this but the placement of the legend tends to be awkward when 'best' is used (below). Also, I would like the legend to be inside the plot. I also came across a way to make the legend transparent (here) so that it does not render the plotted data invisible, but explicitly placing the legend elsewhere is what I am looking for.
Is there a way to place the legend at the extremes of the image ('NorthWest', 'SouthWest' etc) automatically such that it does not overlap on the plotted data (apart from the methods suggested above)?

So, you have tried using Location instead of Position? For example:
x =1:100;
y = x.^2;
lgd = legend('y = x.^2');
set(lgd,'Location','best')
and you are getting odd results correct? A quick way of solving this would be to still use Location, with best, and extract the coordinates:
lgd.Position
You should get something like this:
ans =
0.7734 0.3037 0.1082 0.0200
which maps to:
[left bottom width height]
You will need to focus on left and bottom. These two values, left and bottom, specify the distance from the lower left corner of the figure to the lower left corner of the legend, and they are analogous to the grid frame you are using.
Then, depending on the size of the frame (I would suggest you use axis([XMIN XMAX YMIN YMAX]) for this, if possible), you can pinpoint the position of the legend within the grid. What you can do next, is check if and which of your graphs in the plot cross paths with the legend (maybe define a relative distance function based on some distance threshold) and if they do, then randomly reposition the legend (i.e. change the values of left and bottom) and repeat until your conditions are met.
If this still troubles you I can write a short snippet. Finally, know that you can always opt for placing the legend on the outside:
set(lgd,'Location','BestOutside')

Related

How to rescale vector field onto a different grid?

I currently have a vector field that looks something like this, generated with the following basic structure, where Z is some matrix:
[X,Y] = meshgrid(x,y)
[grad_x, grad_y] = gradient(Z)
quiver(X,Y,grad_x,grad_y)
I would like for this plot to be rescaled, such that the x-axis ranges from 1.5 to 3.8 and the y-axis ranges from 100 to 250, but for the arrows themselves to look identical. The only difference in the figure should be the axes labels.
I have tried:
grad_x_rescaled = [(grad_x - min(grad_x))./(max(grad_x)-min(grad_x))].*(3.8-1.5);
grad_y_rescaled = [(grad_y - min(grad_y))./(max(grad_y)-min(grad_y))].*(250-100);
But the problem with this is that although the grad_x and grad_y get rescaled overall, the scaling of the arrows themselves relative to each other are not conserved, and results in below (note the thick black streaks are presumably arrowheads, but the important thing is that the direction and relative sizes of the arrows are not exactly like in the first case.
Is there a matlab function or an expression to renormalize data into a new range, but such that the renormalized data is scaled relative to itself (such as the arrows should be scaled the same relative to one another)?
To simply change the axes tick labels you could use Matlab's ability to specify tick marks and tick labels. Basically you would just tell Matlab where to put the ticks and what the labels should say like this:
xticks(linspace(0,1,6))
xticklabels(linspace(1.5,3.8,6))
yticks(linspace(0,1,6))
yticklabels(linspace(100,250,6))

How to reverse the direction of Y-Axis of MatLab figure generated by `imagesc()` function

I am trying to display data in a matrix using imagesc() function but it is showing row index in decreasing order (Assuming origin at left-bottom). Any idea what mistake i could be making or how to correct this?
The matrix only has zeros and ones in it.
Set Ydir property of the current axes to normal
By default, imagesc uses reverse for YDir
set(gca,'YDir','normal');
See Documentation for Axes properties
Before:
After:
Note: This completely flips the inside data as well (it supposed to). As you are dealing with matrices, I hope this is what you want.
If you don't want to affect inside data, you need to change order of YTickLabels instead.
There's another option which requires slightly less code:
axis ij
Reverse the coordinate system so that the y values increase from top to bottom.
As in this case (as it is already reversed), you could use
axis xy
To get back to normal, so that y values increases from bottom to top.
As mentioned in the docs of axis.

Matlab subplot disappears on reposition

I have the following function that is supposed to create subplots that are tightly spaced within a row, and distributed with spacing in each column. It also lets you set buffer sizes for the edges:
function fill_graph()
for x=1:3
for y=1:3
ax = subplot(3,3,(x-1)*3+y);
left_buffer = .05;
right_buffer = .025;
x_pos = left_buffer+(x-1)*(1/3*(1-left_buffer-right_buffer));
width = 1/3*(1-left_buffer-right_buffer);
bottom_buffer = .1;
top_buffer = .05;
spacing=.07;
height = (1/3)*(1-2*spacing-top_buffer-bottom_buffer);
y_pos = bottom_buffer+(y-1)*(spacing+height);
set(ax,'position',[x_pos,y_pos,width,height])
if x>1
set(gca,'yTickLabel','');
ylabel('');
end
if y>1 || x~=2
xlabel('')
end
end
end
When I run the function, the bottom row of plots and the leftmost plot on the middle row all disappear.
I'm aware this probably has something to do with the fact that subplots will disappear when they overlap with one another, but regardless of how far apart I set the spacing, I can't get the bottom row to appear (the only way I've found is setting the bottom buffer above .34, which only works some of the time). I've tried switching 'position' to 'outerposition', which should make it so that none of them overlap, but that doesn't seem to work either.
I have seen Second subplot disappearing, but when I specify the position in that manner (subplot('position',x_pos,y_pos,width,height)), it writes over the plots that are already there. If I place that code before I plot, the plots resize as soon as I issue the plot command.
Try replacing subplot(....) with axes().
The command subplot checks all existing axes on the figure to see if any come near the required space, or were likely generated by a previous, identical subplot command. Sounds like you are spending all of your time/effort reverse engineering this part of Matlab's algorithm.
The command axes just makes a new axis on the figure, no matter what else is already there. For example, I have built plots where the axes intentionally overlap. As long as you are doing all the positioning work yourself, don't waste your time with subplot.

MATLAB: Plotting two different axes on one figure

The MATLAB surf plot below is essentially two plots plotted adjacent to each other. For clarity, I have included some code below used to prepare the plot:
band1 = horzcat(band1, eSurface2(:,:,1));
band2 = horzcat(band2, eSurface2(:,:,2));
surf(band2,'DisplayName','band2');
surf(band3,'DisplayName','band2');
I would like for the y axis numbering to restart at the start of the second graph. How do I go about doing that?
You can use the 'YTick' and 'YTickLabel' properties of the axis to control the ticks, this way you can make it start from zero for the second graph. It will require some trail and error to get it right. See the relevant doc here (you'll have to scroll all the way to the bottom of the page).
Take advantage of the following feature of 'YTickLabel': "If you do not specify enough text labels for all the tick marks, MATLAB uses all of the labels specified, then reuses the specified labels".

CorePlot polar plot

It became apparent that I needed to attempt to modify CorePlot code to allow me to plot Polar/Radar plots, due to heavy memory usage trying to plot circles/spokes as ScatterPlots.
I realised I could continue to use CPTScatterPlot for the actual polar data, however somehow I needed to modify the drawGridLinesInContext, such that instead of straight lines at each location, CPTXCoordinate would draw the circular line, CPTYCoordinate would be ignored, and CPTZCoordinate would draw the spokes.
I had to create new classes based on their XY siblings viz CPTPolarGraph, CPTPolarPlotSpace, CPTPolarAxisSet, CPTPolarAxis. The new code continues to use X and Y axis to plot those axes, however a Z axis was introduced to manage the spokes.
Now I seem to have cracked this, however if I scroll up and down, the circles continue to pass through the X and Y axis ticks, as they should do, but when I scroll left and right, the circles get redrawn and no longer sit on the ticks.
I obviously got some more debugging to do here, but was hoping for some pointers from the CorePlot crew, as to what might be happening
.
I can zip my modified version of CorePlot_1.1, including a example polar scatter plot, and forward if needs be.
The positioning of the centreViewPoint tracks precisely, as the spokes are always generated from the same point, wherever the centre is in the plotArea. The rings are also always generated from the same centre.
It seems to me that somehow, the diameters of the rings when I scroll left right get changed from the first plot presentation, yet when I scrolled Up-down they don't. Notice that when the plot is scrolled to left edge or right edge the major rings are line up on the major ticks again, as are the minor.
I tried reversing the code such that only the CPTCoordinateY get plotted, and I see the same effect, except scrolling up-down exhibits the changing in ring diameter size.
Now perhaps CGPoint startViewPoint = [thePlotSpace plotAreaViewPointForPlotPoint:startPlotPoint]; which establishes the diameter of a ring from its x-coordinate, is not returning correctly. Although perhaps also the locations set are changing, but why should they if no zooming has been done.
I'm kind of struggling here, as when I walk through the code the locations don't appear to change.
This is likely a pixel alignment issue. The tick drawing code aligns the tick marks with the pixel grid but the new axis drawing does not. Look at CPTAlignRectToUserSpace() and the other alignment functions in CPTUtilities.h.
Edit:
You also may need a custom setter method for the zRange in the plot space. Make it similar to the xRange and yRange setters. The notifications fired by these methods are important—they force other parts of the graph to redraw when the plot space changes.