Scatterplot in Matlab: how to improve visualisation - matlab

Consider the following Matlab code creating a scatterplot, where I essentially draw horizontal lines of random numbers.
clear
rng default
s1=66;
%(1) Create vectors of random numbers with different dimensions and store them in the cell array K_id
%(some cells are empty on purpose)
dim=randi([1 1000],1000,1);
K_id=cell(s1,1);
K_id{1}=(1.99-0.01).*rand(dim(1),1) + 0.01;
for j=12:s1
K_id{j}=(1.99-0.01).*rand(dim(j),1) + 0.01;
end
%(2) Plot
for j=1:s1
scatter(K_id{j},j*ones(size(K_id{j},1),1));
hold on
end
Question 1: How can I increase the distance between every two lines, so that each line can be seen better, separated from the others? I am not interested in the y-axis. I have tried to increase the height at which each line is plotted, but the effect does not change because Matlab rescales everything.
Question 2: Next to each line, I would like to attach a label. These are the labels:
p_temp=(0:0.1:1).';
[ca, cb] = ndgrid(p_temp, p_temp);
p_grid=[ca(:) cb(:)];
p_grid(p_grid(:,1)+p_grid(:,2)>1,:)=[];
Specifically, the label of the line corresponding to K_id{j} is p_grid(j,:). For example, the label for K_id{1} is [0,0].
The problem is that there are too many lines and, hence, too many labels.
One idea could be to reduce the number of labels as follows. From the structure of p_grid, note that from row 1 to 11 p_grid(:,2)=0 and p_grid(:,1) goes from 0 to 1 at intervals of 0.1; from row 12 to 21, p_grid(:,2)=0.1 and p_grid(:,1) goes from 0 to 0.9 at intervals of 0.1; and so on.
Therefore, it would be sufficient for me to just insert the extreme labels:
[0 0],
[0 1],
[0.1 0],
[0.1 0.9],
[0.2 0],
[0.2 0.8], etc.
But how can I do that?
Or, do you have other suggestions to improve visualisation?

Related

Plotting transparent lines in MATLAB

I'm trying to create a plot in MATLAB of ERP data. At present, the below code plots a waveform for 26 participant for channel 1, with mean amplitude on Y axis and time on X. I want to change the plot such that the waveforms are all light grey, but become darker where there are a lot of waves on top of one another.
times = Condition1.time;
channel = [1];
% the difference (for every participant, every channel, and every timepoint)
diff = (grandaverages.Condition1.individual) - (grandaverages.Condition2.individual);
channeldiffwaves = squeeze( mean( diff(:,channels,:), 2 ) );
% make the space to put the figure on
figure; hold on;
% list of participants to plot
plotparticipantIdx = [1:26];
% go through each participant
for participantIdx = plotparticipantIdx
ptpdiffwave = channeldiffwaves( participantIdx, : );
plot( times, ptpdiffwave )
end
% make a x-axis at zero
plot( times, zeros( size(times) ), 'k' )
How can I make all lines light gray and darkening where lines overlap?
You can use the RGB-alpha quadruplet:
plot(x, y, 'Color', [0 0 0 0.3]);
The first three entries are your standard RGB-triplet, i.e. 0 0 0 for black, then change the alpha (=transparency) between 0 (invisible) and 1 (completely visible).
As a side-note, this isn't even documented in the Chart line appearance and behavior part of MATLAB's documentation.
I can't quite figure out when this syntax was introduced; on my R2007b it doesn't work, but from 2017 onwards this solution starts popping up on the internet, thus I presume this was introduced with the overhaul of the graphic's engine in R2016b.

In MATLAB: How can XData and YData be updated with a changing number of lines?

