Wrong tick location when I set the x-axis labels manually in MATLAB - matlab

I have been trying to plot two vectors against some x values on the same graph. And I want to set the numerical x labels manually, as characters. But the final result looks weird.
vars = {'50', '100', '250', '500'};
inducing_p = linspace(1,4,4);
ind_table_mse = [0.9051 0.8911 0.8770 0.8688];
ind_table_mseF = [0.9155 0.9070 0.8796 0.8708];
plot(inducing_p, ind_table_mse);
hold on;
plot(inducing_p, ind_table_mseF);
title('ASA Flight Delay Dataset','interpreter','latex');
xlabel('Inducing points','interpreter','latex');
ylabel('MSE','interpreter','latex');
set(gca,'XTickLabel',vars);
xtickangle(45);
And I get this graph, which is not at all of what I indented. As, I would like to see only 50 100 250 500 labels on x. Any suggestions please?

You have first to modify the location of the ticks in your figure
figure
plot(inducing_p, ind_table_mse);
hold on;
plot(inducing_p, ind_table_mseF);
title('ASA Flight Delay Dataset','interpreter','latex');
xlabel('Inducing points','interpreter','latex');
ylabel('MSE','interpreter','latex');
set(gca,'XTick',[1 2 3 4]); %%%% HERE
set(gca,'XTickLabel',vars);
xtickangle(45);
The weird behavior is indeed due to the fact that you specify less labels than ticks. So Matlab just repeats them.

Related

Multiple bar charts in one graph in Octave

