I am trying to fit my data to match the published map below (the figure on the left), but cannot figure out the right code for the colour bar. The increments are non linear.
Here is the relevant code that I have (it is part of a very large code for spatial mapping so unfortunately not possible to make it reproducible):
caxes.donatt = [0 2.5];
colormaps.donat = mf_colormap_cpt('BlWhRe', 8);
colormaps.donat(1:1,:) = [0.00 0.00 0.50];
colormaps.donat(2:2,:) = [0.00 0.50 1.00];
colormaps.donat(3:3,:) = [0.67 0.90 0.93];
colormaps.donat(4:4,:) = [1.00 1.00 1.00];
colormaps.donat(5:5,:) = [1.00 0.87 0.68];
colormaps.donat(6:6,:) = [0.98 0.67 0.38];
colormaps.donat(7:7,:) = [1.00 0.40 0.10];
colormaps.donat(8:8,:) = [1.00 0.00 0.00];
Here is a picture of the expected result of the colorbar:
expected result
Here is my current result using the code shown above:
current colorbar result
The problem here is that the colormap you're trying to mimic is non-linear, but MATLAB maps the data to a colormap in a linear fashion. You can solve this by first binning your data using histcounts to create a linear mapping, then adjusting the color bar ticks labels to make your linear colormap appear non-linear. Here's an example:
data = 2.5.*rand(200); % Sample random data in the range [0 2.5]
edges = [0 0.5 0.75 0.9 1.1 1.25 1.5 2 2.5]; % Define edges of nonlinear map
imgMap = [0.00 0.00 0.50; ... % Colormap colors
0.00 0.50 1.00; ...
0.67 0.90 0.93; ...
1.00 1.00 1.00; ...
1.00 0.87 0.68; ...
0.98 0.67 0.38; ...
1.00 0.40 0.10; ...
1.00 0.00 0.00];
[~, ~, bin] = histcounts(data, edges); % Bin the data according to the edges
image(bin); % Plot bin index, not the original data
colormap(imgMap); % Add new colormap
hBar = colorbar; % Add color bar
set(hBar, 'TickLabels', ... % Modify color bar tick labels
[{''}; cellstr(num2str(edges(2:(end-1)).', '%g')); {''}]);
And here's the sample plot:
Note that if your data contains NaN values, you will get a bin value of 0, which in the above example will be mapped to the lowest value in the colormap range (which is the first element of imgMap). To reconstitute these NaN values, do the following after binning the data with histcounts:
bin(bin == 0) = nan;
Related
How can I resample my [t x] matrix and fill the gap of resampled data with interpolation data in Matlab?
Input is the upper signal output is lower signal in the image.The output should be [tout xout] with similar dimensions to [t x]. The middle points of resampled data should be interpolated.
Here is a visualisation of my desired output:
t = [0.2 0.25 0.3 0.35 0.4 0.45 0.5] % Original Time Vector
x = [1 2 2.5 2.4 3 2 1] % Original Data Vector
L = length(t);
tv = linspace(min(t), max(t), L); % Time Vector For Interpolation
dv = interp1(t, x, tv, 'linear'); % Interpolated Data Vector
Ts = mean(diff(tv));
I have the following code for a plot with 2 y-axes in MATLAB. I am glad that the 2-axes feature works, however, I would like to avoid the overlapping of the bars. Also, the categories on the right-hand axis should have different colors, not only yellow, yet it should be somehow clear that they are plotted on the right-hand axis and not the left one. How can this be done?
EONMW = [100 399 500];
RWEMW = [200 996 120];
GermanByEON = [0.2 0.4 0.5];
GermanByRWE = [0.1 0.5 0.9];
EONGermanPortfolio = [0.7 0.2 0.1];
RWEGermanPortfolio = [0.8 0.3 0.6];
years = [2010 2012 2014];
% Plot
values1 = [EONMW; RWEMW]';
values2 = [GermanByEON; GermanByRWE; EONGermanPortfolio; RWEGermanPortfolio]';
years1 = [years; years]';
years2 = [years; years; years; years]';
figure;
bar(years1,values1);
ylabel('Utilities generation portfolio in MW')
yyaxis right
bar(years2,values2);
legend('EON German portfolio in MW', 'RWE German portfolio in MW',...
'Percentage of German portfolio by EON', 'Percentage of German portfolio by RWE',...
'EON"s percentage of generation in Germany', 'RWE"s percentage of generation in Germany')
legend('Location','northwest')
ylabel('Utilities generation portfolio as percentages')
I agree that it is somewhat difficult to read this sort of plot, but perhaps there's a way to improve the situation a little.
The main thing I changed was adding invisible bars (using NaN) so that the color order remains intact:
function q54071610
EONMW = [100 399 500];
RWEMW = [200 996 120];
GermanByEON = [0.2 0.4 0.5];
GermanByRWE = [0.1 0.5 0.9];
EONGermanPortfolio = [0.7 0.2 0.1];
RWEGermanPortfolio = [0.8 0.3 0.6];
years = [2010 2012 2014];
% Plot
values1 = [[EONMW; RWEMW].' NaN(3,4)];
values2 = [NaN(3,2) [GermanByEON; GermanByRWE; EONGermanPortfolio; RWEGermanPortfolio].'];
years1 = repmat(years.', [1,6]);
figure;
bar(years1,values1, 'EdgeColor', 'b', 'LineWidth', 2);
ylabel('Utilities generation portfolio in MW')
yyaxis right
hB = bar(years1,values2, 'EdgeColor', 'r', 'LineWidth', 2);
c = lines(6);
for ind1 = 1:6
hB(ind1).FaceColor = c(ind1, :);
end
legend('EON German portfolio in MW', 'RWE German portfolio in MW',...
'Percentage of German portfolio by EON', 'Percentage of German portfolio by RWE',...
'EON"s percentage of generation in Germany', 'RWE"s percentage of generation in Germany')
legend('Location','northwest')
ylabel('Utilities generation portfolio as percentages')
Which results in:
Now you should explain that red-framed bars belong to the right axis whereas blue-framed bars belong to the left.
I'm not sure what exactly these bars mean, and so I may have missed the point of the figure (which could be the main problem here). However, I find this way of presentation not pleasing and misleading, as it takes a lot of effort from the reader to understand which value belongs to which bar, and what is comparable and what's not.
What I suggest here, is not a direct answer to the technical problem (which you have already got from #Dev-iL), but a different solution for the more basic problem - how to visualize these data? I believe that if I'll understand what the numbers represent (percentage from what?) and what you want to emphasize with this plot, I can find a better solution.
First, the code:
EONMW = [100 399 500];
RWEMW = [200 996 120];
GermanByEON = [0.2 0.4 0.5];
GermanByRWE = [0.1 0.5 0.9];
EONGermanPortfolio = [0.7 0.2 0.1];
RWEGermanPortfolio = [0.8 0.3 0.6];
years = [2010 2012 2014].';
values1 = [EONMW; RWEMW].';
values2 = [GermanByEON; GermanByRWE; EONGermanPortfolio; RWEGermanPortfolio].'*100;
% Plot
colMap = mat2cell(lines(2),[1 1],3); % Choose your favorite colors
figure(2);
% upper plot:
subplot 211
b = bar(years,values1);
set(b,{'FaceColor'},colMap)
xticklabels({}) % remove the years labels, the bottom axes will show them
ylabel('Utilities generation portfolio in MW')
legend('EON German', 'RWE German',...
'Location','northwest')
% bottom plot
subplot 212
b = bar(years,values2);
set(b,{'FaceColor'},repmat(colMap,2,1)) % matching the colors by topic
set(b,{'FaceAlpha'},{1;1;0.6;0.6}) % distiguish between related mesures
xlabel('Year')
ylabel('Utilities generation portfolio (%)')
legend('German portfolio by EON', 'German portfolio by RWE',...
'EON''s generation in Germany', 'RWE''s generation in Germany',...
'Location','north')
The result:
The major things I changed:
Split the bars by the units of the y-axis, but align them by the x-axis
Match the colors of related bars between the plots
Shorten legends and labels
Good luck!
It is best if you define bar(x,y) as b=bar(x,y) then control the options of b one of such is b.FaceColor. Take a look at the following code
EONMW = [100 399 500];
RWEMW = [200 996 120];
GermanByEON = [0.2 0.4 0.5];
GermanByRWE = [0.1 0.5 0.9];
EONGermanPortfolio = [0.7 0.2 0.1];
RWEGermanPortfolio = [0.8 0.3 0.6];
years = [2010 2012 2014];
x=0.2;
% Plot
values1 = [EONMW; RWEMW]';
values2 = [GermanByEON; GermanByRWE; EONGermanPortfolio; RWEGermanPortfolio]';
years1 = [years; years]';
years2 = [years; years; years; years]';
figure;
b1=bar(years1,values1,x*0.66);
ylabel('Utilities generation portfolio in MW')
yyaxis right
b2=bar(years2,values2,x);
%%%%%%%%%%%%
%%%%%%%%%%%%
%% Defining colors
b1(1).FaceColor=[1 0 0];
b1(2).FaceColor=[0 1 0];
b2(1).FaceColor=[0 0 1];
b2(2).FaceColor=[1 1 0];
b2(3).FaceColor=[0 1 1];
b2(4).FaceColor=[1 0 1];
%%%%%%%%%%%%
%%%%%%%%%%%%
%%
legend('EON German portfolio in MW', 'RWE German portfolio in MW',...
'Percentage of German portfolio by EON', 'Percentage of German portfolio by RWE',...
'EON"s percentage of generation in Germany', 'RWE"s percentage of generation in Germany')
legend('Location','northwest')
ylabel('Utilities generation portfolio as percentages')
which is your code plus the following block
%%%%%%%%%%%%
%%%%%%%%%%%%
%% Defining colors
b1(1).FaceColor=[1 0 0];
b1(2).FaceColor=[0 1 0];
b2(1).FaceColor=[0 0 1];
b2(2).FaceColor=[1 1 0];
b2(3).FaceColor=[0 1 1];
b2(4).FaceColor=[1 0 1];
%%%%%%%%%%%%
%%%%%%%%%%%%
%%
and the result is as follows
also a trigger option x has been added to control bar width.
I had to plot this in matlab :
so I wrote the following code:
x=[0.9 1 0.9 -0.9 0.7 0.7 -0.9 0.9];
y=[-1 0 1 -0.5 -0.8 0.8 -0.4 -1];
plot(x,y);
but this gives me:
Is this method insufficient to draw the first figure....Is there some other short method for this...
You can do better positioning your data points
nPoints = 7;
th = linspace(-2*pi, 2*pi, 2*nPoints+1);%// extra point to close the curve
r = 1;
x = r*cos(th);
y = r*sin(th);
scatter( x, y, 'ro' );
hold on;
plot( x(1:2:end), y(1:2:end), 'b-' );
axis equal;
Resulting with:
BTW, this code works for any odd nPoints - just try ;)
It seems to me that you want to construct a star polygon, which has the property that all points are equidistant to its neighboring points, and all points lie on the same circle.
First, we generate the desired angles a (measured from the x-axis to a line that connects the origin with the desired point, see wikipedia). Based on the polygon, we rearrage the angles in such a way that a desired number of points is skipped (in the code below, this is done by using among others repmat - but many alternatives exist).
To convert the angles to actual points in the plane, we take sine and cosine values, and then we can plot the dots and lines. Putting this together results in the following code, which results in the dersired figure
n = 7;
a = linspace(0,2*pi,n+1);
skip = 1;
b = [repmat(a(1:end-1),1,skip+1) a(end)];
a = b(1:skip+1:end);
figure;
clf;
hold on;
plot(cos(a),sin(a),'b-');
plot(cos(a(1:end-1)),sin(a(1:end-1)),'ro');
axis([-1 1 -1 1])
axis equal
A little less involved would be to compute the vector a like this:
a = mod(linspace(0,(skip+1)*2*pi,n+1),(skip+1)*2*pi);
I tried manually:
x = [-0.4 0.6 1 0.6 -0.4 -0.8 -0.8];
y = [-0.9 -0.7 0 0.7 0.9 0.4 -0.4];
x_ = [x,x];
y_ = [y,y];
figure;
hold on;
for ii=1:numel(x),
scatter(x(ii),y(ii),'ro');
plot([x_(ii),x_(ii+1+1)],[y_(ii),y_(ii+1+1)],'b-');
end
axis([-1 1 -1 1]);
And I get his:
I come across a strange scaling in y- axis in a IEEE journal paper.
From top to bottom
y_axis = [0.9999 0.9995 0.999 0.995 0.99 0.98 0.95 0.9 0.8 0.7 0.5 0.3 0.2 0.1 0.05 0.02 0.01 0.005 0.001 0.0005 0.0001].
The scaling is not logaritmic. The space between the ticks are not equal. Definitely, it is not linear. You can see the big numbers (0.9... 0.999) and very small numbers(0.0001... 0.1) in detail in only one y-axis. I don't know how to do in MATLAB. I googled it, but i could not find. Can anyone help me? Thanks in advance.
The figure is the following code:
clear all
close all
set(0,'defaulttextinterpreter','latex')
P_tb = 1e-2;
Ntrial = 1e7; % # of Monte Carlo trials
jey=sqrt(-1);
omega_db = -15; % sidelobe gain of main antenna
omega = db2pow(omega_db); % omega in linear scale
F_db = [-5 -2 0 2 5];
JNR_db = -5:20;
beta_db = 2;
F_lin = 10.^(0.1*F_db);
JNR = 10.^(0.1*JNR_db);
beta = 10.^(0.1*beta_db);
temp = cell (length(F_db),1);
P_b = zeros (length(JNR_db), length(F_db));
for ii = 1:length(F_db)
SNR = JNR;
x = sqrt(omega);
F = F_lin(ii);
P_b(:,ii) = 1 - 1./(F+1).*(1-marcumq(x.*sqrt(2.*SNR./(F+1)),sqrt(2.*SNR.*F./(F+1))))-F./(F+1).*marcumq(sqrt(2.*SNR.*F./(F+1)), x.*sqrt(2.*SNR./(F+1)));
temp (ii) = {['$F=$' num2str(F_db(ii)) ' dB']};
end
figure,
h = plot(JNR_db, (P_b));
set(gca,'YTick',fliplr([0.9999 0.9995 0.999 0.995 0.99 0.98 0.95 0.9 0.8 0.7 0.5 0.3 0.2 0.1 0.05 0.02 0.01 0.005 0.001 0.0005 0.0001]))
set(gca,'YTickLabel',num2cell(fliplr([0.9999 0.9995 0.999 0.995 0.99 0.98 0.95 0.9 0.8 0.7 0.5 0.3 0.2 0.1 0.05 0.02 0.01 0.005 0.001 0.0005 0.0001])));
grid on
In the figure posted by the OP, the tickmarks are not at all equally distributed. Also, the scale of the axis is rather the inverse of sigmoidal (see below). To really see what the authors of that paper did, we can skeletonize the figure
im = conv2(im, fspecial('gaussian', [5, 5], 2));
im = ~bwmorph(im < 2.5, 'skel', inf);
and obtain the exact positions y_px as in
y_px = flipud(find(im(:, 285) == 0));
y_px([1, 2, 3, 11, 15, 19, 28]) = [];
I am removing some of the detections which are from the trendlines or from the -10 tick mark label of the x-axis.
If you plot the y-tick labels y_val (flipping your y_axis into ascending order) as a function of those pixel positions y_px, you can confirm that the relationship is exactly sigmoidal as suggested by #chapjc. However, in order to produce similar plots, you may rather want to invert the formula and define a function
px_y = #(y) log(-y ./ (y - 1));
You can use this function then for plotting. The paper you refer to shows data in a range x = -10 : 0.1 : 4. Let's plot in this same range a sine function somewhere between 0.0001 and 0.9999. Note that we use our scaling function px_y, and then replace the y-tick positions and labels
plot(x, px_y(0.7 + sin(x) / 4));
set(gca(), 'ytick', px_y(y_val), 'yticklabel', num2cell(y_val));
resulting in something that should look like this
In summary, you can define a function y_px to transform your y-data, and then set the ytick and yticklabel properties of your axes. Whatever scale you choose for this approach, it is important to transform both the ytick values and all y-data with the same function.
Try this:
set(gca,'YTick',fliplr([0.9999 0.9995 0.999 0.995 0.99 0.98 0.95 0.9 0.8 0.7 0.5 0.3 0.2 0.1 0.05 0.02 0.01 0.005 0.001 0.0005 0.0001]));
set(gca,'YTickLabel',num2cell(fliplr([0.9999 0.9995 0.999 0.995 0.99 0.98 0.95 0.9 0.8 0.7 0.5 0.3 0.2 0.1 0.05 0.02 0.01 0.005 0.001 0.0005 0.0001])));
Matlab wants the numbers to be in increasing order, so instead of reordering your numbers, I just invoked fliplr instead.
To get an idea of this custom y-axis space, you can do plot(linspace(-5,5,numel(y_axis)),fliplr(y_axis),'r'). This looked a lot like a dose curve, so plot an equation I found with hold on; x=-5:0.01:5; plot(x,exp(x)./(1+exp(x))). Here's what it looks like:
The form looks right. There is probably a constant on one of the terms to tweak the shape. If you want to put your data in this space, apply this function (yscFun = #(x) exp(x)./(1+exp(x)) or yscFun = #(x) 1./(1+exp(-x))). Then set the tick labels to y_axis with set(gca,'YTickLabel',num2cell(fliplr(y_axis))); as suggested by nispio.
This is the final solution that I found. Thank you very much. I did not know the sigmoid function. Below are the MATLAB codes for this puporse.
close all
clear all
%your desired y_ticks
y_axis = [0.9999 0.9995 0.999 0.995 0.99 0.98 0.95 0.9 0.8 0.7 0.5 0.3 0.2 0.1 0.05 0.02 0.01 0.005 0.001 0.0005 0.0001];
%order in increasing way
y_val = fliplr (y_axis);
% the Sigmoid function and its inverse
py_x = #(x) 0.5*erf(x*sqrt(pi/8)) + 0.5;
px_y = #(x) sqrt (8/pi)*erfinv (2*x - 1);
beta = 10^(0.1*-15);
F = 10^(0.1*-5);
JNR_db = -5:20;
SNR = 10.^(0.1.*JNR_db);
% my original data
P_b = # (x) 1 - 1./(F+1).*(1-marcumq(x.*sqrt(2.*SNR./(F+1)),sqrt(2.*SNR.*F./(F+1))))-F./(F+1).*marcumq(sqrt(2.*SNR.*F./(F+1)), x.*sqrt(2.*SNR./(F+1)));
P_b1 = P_b(sqrt(beta));
% tranfrom it using inverse function
P_b2 = px_y(P_b1);
figure,
plot(JNR_db, P_b2);
grid on
ylim ([ px_y(0.0001) px_y(0.9999) ]);
% tranform the desired y_tick using inverse function
set(gca(), 'ytick', px_y (y_val));
set (gca (), 'yticklabel', num2cell(y_val));
% % Sigmoid function verification
x_temp = linspace(-5,5,numel(y_axis));
figure
plot(x_temp, fliplr(y_axis), 'r');
hold on
plot (x_temp, py_x (x_temp), 'b' )
I have 2 vectors, X and Y, corresponding to a list of unordered coordinates, and a corresponding concentration vector C for each point.
I'd like to plot this on a structured grid as a 2D contour plot.
scatter3(X,Y,C,[],C);
gives me what I want visually, but I'm looking for 2D contours, i.e. pcolor. Is there an easy solution like griddata or trigriddata?
EDIT: Ok, so `scatter3(X,Y,C,[],C); view([0 90])ยด is the correct visual.
TriScatteredInterp works nicely for a rectangle. But what about an irregular shape like a map? :=)
F = TriScatteredInterp(x,y,C);
ty=0:0.005:0.284;
tx=0:0.005:0.65;
[qx,qy] = meshgrid(tx,ty);
qC = F(qx,qy);
pcolor(qx,qy,qC);
EXAMPLE: (X=width coordinate , Y= height coordinate, C= concentration of pollutant)
X Y C
0.1 0.0 5
0.1 0.1 10
0.1 0.21 5
0.2 0.1 4
0.2 0.3 1
0.2 0.5 2
0.2 0.51 7
0.3 0.15 4
0.3 0.36 6
0.3 0.5 3
0.3 0.52 7
scatter3(X,Y,C,[],C,'filled'); %individual plotting of X,Y pairs and colors=C
view([0 90]) %see only XY and Z becomes flat
Imagine we had 10000 XY pairs so scatter3 produces almost an image but without interpolation.
If I understand your question correctly you can use contour(X,Y,Z)
EDIT: You can use imagesc with a matrix that you make yourself. So if your x and y values are in a reasonable range you can just start with:
I = zeros(max(x), max(y));
for d = 1: length(x),
I(x(d),y(d)) = z(d);
end
imagesc(I);