How to set number of ticks along X axis in matlab? - 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.

Related

Changing axes ticks in contourf (MatLab)

I've got the following code, which produces the graph below. Unfortunately, I can't share the data for this one.
time=data.time();
tim=find(time>0.0 & time<1.4)
time(tim)
pow=mean(data.powspctrm,1);
pow=squeeze(pow);
pow(isnan(pow))=0;
pow2=pow(:,:);
Min = min(pow,[],'omitnan');
Min=min(Min);
Max = max(pow,[],'omitnan');
Max=max(Max);
contourf(time(tim),data.freq,pow2(:,tim),40,'linecolor','none');caxis([Min Max]);
colbar = colorbar
caxis([-.31 .31])
colbar.TickLabels = -30:10:30
xtickvec = -0.1:0.2:1.3
set(gca,'XTick',xtickvec)
I've been trying to change the y axis ticks to go until 30 the same way as I did for the x axis with ytickvec = 5:5:30 then set(gca,'YTick',ytickvec) but it does nothing. Any suggestions?

Trying to apply a color map to a bar graph in MATLAB

I have a collection of data that I am trying to graph as a histogram. Additionally, I would like to color the individual bars as a function of the x axis location. CData, described here seems to do what I want but I can't get it to work.
Here is my code:
h = bar(new_edge,N,'hist','FaceColor','flat');
hold on
for n = 1:length(N)
if (x - x/1.09) - (x-1) > 0
probability(n) = 1 - ((x-x/1.09) - (x-1))/((x - 1/1.09)+(x/0.91 - x));
else
probability(n) = 1;
end
color_num = 30;
cm = jet(color_num);
min = 0.5450;
max = 1;
color_map_index = floor(1 + (probability(n) - min)/(max-min)*(color_num-1));
rbg = cm(color_map_index,:);
h.CData(n,:) = rbg;
end
Similar to the MATLAB example, I first create my bar graph. Next, I want to loop through and prescribe the color for each bar based on a calculation. I do this by creating a colormap with # of bins and a min/max, getting a color index, then finally retrieving the rbg value. I get the following error when I try to apply the color:
Subscript indices must either be real positive integers or logicals.
h.CData(n,:) = rbg;
If I dive into the h object, MATLAB tells me that CData has a size of (4x65). What's going on here? Both new_edge and N are 1x65 vectors.
Are you certain that the error you're getting ("Subscript indices must either be real positive integers or logicals") is coming from the following line?:
h.CData(n,:) = rbg;
Since we know n is a positive integer greater than or equal to one, the indexing here shouldn't have a problem. It's more likely that your error is coming from the line above it (i.e. the value for color_map_index is less than 1). I would double-check how you are computing color_map_index.
You could also try using function notation (i.e. get and set) instead of dot notation to update the property:
cData = get(h, 'CData');
cData(n, :) = rbg;
set(h, 'CData', cData);
Incidentally, you should also not be giving your variables the same name as existing functions, like you are doing here:
...
min = 0.5450;
max = 1;
...
This shadows the built-in min and max functions, which can also lead to the same error message under other conditions. Definitely rename those.
If you are still having trouble after trying those fixes, you could try setting the color using indexed color mapping instead, as illustrated in one of my other answers (near the bottom). As a simple example, the following plots 20 bars of 30 different possible values, then colors them based on their height:
color_num = 30;
N = randi(color_num, 1, 20);
hBar = bar(N, 'hist');
colormap(parula(color_num));
set(hBar, 'CData', N, 'CDataMapping', 'direct');
And the plot:
This could be a problem with your Matlab version.
When I test CData with bar on 2017b, this works:
openExample('graphics/ControlIndividualBarColorsExample')
When I try it on 2017a, it doesn't run.
Does the example work?
Given that this is a version control problem, there's really not a clean solution. In case anyone else comes along with a similar question and has the same version, here's a workaround that worked for me in 2017a.
Rather than creating a bar chart, you can simply draw rectangles. It's messy, but it does produce the desired result.
[N,edges] = histcounts(AB(AB<2));
probability = zeros(1,length(N));
new_edge = zeros(1,length(N));
for m = 1:length(N)
new_edge(m) = (edges(m) + edges(m+1))/2;
end
figure
hold on
for n = 1:length(N)
x = new_edge(n);
if ((x - x/1.09) - (x-1)) > 0
probability(n) = 1 - ((x-x/1.09) - (x-1))./((x - x/1.09)+(x/0.91 - x));
else
probability(n) = 1;
end
color_num = 100;
cm = jet(color_num);
min = 0;
max = 1;
color_map_index(n) = floor(1 + (probability(n) - min)/(max-min)*(color_num-1));
rbg = cm(color_map_index(n),:);
rectangle('Position',[edges(n),0,(edges(n+1)-edges(n)),N(n)],'Edgecolor','k','FaceColor',rbg)
end
set(gcf,'color','w');
blah = colorbar;