I am looking for a way to add vertical dividing lines separating consecutive days in a dynamically updating plot of animal migration data (location vs. time). Part of the challenge is that the number of these dividers changes as the plot domain expands to display more temporal data: As the number of days in the plot increases from 3 to 5, for example, the number of dividers increases by 2.
A minimal code example, written in MATLAB, is shown below:
xcols = [1; 1];
ycols = [0; 1];
figure(4)
clf
h.divs = plot(xcols,ycols,':k');
xlabel('time')
ylabel('location')
for ii=2:6
xcols(:,end+1) = [ii; ii];
ycols(:,end+1) = [0; 1];
% set(h.divs, 'XData', xcols, 'YData', ycols);
% set(h.divs, {'XData'}, num2cell(xcols',2), {'YData'}, num2cell(ycols',2));
drawnow
pause(1)
end
The problem centers on the two lines that have been commented out. If I comment in the first of these to try to update XData and YData with each new set of dividers (given as the 2 x DividerCount matrices xcols and ycols), then I receive an error that these inputs "must be a vector of numeric type". If I instead comment in the second line as way of using cell arrays to get around this (per this Stack Overflow post and this MATLAB Newsgroup post), then the code returns an error that "cell array handle dimension must match handle vector length" as soon as the number of dividers changes.
Hacky solutions are certainly possible. For example, the dividers can be plotted as a single line of horizontal and vertical segments, where the horizontal segments are placed above and below the y-axis limits of the plot. Or a fixed number of dividers can be used, with some of the dividers plotted outside the x-axis limits of the plot. The question is whether there is a non-hacky approach – one that can plot a potentially changing number of lines of identical style in the same figure with each pass of the loop.
Assume we have at the beginning
xcols = [1:3; 1:3];
ycols = [0 0 0; 1 1 1];
then h.divs = plot(xcols,ycols,':k'); will create 3 line objects.
Using
set(h.divs,{'XData'},num2cell(xcols',2),{'YData'},num2cell(ycols',2));
with size(xcols, 2)>3 will fail, because this assumes there are more than 3 graphics objects to set values for (but numel(h.divs) is still 3).
So do we have to create a new plot for every divider?
No!, because if we insert NaNs into our data, we can introduce gaps into lines.
As a first iteration, we could use this:
xcols = [1 1];
ycols = [0 1];
figure(4)
clf
h.divs = plot(xcols,ycols,':k');
for ii=2:6
xcols(end+(1:3)) = [nan ii ii];
ycols(end+(1:3)) = [nan 0 1];
set(h.divs, 'XData', xcols, 'YData', ycols);
drawnow
pause(1)
end
Starting with one divider which we plot, we then grow the data vectors (one-dimensional!) with a new value pair separated from the old data by a nan.
This of course grows the data vectors in the loop, which is not so great. Instead, if we know how many dividers there will be, we can preallocate with NaNs and only fill in new data in the loop:
n_div = 6;
xcols = nan(3 * n_div, 1);
ycols = nan(3 * n_div, 1);
figure(4)
clf
h.divs = plot(xcols,ycols,':k');
for ii=1:6
xcols((ii - 1)*3 + (1:2)) = [ii ii];
ycols((ii - 1)*3 + (1:2)) = [0 1];
set(h.divs, 'XData', xcols, 'YData', ycols);
drawnow
pause(1)
end
This has also the benefit that we can assign XData and YData separately, as in the new handle syntax:
h.divs.XData = xcols;
h.divs.YData = cols;
(or even better: h.divs.XData((ii - 1)*3 + (1:2)) = [ii ii];), because the lengths don't change.
You can start with divider definition:
divider.x=[];
divider.y=[];
divider.counter=0;
h.div=line('xdata',divider.x,'ydata',divider.y,'linestyle',':','color','k');
Which will draw no line, but handle will be set.
Then, perhaps in some loop, you can call:
divider.counter=divider.counter+1; % increase the counter
divider.x=[divider.x,nan,divider.counter*[1 1]]; % append X coords of new divider line
divider.y=[divider.y,nan,divider.counter*[0 1]]; % append Y coords of new divider line
set(h.div,'xdata',divider.x,'ydata',divider.y) % update dividers
drawnow % update figure immediately
This approach works because NaN value can be passed to line function but will not be plotted and neither will be lines from neighbour points.

Is it possible to plot rows of a matrix without a for loop?

I have a matrix that stores multiple functions in its rows each evaluated against the interval [0,20]. I'm running through a for loop to output them at the moment. Is there a better way of doing this or is this the only way of doing it in MATLAB?
h = 0.1;
xLine = 0:h:20;
nGrid = length(xLine);
nu = [ 1, 2, 3 ];
nNu = length(nu);
b = zeros(nNu,nGrid);
for i=1:nNu
b(i:i,1:nGrid) = besselj(nu(i), xLine);
end
hFig = figure(1);
hold on
set(hFig, 'Position', [1000 600 800 500]);
for i=1:nNu
plot(xLine, b(i:i,1:nGrid))
end
You can use plot vectorized. Specifically, you can supply b directly into plot but you need to make sure that the larger of the two dimensions in b matches the total number of elements in the vector xLine. This is what you have, so we're good. Therefore, because each unique signal occupies a row in your matrix, just supply b into your plot call and use it a single time.
hFig = figure(1);
hold on
set(hFig, 'Position', [1000 600 800 500]);
plot(xLine, b);
This will plot each row as a separate colour. If you tried doing this, you'll see that the plots are the same in comparison to the for loop approach.
Check out the documentation for plot for more details: http://www.mathworks.com/help/matlab/ref/plot.html
Replace for loop with:
plot(xLine, b(:,1:nGrid))
Note: I can't perfectly recall but some older versions of Matlab may want everything in columns and you'd want to transpose the matrices:
plot(xLine.', b(:,1:nGrid).')

