Changing axes ticks in contourf (MatLab) - 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?

Related

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?

plot interpolate a curve between 2 different types of curves in matlab

I have the following data that predicts a curve in the middle of the two curves which has different equation and datas.I also need to spline and smothen the curve of the middle curve
I've tried searching other codes here in stackoverflow but this is the most close to the right solution. So far the plot for the two curve is right but the interpolated point gives me wrong plot.
Im trying to find the plot for val=30 given that (a25,vel25)=25 and (a50,vel50)=50. Please help me troubleshoot and get a table of data (x,y) for the generated interpolated curve. Thanks for your help
generated plot using this program
a50=[1.05
0.931818182
0.931818182
0.968181818
1.045454545
1.136363636
1.354545455
1.568181818
1.718181818
1.945454545
2.159090909
2.454545455
2.772727273
];
vel50=[0.85
0.705555556
0.605555556
0.533333333
0.472222222
0.45
0.427777778
0.45
0.477777778
0.533333333
0.611111111
0.711111111
0.827777778
];
a25=[0.5
0.613636364
0.686363636
0.795454545
0.918181818
0.963636364
1.090909091
1.236363636
1.304545455
1.431818182
1.545454545
1.659090909
1.818181818
];
vel25=[0.425555556
0.354444444
0.302222222
0.266666667
0.233333333
0.226666667
0.211111111
0.222222222
0.237777778
0.266666667
0.311111111
0.35
0.402222222
];
plot(a25,vel25,'b-');
hold on
plot(a50,vel50,'g-');
minX = min([a25 a50]);
maxX = max([a25,a50]);
xx = linspace(minX,maxX,100);
vel25_inter = interp1(a25,vel25,xx);
vel50_inter = interp1(a50,vel50,xx);
val = 30; % The interpolated point
interpVel = vel25_inter + ((val-25).*(vel50_inter-vel25_inter))./(50-25);
plot(xx,interpVel,'r-');
The question and answer linked in comment still apply and can be a solution.
In your case, it is not so direct because your data are not on the same grid and some are not monotonic, but once they are packaged properly, the easiest solution is still to use griddata.
By packaged properly, I mean finding the maximum common interval (on x, or what you call a), so the data can be interpolated between curve without producing NaNs.
This seems to work:
The red dashed line is the values interpolated at val=30, all the other lines are interpolations for values between 25 to 50.
The code to get there:
% back up original data, just for final plot
bkp_a50 = a50 ; bkp_vel50 = vel50 ;
% make second x vector monotonic
istart = find( diff(a50)>0 , 1 , 'first') ;
a50(1:istart-1) = [] ;
vel50(1:istart-1) = [] ;
% prepare a 3rd dimension vector (from 25 to 50)
T = [repmat(25,size(a25)) ; repmat(50,size(a50)) ] ;
% merge all observations together
A = [ a25 ; a50] ;
V = [vel25 ; vel50] ;
% find the minimum domain on which data can be interpolated
% (anything outside of that will return NaN)
Astart = max( [min(a25) min(a50)] ) ;
Astop = min( [max(a25) max(a50)] ) ;
% use the function 'griddata'
[TI,AI] = meshgrid( 25:50 , linspace(Astart,Astop,10) ) ;
VI = griddata(T,A,V,TI,AI) ;
% plot all the intermediate curves
plot(AI,VI)
hold on
% the original curves
plot(a25,vel25,'--k','linewidth',2)
plot(bkp_a50,bkp_vel50,'--k','linewidth',2)
% Highlight the curve at T = 30 ;
c30 = find( TI(1,:) == 30 ) ;
plot(AI(:,c30),VI(:,c30),'--r','linewidth',2)
There were quite a few issues with your code that's why it was not executing properly. I have just made very little changes to your code and made it running,
clc
%13
a50=[1.05
0.931818182
0.932
0.968181818
1.045454545
1.136363636
1.354545455
1.568181818
1.718181818
1.945454545
2.159090909
2.454545455
2.772727273
];
%13
vel50=[0.85
0.705555556
0.605555556
0.533333333
0.472222222
0.45
0.427777778
0.45
0.477777778
0.533333333
0.611111111
0.711111111
0.827777778
];
%13
a25=[0.5
0.613636364
0.686363636
0.795454545
0.918181818
0.963636364
1.090909091
1.236363636
1.304545455
1.431818182
1.545454545
1.659090909
1.818181818
];
%13
vel25=[0.425555556
0.354444444
0.302222222
0.266666667
0.233333333
0.226666667
0.211111111
0.222222222
0.237777778
0.266666667
0.311111111
0.35
0.402222222
];
plot(a25,vel25,'b-');
hold on
plot(a50,vel50,'g-');
minX = min([a25 a50])
maxX = max([a25 a50])
%xx = linspace(minX,maxX);
xx = linspace(0.5,2.7727,100);
vel25_inter = interp1(a25,vel25,xx);
vel50_inter = interp1(a50,vel50,xx);
val = 30; % The interpolated point
interpVel = vel25_inter + ((val-25).*(vel50_inter-vel25_inter))./(50-25);
plot(xx,interpVel,'r-');
There issues were
The interval on which you wanted to interpolate is xx = linspace(minX,maxX); but it gives an error of the type,
Matrix dimensions must agree.
Because you were assigning two values for the starting point and two for the ending point. So I replace it with xx = linspace(0.5,2.7727,100); where the starting point is being the minimum of the two minimum minX and the same for maxX
There are values of a50 (0.931818182) that repeat which was producing the following error
The grid vectors are not strictly monotonic increasing.
I change one of the value and replaced it with 0.932
The output is not that promising but is suppose the one you want?

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.