Wrong tick location when I set the x-axis labels manually in 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.

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?

Reverse-calculating original data from a known moving average

I'm trying to estimate the (unknown) original datapoints that went into calculating a (known) moving average. However, I do know some of the original datapoints, and I'm not sure how to use that information.
I am using the method given in the answers here: https://stats.stackexchange.com/questions/67907/extract-data-points-from-moving-average, but in MATLAB (my code below). This method works quite well for large numbers of data points (>1000), but less well with fewer data points, as you'd expect.
window = 3;
datapoints = 150;
data = 3*rand(1,datapoints)+50;
moving_averages = [];
for i = window:size(data,2)
moving_averages(i) = mean(data(i+1-window:i));
end
length = size(moving_averages,2)+(window-1);
a = (tril(ones(length,length),window-1) - tril(ones(length,length),-1))/window;
a = a(1:length-(window-1),:);
ai = pinv(a);
daily = mtimes(ai,moving_averages');
x = 1:size(data,2);
figure(1)
hold on
plot(x,data,'Color','b');
plot(x(window:end),moving_averages(window:end),'Linewidth',2,'Color','r');
plot(x,daily(window:end),'Color','g');
hold off
axis([0 size(x,2) min(daily(window:end))-1 max(daily(window:end))+1])
legend('original data','moving average','back-calculated')
Now, say I know a smattering of the original data points. I'm having trouble figuring how might I use that information to more accurately calculate the rest. Thank you for any assistance.
You should be able to calculate the original data exactly if you at any time can exactly determine one window's worth of data, i.e. in this case n-1 samples in a window of length n. (In your case) if you know A,B and (A+B+C)/3, you can solve now and know C. Now when you have (B+C+D)/3 (your moving average) you can exactly solve for D. Rinse and repeat. This logic works going backwards too.
Here is an example with the same idea:
% the actual vector of values
a = cumsum(rand(150,1) - 0.5);
% compute moving average
win = 3; % sliding window length
idx = hankel(1:win, win:numel(a));
m = mean(a(idx));
% coefficient matrix: m(i) = sum(a(i:i+win-1))/win
A = repmat([ones(1,win) zeros(1,numel(a)-win)], numel(a)-win+1, 1);
for i=2:size(A,1)
A(i,:) = circshift(A(i-1,:), [0 1]);
end
A = A / win;
% solve linear system
%x = A \ m(:);
x = pinv(A) * m(:);
% plot and compare
subplot(211), plot(1:numel(a),a, 1:numel(m),m)
legend({'original','moving average'})
title(sprintf('length = %d, window = %d',numel(a),win))
subplot(212), plot(1:numel(a),a, 1:numel(a),x)
legend({'original','reconstructed'})
title(sprintf('error = %f',norm(x(:)-a(:))))
You can see the reconstruction error is very small, even using the data sizes in your example (150 samples with a 3-samples moving average).