Retaining colors while plotting multiple lines in a loop (Matlab)

I'm plotting a changing number of line trajectories on a sequence of images. I want the lines to be of different colors (as much as possible), and I want the colors to be retained throughout the sequence.
My code right now uses one plot command (plot(traj_to_plot{:})) using a cell array containing alternating x and y coordinates for each trajectory (meaning traj_to_plot={[traj1_x_coor] [traj1_y_coor] [traj2_x_coor] [traj2_y_coor] ...}). The order of the trajectories between each cycle of the loop is not always retained, and the number of the trajectories can change, as mentioned before.I need some way of relating between the trajectory drawn in one frame to the same trajectory drawn in a consecutive frame, and if it stopped, I need the following trajectories to stay in the same color (not simply change according to the ColorOrder cycle).
Here's two consecutive images where a change occurs:
the problem is evident in these sample photos. Because ant number 2 wasn't recognized in the second frame, the color order cycle changed the color of most of the trajectories.
Any ideas?
You could manually assign colours to each plot as so:
figure();
hold on;
plot(traj_to_plot{1},'red')
plot(traj_to_plot{2},'blue')
and so on.
If this a repetitive task, you could use something along the lines of:
colours = {'blue', 'green', 'red', 'cyan', 'magenta', 'yellow', 'black'};
figure();
hold on;
traj_to_plot1{1} = [1 2 3];
traj_to_plot1{2} = [0 2 4];
for ii=1:numel(traj_to_plot1)
plot(traj_to_plot1{ii},colours{mod(ii,numel(colours))});
end
traj_to_plot2{1} = [0.5 2 3.5];
traj_to_plot2{2} = [-0.5 2 4.5];
traj_to_plot2{3} = [-1.0 2 5];
for ii=1:numel(traj_to_plot2)
plot(traj_to_plot2{ii},colours{mod(ii-1,numel(colours))+1}); %Thanks to #wakjah.
end

Smoothing out of rough plots

I want to draw some plots in Matlab.
Details: For class 1, p(x|c1) is uniform for x between [2, 4] with the parameters a = 1 and b = 4. For class 2, p(x|c2) is exponential with parameter lambda = 1. Besides p(c1) = p(c2) = 0.5 I would like to draw a sketch of the two class densities multiplied by P(c1) and P(c2) respectively, as
a function of x, clearly showing the optimal decision boundary (or boundaries).
I have the solution for this problem, this is what the writer did (and I want to get), but there's no Matlab code, so I want to do it all by myself.
And this is what I drew.
And this is the MATLAB code I wrote.
x=0:1:8;
pc1 = 0.5;
px_given_c1 = exppdf(x,1);
px_given_c2 = unifpdf(x,2,4);
figure;
plot(x,px_given_c1,'g','linewidth',3);
hold on;
plot(x,px_given_c2,'r','linewidth',3);
axis([0 8 0 0.5]);
legend('P(x|c_1)','P(x|c_2)');
figure;
plot(x,px_given_c1.*pc1,'g','linewidth',3);
hold on;
plot(x,px_given_c2.*(1-pc1),'r','linewidth',3);
axis([0 8 0 0.5]);
legend('P(x|c_1)P(c_1)','P(x|c_2)P(c_2)');
As you can see, they are almost smiliar, but I am having problem with this uniform distribution, which is drawn in red. How can I change it?
You should probably change x=0:1:8; to something like x=0:1e-3:8; or even x=linspace(0,8,1000); to have finer plotting. This increases number of points in vectors (and therefore line segments) Matlab will use to plot.
Explanation: Matlab works with line segments when it does plotting!
By writing x=0:1:8; you create vector [0 1 2 3 4 5 6 7 8] that is of length 9, and by applying exppdf and unifpdf respectively you create two vectors of the same length derived from original vector. So basically you get vectors [exppdf(0) exppdf(1) ... exppdf(8)] and [unifpdf(0) unifpdf(1) ... unifpdf(8)].
When you issue plot command afterwards Matlab plots only line segments (8 of them in this case because there are 9 points):
from (x(1), px_given_c1(1)) to (x(2), px_given_c1(2)),
...
from (x(8), px_given_c1(8)) to (x(9), px_given_c1(9)).