Using Octave 4.2.1 on Windows with the qt graphics toolkit (I can't use gnuplot because it crashes in some other part of the code). I have a dataset which is 35x7x4 (35 data points for 7 conditions on 4 channels) - you can use random data for the purpose of this exercise.
I am trying to create 4 subplots (1 for each channel), with 7 bar graphs on each subplot (one per condition) to see how the distribution of data changes with each condition. Each of the 7x4 = 28 distributions has its own set of bins and frequencies, and I can't seem to be able to combine the 7 datasets on one graph (subplot).
Posting the whole of the code would be too complicated, but here's a simplified version:
nb_channels = 4;
nb_conditions = 7;
nbins = 15;
freq = zeros(nbins,nb_conditions,nb_channels);
xbin = zeros(nbins,nb_conditions,nb_channels);
plot_colours = [91 237 165 255 68 112 255;
155 125 165 192 114 173 0;
213 49 165 0 196 71 255];
plot_colours = plot_colours / 255;
for k = 1:nb_channels
for n = 1:nb_conditions
% some complex calculations to generate temp variable
[freq(:,n,k),xbin(:,n,k)] = hist(temp,nbins);
end
end
figure
for k = 1:nb_channels
subplot(2,2,k)
for n = 1:nb_conditions
bar(xbin(:,n,k),freq(:,n,k),'FaceColor',plot_colours(:,n))
hold on
end
hold off
legend('condition #1','condition #2','condition #3','condition #4','condition #5','condition #6','condition #7')
end
which gives something like this:
So you can't really see anything, all the bars are on top of each other. In addition, Octave doesn't support transparency property for patch objects (which is what bar charts use), so I can't overlay the histograms on top of each other, which I would really quite like to do.
Is there a better way to approach this? It seems that bar will only accept a vector for x data and not a matrix, so I am stuck in having to use hold on and loop through the various conditions, instead of using a matrix approach.
OK, so I'll try to answer my own question based on the suggestions made in the comments:
Suggestion 1: make all the bins the same
This does improve the results somewhat but it's still an issue due to the lack of transparency for patch objects.
Code changes:
nbins = 15;
xbin = linspace(5.8,6.5,nbins);
for k = 1:nb_channels
for n = 1:nb_conditions
% some complex calculations to generate temp variable
freq_flow(:,n,k) = hist(temp,xbin);
end
end
figure
for k = 1:nb_channels
subplot(2,2,k)
for n = 1:nb_conditions
bar(xbin,freq_flow(:,n,k),'FaceColor',plot_colours(:,n))
hold on
end
hold off
xlim([5.8 6.3])
legend('condition #1','condition #2','condition #3','condition #4','condition #5','condition #6','condition #7')
end
Which gives the following plot:
Suggestion 2: Use line plots instead of bar charts
This helps a bit more in terms of readability. However, the result is a bit "piece-wise".
Code changes:
figure
for k = 1:nb_channels
subplot(2,2,k)
for n = 1:nb_conditions
plot(xbin,freq_flow(:,n,k),'LineStyle','none','marker','.',...
'markersize',12,'MarkerEdgeColor',plot_colours(:,n),...
'MarkerFaceColor',plot_colours(:,n))
hold on
end
hold off
xlim([5.8 6.3])
legend('condition #1','condition #2','condition #3','condition #4','condition #5','condition #6','condition #7')
end
Which gives the following result:
The legend is a bit screwed but I can probably sort that out.
A variation on this I also tried was to plot just the points as markers, and then a fitted normal distribution on top. I won't post all the code here, but the result looks something like this:
Suggestion 3: transparency workaround with gnuplot
Unfortunately, before I even got to the transparency workaround, gnuplot keeps crashing when trying to plot the figure. There's something it doesn't like with subplots and legends I think (which is why I moved to qt graphics toolkit in the first place, as I had exactly the same issue in other parts of the code).
Solution 4: use 3D bar graph
I found this on SO: 3D histogram with gnuplot or octave
and used it as such:
figure
for k = 1:size(flow_factor,2)
subplot(2,2,k)
h = my_bar3(freq_flow(:,:,k));
fvcd = kron((1:numel(freq_flow(:,:,k)))', ones(6,1));
set(h, 'FaceVertexCData',fvcd, 'FaceColor','flat', 'CDataMapping','scaled')
colormap hsv; axis tight; view(50,25)
ylbl = cell(length(xbin),1);
for k=1:length(xbin)
ylb{k} = num2str(xbin(k));
end
set(gca,'YTick',1:2:nbins);
set(gca,'YTickLabel',ylb(1:2:end));
end
to produce:
Which isn't bad, but probably not as clear as the line plots.
Conclusion
On balance, I will probably end up using one of the line plots approaches, as they tend to be clearer.

Matlab: Using "hold on" for histograms results in different bin width

I seem to have the strange problem that when I plot the following, the bars of the two histograms do not seem to have the same width:
hold on
[N,X] = hist(feature_1(:,1))
Bh = bar(X,N,'facecolor',[0.7 0.2 0.2]);
[A,Y] = hist(feature_2(:,1))
Bh = bar(Y,A,'facecolor',[0.3 0.6 0.2]);
hold off
Why is that?
Thanks
Edit: Sorry for not providing input.
For instance, feature_1(:,1:5) =
[0.72507334
0.019627856
0.19571847
-0.23818338
1.6526113
0.23925941
0.69914567
0.15934853
0.28082907
-0.035707321
0.072205774
-0.15791744
0.81654513
0.19398287
-0.33666527
-0.24295111
-1.0770919
-1.2977802
0.67290813
-0.56841594
-0.28522778
-2.2450733
-1.4413888
-2.2216258
-0.46346179
1.8239603
1.6443830
1.3715266
0.34339836
-0.29903534]
and feature_2(:,1) =
[0.18098037
-0.81469119
-0.086869463
-0.67799056
1.1408544
1.2589806
1.0065788
0.64472252
-0.70849174
0.69045025
-0.0031675443
-0.82824785
0.15744546
-0.028384065
-0.065391541
-0.35754660
-1.0809286
-0.12427557
1.3792992
-0.28740802
1.7593855
-1.2061185
-3.0156419
-1.1680259
0.23381938
0.97127295
0.91487378
0.83101124
0.24949571
-0.96599007]
MATLAB suggests you use histogram() instead of hist().
If I had to guess why your bars are of different widths, it would be because you have different numbers of bins for each histogram, though don't take my word for it. (It also could be a stylistic thing, where the bars are offset so that you can see both colors, as hist() does not blend like histogram() does.)
You can solve the width problem by specifying the width using histogram():
histogram(feature_1(:,1:5),'BinWidth',.5);
hold on
histogram(feature_2(:,1),'BinWidth',.5);
If you run this code, you'll be able to see the differences in plotting styles:
subplot(2,1,1)
hold on
[N,X] = hist(feature_1(:,1:5));
Bh = bar(X,N,'facecolor',[0.7 0.2 0.2]);
[A,Y] = hist(feature_2(:,1));
Bh = bar(Y,A,'facecolor',[0.3 0.6 0.2]);
subplot(2,1,2)
histogram(feature_1(:,1:5),'BinWidth',.5,'FaceColor','r');
hold on
histogram(feature_2(:,1),'BinWidth',.5,'FaceColor','g');
Hope this helped somewhat!
I don't get the purpose but width is same for both, the bins are different. If you want to show both in a same figure for comparison purpose, then you must adapt this way
bar([X',Y'])
xlable('-->No of bins')
legend('Feature1','Feature2')

Summing Values based on Area in Matlab

Im trying to write a code in Matlab to calculate an area of influence type question. This is an exert from my data (Weighting, x-coord, y-coord):
M =
15072.00 486.00 -292
13269.00 486.00 -292
12843.00 414.00 -267
10969.00 496.00 -287
9907.00 411.00 -274
9718.00 440.00 -265
9233.00 446.00 -253
9138.00 462.00 -275
8830.00 496.00 -257
8632.00 432.00 -253
R =
-13891.00 452.00 -398
-13471.00 461.00 -356
-12035.00 492.00 -329
-11309.00 413.00 -353
-11079.00 467.00 -375
-10659.00 493.00 -333
-10643.00 495.00 -338
-10121.00 455.00 -346
-9795.00 456.00 -367
-8927.00 485.00 -361
-8765.00 467.00 -351
I want to make a function to calculate the sum of the weightings at any given position based on a circle of influence of 30 for each coordinate.
I have thought of using a for loop to calculate each point independently and summing the result but seems unnecessarily complicated and inefficient.
I also thought of assigning an intensity of color to each circle and overlaying them but I dont know how to change color intensity based on value here is my attempt so far (I would like to have a visual of the result):
function [] = Influence()
M = xlsread('MR.xlsx','A4:C310');
R = xlsread('MR.xlsx','E4:G368');
%these are my values around 300 coordinates
%M are negative values and R positive, I want to see which are dominant in their regions
hold on
scatter(M(:,2),M(:,3),3000,'b','filled')
scatter(R(:,2),R(:,3),3000,'y','filled')
axis([350 650 -450 -200])
hold off
end
%had to use a scalar of 3000 for some reason as it isnt correlated to the graph size
I'd appreciate any ideas/solutions thank you
This is the same but with ca. 2000 data points
How about this:
r_influence = 30; % radius of influence
r = #(p,A) sqrt((p(1)-A(:,2)).^2 + (p(2)-A(:,3)).^2); % distance
wsum = #(p,A) sum(A(find(r(p,A)<=r_influence),1)); % sum where distance less than roi
% compute sum on a grid
xrange = linspace(350,550,201);
yrange = linspace(-200,-450,201);
[XY,YX] = meshgrid(xrange,yrange);
map_M = arrayfun(#(p1,p2) wsum([p1,p2],M),XY,YX);
map_R = arrayfun(#(p1,p2) wsum([p1,p2],R),XY,YX);
figure(1);
clf;
imagesc(xrange,yrange,map_M + map_R);
colorbar;
Gives a picture like this:
Is that what you are looking for?

Animated plot of infectious disease spread with for loop (Matlab)

I'm a beginner in Matlab and I'm trying to model the spread of an infectious disease using Matlab. However, I encounter some problems.
At first, I define the matrices that need to be filled and their initial status:
diseasematrix=zeros(20,20);
inirow=10;
inicol=10;
diseasematrix(inirow,inicol)=1; % The first place where a sick person is
infectionmatrix=zeros(20,20); % Infected people, initially all 0
healthymatrix=round(rand(20,20)*100); % Initial healthy population (randomly)
Rate=0.0001; % Rate of spread
Now, I want to make a plot where the spread of the disease is shown, using a for loop. But i'm stuck here...
for t=1:365
Zneighboursum=zeros(size(diseasematrix));
out_ZT = calc_ZT(Zneighboursum, diseasematrix);
infectionmatrix(t) = round((Rate).*(out_ZT));
diseasematrix(t) = diseasematrix(t-1) + infectionmatrix(t-1);
healthymatrix(t) = healthymatrix(t-1) - infectionmatrix(t-1);
imagesc(diseasematrix(t));
title(sprintf('Day %i',t));
drawnow;
end
This basically says that the infectionmatrix is calculated based upon the formula in the loop, the diseasematrix is calculated by adding up the sick people of the previous timestep with the infected people of the previous time. The healthy people that remain are calculated by substracting the healthy people of the previous time step with the infected people. The variable out_ZT is a function I made:
function [ZT] = calc_ZT(Zneighboursum, diseasematrix)
Zneighboursum = Zneighboursum + circshift(diseasematrix,[1 0]);
Zneighboursum = Zneighboursum + circshift(diseasematrix,[0 1]);
ZT=Zneighboursum;
end
This is to quantify the number of sick people around a central cell.
However, the result is not what I want. The plot does not evolve dynamically and the values don't seem to be right. Can anyone help me?
Thanks in advance!
There are several problems with the code:
(Rate).*(out_ZT) is wrong. Because first one is a scalar and
second is a matrix, while .* requires both to be matrices of the
same size. so a single * would work.
The infectionmatrix,
diseasematrix, healthymatrix are all 2 dimensional matrices and
in order to keep them in memory you need to have a 3 dimensional
matrix. But since you don't use the things you store later you can
just rewrite on the old one.
You store integers in the
infectionmatrix, because you calculate it with round(). That
sets the result always to zero.
The value for Rate was too low to see any result. So I increased it to 0.01 instead
(just a cautionary point) you haven't used healthymatrix in your code anywhere.
The code for the function is fine, so after debugging according to what I perceived, here's the code:
diseasematrix=zeros(20,20);
inirow=10;
inicol=10;
diseasematrix(inirow,inicol)=1; % The first place where a sick person is
infectionmatrix=zeros(20,20); % Infected people, initially all 0
healthymatrix=round(rand(20,20)*100); % Initial healthy population (randomly)
Rate=0.01;
for t=1:365
Zneighboursum=zeros(size(diseasematrix));
out_ZT = calc_ZT(Zneighboursum, diseasematrix);
infectionmatrix = (Rate*out_ZT);
diseasematrix = diseasematrix + infectionmatrix;
healthymatrix = healthymatrix - infectionmatrix;
imagesc(diseasematrix);
title(sprintf('Day %i',t));
drawnow;
end
There is several problems:
1) If you want to save a 3D matrix you will need a 3D vector:
so you have to replace myvariable(t) by myvariable(:,:,t);
2) Why did you use round ? if you round a value < 0.5 the result will be 0. So nothing will change in your loop.
3) You need to define the boundary condition (t=1) and then start your loop with t = 2.
diseasematrix=zeros(20,20);
inirow=10;
inicol=10;
diseasematrix(inirow,inicol)=1; % The first place where a sick person is
infectionmatrix =zeros(20,20); % Infected people, initially all 0
healthymatrix=round(rand(20,20)*100); % Initial healthy population (randomly)
Rate=0.01; % Rate of spread
for t=2:365
Zneighboursum=zeros(size(diseasematrix,1),size(diseasematrix,2));
out_ZT = calc_ZT(Zneighboursum, diseasematrix(:,:,t-1));
infectionmatrix(:,:,t) = (Rate).*(out_ZT);
diseasematrix(:,:,t) = diseasematrix(:,:,t-1) + infectionmatrix(:,:,t-1);
healthymatrix(:,:,t) = healthymatrix(:,:,t-1) - infectionmatrix(:,:,t-1);
imagesc(diseasematrix(:,:,t));
title(sprintf('Day %i',t));
drawnow;
end
IMPORTANT: circshift clone your matrix in order to deal with the boundary effect.

How to set number of ticks along X axis in matlab?

I'm having trouble setting the appropriate number of ticks along the Xaxis in Matlab. As you can see below, I set the number to 2 in ha.XTicksNumber=2, yet it still plots 10.
nSites = 2;
ha = tight_subplot(nSites,1,[.01 .01],[.1 .1],[.1 .1]);
display(ha);
for ii = 1:nSites;
axes(ha(ii));
xData=linspace(1,100,90);
plot(xData);
if ii~=nSites
set(ha,'XTickLabel','');
else
set(ha,'XTickLabel','');
ha.XTicksNumber=2;
ha.XTick = linspace(1,90,55);
datetick('x','mm/dd','keepticks');
end
end
The above code is reproducible. Thanks for any help!
What I want in the end is an x axis with dates, but I want to be able to either
1) set the number of dates along the x axis
OR
2) set the interval between any two dates.
Anyone know how to do this?
Try this out
NumTicks = 4;
L = get(gca,'XLim');
set(gca,'XTick',linspace(L(1),L(2),NumTicks))
You can easily wrap it in a function if you like.