Brushing data on plot linked with 2D variable - matlab

I have a 2D numeric array (100x100 double) which looks like this when plotted on a surf plot:
I am trying to link the plot with the variable, and then delete some data points (say, one of the two peaks) both in the variable (make the selected points 0) and in the plot, by using the brush tool on the plot.
The problem is, when the variable and the plot are linked, the brushing tool selects the full rows for the points that fall on the selected area, as shown here:
Selection when data is linked (I want to avoid this type of selection):
Same selection, data not linked (this is what I want, but with linked data):
Is there any way to avoid this, and select only the points that I want?
Details about this phenomenon can be found here:
https://uk.mathworks.com/help/matlab/ref/matlab.graphics.interaction.internal.brush.html#mw_b080675e-afd3-4251-99d8-a8273e85dc6c
I have also tried using other types of plots (mesh, sky, etc), but I could not find any solutions.
As a minimal reproducible example, you can use the following code:
PeaksVariable = peaks;
surf(PeaksVariable)
linkdata on
brush on

You can get the brushed data points with
PeaksVariable = peaks;
brush on;
s = surf( PeaksVariable );
b = logical( s.BrushData );
Then set the brushed points to whatever value you want
PeaksVariable( b ) = NaN;
And optionally update the surface with the updated data variable
s.ZData = PeaksVariable;

Related

How to add datatips in a fitted surface chart

I have created a fitted surface from x, y, z data points. How do I insert data tips for the min and max value in the chart?
defDM_fit = fit([def_X, def_Y],def_Z,'cubicinterp');
clf;
figure(2)
plot(defDM_fit,[def_X, def_Y],def_Z);
using the following test code is raising an error "Invalid argument. The object has been deleted or does not support data tips":
datatip(defDM_fit, def_X(1), def_Y(1), def_Z(1))
And I do not know how to manage that tips show up at min and max value in the chart by code.
Plotting a fitted surface created with fit outputs a 2x1 graphics array. The first element is the surface (Surface object), the second element is a Line object that holds the points on which your data was fitted. In order to add datatips, you will have to use one of these two objects, and more probably the Surface object, for example:
load franke
T = table(x,y,z);
f = fit([T.x, T.y],T.z,'linearinterp');
p = plot( f, [T.x, T.y], T.z );
datatip(p(1),T.x(1),T.y(1),T.z(1))
The first argument of datatip is a graphic object, not a surface/line fit object.
defDM_fit = fit([def_X, def_Y],def_Z,'cubicinterp');
figure(2)
p=plot(defDM_fit,[def_X, def_Y],def_Z);
datatip(p, def_X(1), def_Y(1), def_Z(1))
There are many other things that may be wrong with your approach, particularly because you are showing a surface plot (surf) in your example, yet your code uses a line plot (plot). I am not even sure what the arguments even are, the way you are putting them.
Consider reading the documentation of the functions you are using, as they come with examples on how to use them: https://uk.mathworks.com/help/curvefit/fit.html

