Matlab plot: remove connecting line between disconnected regions? - matlab

Assume you have 1000 indexed datapoints, with two labels grouped into region1 and region2. Here is an example of how to generate such random data
indices = 1:1000;
data = zeros(size(indices));
% some regions of data
region1 = [50:100 200:340 450:500 670:980];
region2 = setdiff(indices, region1);
% generating random data
data(region1) = rand(size(region1)) + 1;
data(region2) = rand(size(region2));
Now, if I plot these two regions I get a plot shown below
The code to generate the plot
% plotting
figure(1);
cla(gca);
hold on;
plot(region1, data(region1));
plot(region2, data(region2));
hold off;
Now the question: Is there an elegant way of removing the connecting lines between the disconnected data regions, without doing much data manipulation? I still want to use the solid line linestyle, or have a look similar to that.

If you make the x or y values into NaN then they wont be plotted. Since you have two complimentary regions, you can use them to set values to NaN...
% Two vectors which each cover ALL elements in "data", but with NaN where
% the other region is to be plotted. As per example, indices=1:1000;
r1 = 1:1000; r1(region2) = NaN;
r2 = 1:1000; r2(region1) = NaN;
% Plot all data for both lines, but NaNs wont show.
figure(1); clf;
hold on;
plot(r1, data);
plot(r2, data);
hold off;
Output:

Turns out if you represent regions as a vector of the same length as x and y with integer values representing the index of the region (e.g. regions = [1 1 1 2 2 1 1 1 ..]), there is an elegant one-linear that does the job for an arbitrary number of regions. Here is an example
% Generating test data
x = 1:1000;
y = sin(x/100) + rand(1, 1000);
regions = repelem([1 2 3 1 2 3 1 2 3 3], repelem(100, 10)); % a [1 x 1000] vector
% Plotting
plot(bsxfun(#rdivide, x(:), bsxfun(#eq, regions(:), unique(regions(:))')), y(:));
Here, I am building the matrix for x with values that should not be plotted being Inf, due to the #rdivide division by 0. The result is the following.
I hope this will be helpful for someone in the future.

Related

Creating graphs that show the distribution in space of a large number of 2D Random Walks at three different time points

So essentially I have this code here that I can use to generate a 2D Random Walk discretely along N number of steps with M number of walkers. I can plot them all on the same graph here.
clc;
clearvars;
N = 500; % Length of the x-axis, also known as the length of the random walks.
M = 3; % The amount of random walks.
x_t(1) = 0;
y_t(1) = 0;
for m=1:M
for n = 1:N % Looping all values of N into x_t(n).
A = sign(randn); % Generates either +1/-1 depending on the SIGN of RAND.
x_t(n+1) = x_t(n) + A;
A = sign(randn); % Generates either +1/-1 depending on the SIGN of RAND.
y_t(n+1) = y_t(n) + A;
end
plot(x_t, y_t);
hold on
end
grid on;
% Enlarge figure to full screen.
set(gcf, 'Units', 'Normalized', 'Outerposition', [0, 0.05, 1, 0.95]);
axis square;
Now, I want to be able to Create graphs that show the distribution in space of the positions of a large number
(e.g. n = 1000) random walkers, at three different time points (e.g. t = 100, 200 and 300 or any three time points really).
I'm not sure how to go about this, I need to turn this into a function and iterate it through itself three different times and store the coordinates? I have a rough idea but iffy on actually implementing. I'd assume the safest and least messy way would be to use subplot() to create all three plots together in the same figure.
Appreciate any assistance!
You can use cumsum to linearize the process. Basically you only want to cumsum a random matrix composed of [-1 and 1].
clc;
close all;
M = 50; % The amount of random walks.
steps = [10,200,1000]; % here we analyse the step 10,200 and 1000
cc = hsv(length(steps)); % manage the color of the plot
%generation of each random walk
x = sign(randn(max(steps),M));
y = sign(randn(max(steps),M));
xs = cumsum(x);
xval = xs(steps,:);
ys = cumsum(y);
yval = ys(steps,:);
hold on
for n=1:length(steps)
plot(xval(n,:),yval(n,:),'o','markersize',1,'color',cc(n,:),'MarkerFaceColor',cc(n,:));
end
legend('10','200','1000')
axis square
grid on;
Results:
EDIT:
Thanks to #LuisMendo that answered my question here, you can use a binomial distribution to get the same result:
steps = [10,200,10000];
cc = hsv(length(steps)); % manage the color of the plot
M = 50;
DV = [-1 1];
p = .5; % probability of DV(2)
% Using the #LuisMendo binomial solution:
for ii = 1:length(steps)
SDUDx(ii,:) = (DV(2)-DV(1))*binornd(steps(ii), p, M, 1)+DV(1)*steps(ii);
SDUDy(ii,:) = (DV(2)-DV(1))*binornd(steps(ii), p, M, 1)+DV(1)*steps(ii);
end
hold on
for n=1:length(steps)
plot(SDUDx(n,:),SDUDy(n,:),'o','markersize',1,'color',cc(n,:),'MarkerFaceColor',cc(n,:));
end
legend('10','200','1000')
axis square
grid on;
What is the advantage ? Even if you have a big number of steps, let's say 1000000, matlab can handle it. Because in the first solution you have a bruteforce solution, and in the second case a statistical solution.
If you want to show the distribution of a large number, say 1000, of these points, I would say the most suitable way of plotting is as a 'point cloud' using scatter. Then you create an array of N points for both the x and the y coordinate, and let it compute the coordinate in a loop for i = 1:Nt, where Nt will be 100, 200, or 300 as you describe. Something along the lines of the following:
N = 500;
x_t = zeros(N,1);
y_t = zeros(N,1);
Nt = 100;
for tidx = 1:Nt
x_t = x_t + sign(randn(N,1));
y_t = y_t + sign(randn(N,1));
end
scatter(x_t,y_t,'k*');
This will give you N x and y coordinates generated in the same way as in the sample you provided.
One thing to keep in mind is that sign(0)=0, so I suppose there is a chance (admittedly a small one) of not altering the coordinate. I am not sure if you intended this behaviour to be possible (a walker standing still)?
I will demonstrate the 1-dimensional case for clarity; you only need to implement this for each dimension you add.
Model N steps for M walkers using an NxM matrix.
>> N = 5;
>> M = 4;
>> steps = sign(randn(N,M));
steps =
1 1 1 1
-1 1 -1 1
1 -1 -1 -1
1 1 -1 1
1 -1 -1 -1
For plotting, it is useful to make a second NxM matrix s containing the updated positions after each step, where s(N,M) gives the position of walker M after N steps.
Use cumsum to vectorize instead of looping.
>> s = cumsum(steps)
s =
1 1 1 1
0 2 0 2
1 1 -1 1
2 2 -2 2
3 1 -3 1
To prevent plot redraw after each new line, use hold on.
>> figure; hold on
>> plot(1:N, s(1:N, 1:M), 'marker', '.', 'markersize', 20, 'linewidth', 3)
>> xlabel('Number of steps'); ylabel('Position')
The output plot looks like this: picture
This method scales very well to 2- and 3-dimensional random walks.

Plotting the implicit function x+y - log(x) - log(y) -2 = 0 on MATLAB

I wanted to plot the above function on Matlab so I used the following code
ezplot('-log(x)-log(y)+x+y-2',[-10 10 -10 10]);
However I'm just getting a blank screen. But clearly there is at least the point (1,1) that satisfies the equation.
I don't think there is a problem with the plotter settings, as I'm getting graphs for functions like
ezplot('-log(y)+x+y-2',[-10 10 -10 10]);
I don't have enough rep to embed pictures :)
If we use solve on your function, we can see that there are two points where your function is equal to zero. These points are at (1, 1) and (0.3203 + 1.3354i, pi)
syms x y
result = solve(-log(x)-log(y)+x+y-2, x, y);
result.x
% -wrightOmega(log(1/pi) - 2 + pi*(1 - 1i))
% 1
result.y
% pi
% 1
If we look closely at your function, we can see that the values are actually complex
[x,y] = meshgrid(-10:0.01:10, -10:0.01:10);
values = -log(x)-log(y)+x+y-2;
whos values
% Name Size Bytes Class Attributes
% values 2001x2001 64064016 double complex
It seems as though in older versions of MATLAB, ezplot handled complex functions by only considering the real component of the data. As such, this would yield the following plot
However, newer versions consider the magnitude of the data and the zeros will only occur when both the real and imaginary components are zero. Of the two points where this is true, only one of these points is real and is able to be plotted; however, the relatively coarse sampling of ezplot isn't able to display that single point.
You could use contourc to determine the location of this point
imagesc(abs(values), 'XData', [-10 10], 'YData', [-10 10]);
axis equal
hold on
cmat = contourc(abs(values), [0 0]);
xvalues = xx(1, cmat(1,2:end));
yvalues = yy(cmat(2,2:end), 1);
plot(xvalues, yvalues, 'r*')
This is because x = y = 1 is the only solution to the given equation.
Note that the minimum value of x - log(x) is 1 and that happens when x = 1. Obviously, the same is true for y - log(y). So, -log(x)-log(y)+x+y is always greater than 2 except at x = y = 1, where it is exactly equal to 2.
As your equation has only one solution, there is no line on the plot.
To visualize this, let's plot the equation
ezplot('-log(x)-log(y)+x+y-C',[-10 10 -10 10]);
for various values of C.
% choose a set of values between 5 and 2
C = logspace(log10(5), log10(2), 20);
% plot the equation with various values of C
figure
for ic=1:length(C)
ezplot(sprintf('-log(x)-log(y)+x+y-%f', C(ic)),[0 10 0 10]);
hold on
end
title('-log(x)-log(y)+x+y-C = 0, for 5 < C < 2');
Note that the largest curve is obtained for C = 5. As the value of C is decreased, the curve also becomes smaller, until at C = 2 it completely vanishes.

Plotting a cell array

I need to plot a cell array with the following format in Matlab:
{[vector1], [vector2], ...}
Into a 2D graph with the index of the vector as the y and the vector as the x
([vector1], 1), ([vector2], 2), ...
Here's a simple option:
% some arbitrary data:
CellData = {rand(10,1)*50,rand(10,1)*50,rand(10,1)*50};
% Define x and y:
x = cell2mat(CellData);
y = ones(size(x,1),1)*(1:size(x,2));
% plot:
plot(x,y,'o')
ylim([0 size(x,2)+1])
so you plot each vector of x on a separate y value:
It will work as long as your cell array is just a list of vectors.
EDIT: For non equal vectors
You'll have to use a for loop with hold:
% some arbitrary data:
CellData = {rand(5,1)*50,rand(6,1)*50,rand(7,1)*50,rand(8,1)*50,rand(9,1)*50};
figure;
hold on
for ii = 1:length(CellData)
x = CellData{ii};
y = ones(size(x,1),1)*ii;
plot(x,y,'o')
end
ylim([0 ii+1])
hold off
Hope this answers your question ;)
Here's my (brute force) interpretation of your request. There are likely more elegant solutions.
This code generates a dot plot that puts the values from the vectors at each index on the y axis—bottom to top. It can accommodate vectors of different lengths. You could make it a dot plot of vector distributions, but you might need to add some jitter to the x value, if multiple occurrences of identical or nearly identical values are possible.
% random data--three vectors from range 1:10 of different lengths
for i = 1:3
dataVals{i} = randi(10,randi(10,1),1);
end
dotSize = 14;
% plot the first vector with dots and increase the dot size
% I happen to like filled circles for this, and this is how I do it.
h = plot(dataVals{1}, ones(length(dataVals{1}), 1),'.r');
set(h,'markers', dotSize);
ax = gca;
axis([0 11 0 4]); % set axis limits
% set the Y axis labels to whole numbers
ax.YTickLabel = {'','','1','','2','','3','','',}';
hold on;
% plot the rest of the vectors
for i=2:length(dataVals)
h = plot(dataVals{i}, ones(length(dataVals{i}),1)*i,'.r');
set(h, 'markers', dotSize);
end
hold off
Without any data this is the best I can come up with for what you want:
yourCell = {[0,0,0],[1,1,1],[2,2,2]}; % 1x3 cell
figure;
plot(cell2mat(yourCell));
ylabel('Vector Values');
xlabel('Index of Vector');
It makes a plot like this:
Hope this helps.

Replacing Values with Blanks in Matlab

I've found some solutions with cells but none with Numberarrays.
The Problem is simple, I have one Array a=(0,1,2,3,4,5,6,7) and I want to change every other value with "blankspace" like this a=(0,'',2,''...) so that the array stays the same length but has only every other value.
When I try something like this a(2:2:end)='';
I get a=(0,2,4,6) the length is not the same.
When I try a(2:2:end)=blanks(1);
It almost works :), but not exactly, I get a=(0,'32',2,'32',4,'32'...)
I know that actually 32 means 'space' (ASCII) what actually means it works properly. I then try to use this to set my TickLabels but it interprets it like 32 not like ASCII.
You can't introduce a space as an entry in a number array. You can only introduce numbers.
If you want that for using it as tick labels, convert to a cell array and then you can set some cells' contents to [] (empty):
a = [0 1 2 3 4 5 6 7]; % original vector
a = num2cell(a); % convert to cell
a(2:2:end) = {[]}; % set some cells' contents to []
x = 1:8; % x data for example plot
y = x.^2; % y data for example plot
plot(x, y) % x plot the graph
set(gca, 'xticklabels', a) % set x tick labels
To get tick labels without scientific notation use num2str with the appropriate format:
a = [0 1 2 3 4 5 6 7]*1e6; % original vector
a = num2cell(a); % convert to cell
a(2:2:end) = {[]}; % set some cells' contents to []
a = cellfun(#num2str, a, 'Uniformoutput', false); % convert each number to a string
x = [0 1 2 3 4 5 6 7]*1e6; % x data for example plot
y = x.^2; % y data for example plot
plot(x, y) % x plot the graph
set(gca, 'xticklabels', a) % set x tick labels

Matlab Recreating freqz, normalizing x axis and getting half of plot

I have a function which is basically recreating the freqz command in matlab. I have figured out how to plot the entire transform of my frequency response, but I only need half of it, and I need to normalize it from pi to 1 (where 0:pi represents my x axis, and I want that to go to 0:1). The code is here:
function freqrespplot(b, a)
hb = fft(b,512);
ha = fft(a,512);
magh = (abs(hb) ./ abs(ha));
angh = angle(hb ./ ha);
x = linspace(0,2*pi, 512);
subplot(2,1,1);
plot(x,magh,'g');
subplot(2,1,2);
plot(x,angh,'r');
end
In the example of b = [1 2 2], a = [0 1 .8], plots like the following:
freqrespplot([1 2 2], [0 1 .8]);
Magnitude
and my corresponding phase plot is
I want the x-axis (omega) to go from 0 to 1 in both cases, and correspond to 0 to pi by taking only half of the graph, like this if possible:
You only need some small changes, marked with comments in the code below:
function freqrespplot(b, a)
hb = fft(b,512);
ha = fft(a,512);
magh = (abs(hb) ./ abs(ha));
angh = angle(hb ./ ha);
x = linspace(0,2, 513); %// 2, not 2*pi. And 513. Last value will be discarded
x = x(1:end-1); %// discard last value to avoid having 0 and 2*pi (they are the same)
subplot(2,1,1);
plot(x(1:end/2),magh(1:end/2),'g'); %// plot only half
subplot(2,1,2);
plot(x(1:end/2),angh(1:end/2),'r'); %// plot only half
end
With your example b and a this produces
You may want to include one additional sample to reach the right edge of the graph. I comment only differences with the above code:
function freqrespplot(b, a)
hb = fft(b,512);
ha = fft(a,512);
magh = (abs(hb) ./ abs(ha));
angh = angle(hb ./ ha);
x = linspace(0,2, 513);
x = x(1:end-1);
subplot(2,1,1);
plot(x(1:end/2+1),magh(1:end/2+1),'g'); %// plot only lower half plus one value
subplot(2,1,2);
plot(x(1:end/2+1),angh(1:end/2+1),'r'); %// plot only lower half plus one value
end
Compare the resulting graph (rightmost part):