How can I plot a meshgrid in Matlab with empty gridsquares (i.e. showing the gridlines) [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I am using meshgrid to create matrices of coordinates to plot model output within gridded data of Europe.The dataset is 106 x 103 and everywhere there is no data, the value is set to NaN.
[meshlat,meshlon]=meshgrid(rlat,rlon);
surf(meshlon,meshlat,data(:,:,1)),'linestyle','none';view(2);
But I actually want all the grid squares that don't have output to be plotted too (so the extra ones that are in this map, comprising Scandinavia..but I want them to be white):
I'm thinking that I may need to create a third matrix the same size as the meshlat and meshlon and fill it with a number that would correspond to the colour white...plot it, then type 'hold', and plot my map on top? I'm not sure how to specify the white colour though? Or is there another way of doing it?
Here is a simplified version of the problem:
data = magic(4);
data(1,2) = nan;
x = [1,2,3,4];
lat = repmat(x,4,1);
lon = lat';
surf(lon,lat,data);view(2);
You can see the blank space on the left..In this example, I would like to see extra grid lines where the squares would be (if there were no nans in the dataset)
When I tried #Hoki's suggestion, I ended up with grid squares around every 'cell' in the matrix...whether it was filled with a number or a NaN (below) which is not what I originally needed. I wanted just the land masses (that have real numbers, not NaNs to have a gridline around them):
By using the full dataset (in the first image), I plotted the outline of the gridsquares for the landmasses using:
surf(meshlon,meshlat,fulldata(:,:,1),'FaceColor','none','EdgeColor','k');view(2);
Then I plotted my 'coloured' grid squares over that original dataset:
hold on;
surf(meshlon,meshlat,data(:,:,1)),'linestyle','none';view(2);
Using the simplified example below, the code is:
data = magic(4);
datafull=data;
data(1,2) = nan;
x = [1,2,3,4];
lat = repmat(x,4,1);
lon = lat';
surf(lon,lat,datafull,'FaceColor','none','EdgeColor','k');view(2);
hold on
surf(lon,lat,data);view(2);
There are several ways to achieve the result you want. The "cleaner" and less memory hungry way is unfortunately quite more complex than the simple workaround.
Method 1 (not recommended, and not detailed ...)
You need to create a special colormap with a "white" color at one end (min or max), making sure that the value that will map to this color are not in your data.
Before you plot your data, for all the pixels for Scandinavia (or any pixel which doesn't have a value but where you want to see your grid) replace the NaN by the value which will map to the white in the colormap.
As you can see, this method will force you to re-evaluate your colormap for each new dataset, so not very flexible.
Method 2 (Recommended, more generic ...)
Just create an empty 'grid' exactly how you want it, then display it on top of your surface plot. This grid will be transparent so it can be used on top of any dataset.
For your example:
%% Your example
data = magic(4);
data(1,2) = nan;
x = [1,2,3,4];
lat = repmat(x,4,1);
lon = lat';
surf(lon,lat,data);view(2);
%% The overlay grid:
% Create a grid the same size of the data. We set the Z value to the max of
% the original data set to make sure the grid will be "on top" of the
% surface plot when view from above.
datagrid = ones(size(data))*max(data(:)) ;
% plot the grid on top of the previous surface plot
hold on
hm = mesh(lon,lat,datagrid,'FaceColor','none','EdgeColor','k') ;
This is what you'll get. The second figure on the right is the same with a different view so you understand what is going on on the Z dimension.
With a reference grid like that, you can overlay it on any of your dataset, regardless of which areas have been blanked/nullified.

How to fill below 2d graphes in 3d with plot3()?

i plotted a 3d plot with the following code, but with my own measured data:
Data = rand(1000, 4); % 4 Channels or more or less
Time = 1:1000;
sData = size(Data);
vSignal = 1:sData(2);
plot3(Time, vSignal(ones(1, sData(1)), :), Data);
view(-150, 60)`
Now I want to fill under the graphes I plotted.But it´s really important for me to be able to plot and fill below multiple graphes!
Do I have to use fill3()? I imported my data as a numeric matrix. I tried several ways but I failed.
Thanks for help.
Here is how to use fill3:
for ii = 1:sData(2)
fill3([Time,Time(end),Time(1)],ii*ones(1,size(Time,2)+2),[Data(:,ii);zeros(2,1)],ii*ones(2+size(Time,2),1),'EdgeColor','none');
end
I use the for loop since I create a patch for each plot separately (I call the filled-in area a Patch). For each patch, I need to give its boundaries, and fill3 will fill everything in between. The boundaries are the exact points that you used in plot3, but in addition you need two more points on the x-y plane to close the patch (to make it a polygon). That is the reason I extend the vectors by 2.

Removing the edge line on a contour plot

I used Matlab to create a polar coordinate and converted it into Cartesian coordinate.
[th,r] = meshgrid((0:0.5:360)*pi/180,0:.02:1);
[X,Y] = pol2cart(th,r);
I get data on this mesh and produce a contourf plot over it.
My problem is that I get a center line in my contourf plot which I would like to remove, could some help me with this
Thank you
If I extend a little bit your example to get something I can plot, I do reproduce the problem:
[th,r] = meshgrid((0:0.5:360)*pi/180,0:.02:1);
[X,Y] = pol2cart(th,r);
Z = sqrt( X.^2 + Y.^2 ) ;
isoLevel = 0:0.1:10 ;
[C ,hc] = contourf(X,Y,Z,isoLevel) ;
The black line at the interface is because the function contourf create patch objects and these objects tend to "close" themselves (they will create a line between the first and last point defined in their profile).
This is easier to observe if you do not complete the definition of your profile over 360 degrees. The picture on the right shows you the same example but with the grid only from 0:350 and with the LineStyle set to :.
As you can see, it is difficult to control how Matlab will actually render this specific profile limit. There are ways to control specific edges of patch objects but in this case it would involve retrieving the handle of each patch object (10 in my case but many more in more complex cases), locating the edge you want to control and basically redefining the patch (each of them). You'd be better off drawing the patches from scratch yourself.
Fortunately, there is a simple ways out of that: Get rid of all the patch edge lines...
but then you may miss your isolines! No problem, just plot them on top of the patches !
You get all your colored patches (with no border) and a set of (iso)lines over which you have full control.
Two easy way to get you patch without lines (i) set the shading to shading flat, or (ii) specify 'EdgeColor','none' in the parameter of the contourf function.
To get your isolines on top, use the sister contour function.
So using the same X,Y and Z data than previously:
isoLevel = 0:0.1:10 ;
[C ,hc] = contourf(X,Y,Z,isoLevel,'EdgeColor','none') ; %// set of patches without border
% shading flat %// use that if you didn't specify ('EdgeColor','none') above
hold on
[C2 ,hc2] = contour(X,Y,Z,isoLevel,'LineColor','k') ; %// now get your isolines
will render:
It's a good idea to store the handle hc2 in case you want to modify your isolines properties (color, style, thicknes etc ...).
Also, specifying the isoline levels is recommended. This way you can make sure both contour and contourf will use the same set of isovalues. It could probably work without this (because the underlying dataset is the same), but personally I always prefer to be explicit and not rely on background calculations.

Smooth Excel-like plot with correct legend in Matlab

I have some sparse data and want to plot them as markers connected by a smooth, interpolated line - like the default behaviour of Microsoft Excel.
There are solutions to this problem easily found on the internet, but I find them unsatisfactory. What they do is: plot the sparse data as one data set drawing it as markers without lines, interpolate it with a method of choice and plot the interpolation as the second data set, with lines without markers.
The problem with these tricks is that in the legend the two data sets will be listed separately. I would expect a single data set depicted in the legend as a line crossing through a marker.
Is it possible in Matlab?
If you want to plot an interpolated line there are lots of ways to do that. You can try generating an interpolated line using the matlab interp1() function.
Let's create x and y data with no NaN.
x = randn(1,10)
y = randn(1,10)
If you want 1000 data points where previously you only had a few, that's pretty easy:
x2 = min(x):(max(x)-min(x))/1000:max(x)
y2 = interp1(x,y,x2,'cubic')
and you can plot your data and spline using
plot(x,y,'r+')
hold on
plot(x2,y2,'r-')
A custom legend is straightforward when you use handle graphics. You can plot a dummy data set with a red line passing through a marker using
h(1) = plot(NaN,NaN,'r-+')
lstring{1} = 'Data';
You can then add a legend that points to this data set using
legend(h,lstring)
You'll end up with something that looks roughly like this:
The nice thing about using handle graphics (i.e. the h) is you can throw whatever data series you want into the legend as h(end+1) and lstring{end+1}.