I create a figure using a barplot that represents means of groups.
I have a matrix that tells me whether the means are statistically different.
sign_diff =
0 0 0 1
0 0 0 1
0 0 0 0
1 1 0 0
In this case the means of the first group and second group are significantly different from the mean of the 4th group.
How to read the matrix:
first rows: there is a 1 in the last column -> first bar is different from bar 4 so bar 1 and bar 4 get a star.
second row: there is a 1 in the last column -> second bar is different from bar 4 so bar 2 and bar 4 get a star. In more since bar 1 and bar 2 are not different between them the stars in bar 1 and bar 2 should be at the same high
How can I add a marker on top of the bars that are different?
I would like to have something like this:
Please note that the first two stars should be at the same levels indicating that bar1 and bar2 do not differ, but they both differ from bar4 (then the star on top of bar 4 should be higher)
Hope you can help me
I'm still not sure I quite grasp the height logic (and we don't have a functioning example) but in the meantime there's a simple answer the superimposition question. You can use line to superimpose the stars onto your plot.
For example:
y = [1 2 3 4];
bar(y);
ylim([0 6]);
sign_diff = [0 0 0 1; 0 0 0 1; 0 0 0 0; 1 1 0 0];
needs_star = (sum(sign_diff) ~= 0); % See which bars need a star
star_heights = sum(sign_diff).*0.75;
star_x = 1:length(y);
star_y = max(y) + star_heights;
star_x = star_x(needs_star);
star_y = star_y(needs_star);
line(star_x, star_y, ...
'linestyle', 'none', ...
'marker', 'p', ...
'markersize', 15 ...
);
Produces the following:
line accepts XY inputs, so if you can create coordinates for your stars based on your sign_diff matrix you can use them in the line call.
Edit: I have updated with my stab at figuring out the logic. Some tweaks will be needed based on your data. The ylim and max calls will need to be adjusted based on the maximum height of the data in your graph in order to fit everything into the axes and to make sure there is no overlap. You can tweak the 0.75 value to whatever you would like in order to show the differences adequately. This is probably not the most efficient method but the behavior is at least explicit.
Related
t: ([] x: til 4; y: -2 3 -4 5)
fillfn: {?[y > 0;`green;`red]}
.qp.go[1000;500] .qp.bar[t; `x; `y] .qp.s.geom[``fill`sortByValue!(::; fillfn; 0b)]
x y
----
0 -2
1 3
2 -4
3 5
Two questions:
How do I fix the bars starting at the bottom instead of zero?
How do I set the fill to be a green bar for positive and a red bar for negative y?
The solution to this turns out to be a different function altogether.
One needs to use a .qp.interval chart, setting one coordinate to be zero always.
For me, this looked like:
plot: { .qp.go[1500;500] .qp.interval[x; `t; `y; `r] .qp.s.aes[`fill; `pos], .qp.s.scale[`fill; .gg.scale.colour.cat 01b!(`red; `green)]}
where y is a column of zeroes.
Suppose I have two input images. One only contains three colors such as green, red, and blue as labels. Another image that needs to be edited based on the colors in the first image. So, for instance, wherever the label image is red, I'd like function A to happen on the original image.
To do this, I would like to create a lookup that gets a color as input and outputs a function to be executed on the original image.
What's the best way to go about this?
You can use logical indexing for this.
im1 = [0 0 1;
1 2 0;
2 2 1];
im2 = rand(3);
find where im1 equals 1:
idx = im1 == 1;
idx is now a matrix of logicals which can act as a mask for im2:
idx =
0 0 1
1 0 0
0 0 1
do something to all the corresponding pixels of im2:
im2(idx) = im2(idx) + 5;
Also, although I doubt this is what you were asking, you could define your function A using anonymous functions:
A = #(x)(2.*x.^2 - x + 5)
im2(idx) = A(im2(idx))
Given a vector of zeros and ones in MATLAB, where the zeros represent an event in time, I would like to add additional ones before and after the existing ones in order to capture additional variation.
Example: I would like to turn [0;0;1;0;0] into [0;1*;1;1*;0] where 1* are newly added ones.
Assuming A to be the input column vector -
%// Find all neighbouring indices with a window of [-1 1]
%// around the positions/indices of the existing ones
neigh_idx = bsxfun(#plus,find(A),[-1 1])
%// Select the valid indices and set them in A to be ones as well
A(neigh_idx(neigh_idx>=1 & neigh_idx<=numel(A))) = 1
Or use imdilate from Image Processing Toolbox with a vector kernel of ones of length 3 -
A = imdilate(A,[1;1;1])
You can do it convolving with [1 1 1], and setting to 1 all values greater than 0. This works for column or row vactors.
x = [0;0;1;0;0];
y = double(conv(x, [1 1 1],'same')>0)
Purely by logical indexing:
>> A = [0 1 1 0 0];
>> A([A(2:end) 0] == 1 | [0 A(1:end-1)] == 1) = 1;
>> disp(A);
A =
1 1 1 1 0
This probably merits an explanation. The fact that it's a 3 element local neighbourhood makes this easy. Essentially, take two portions of the input array:
Portion #1: A starting from the second element to the last element
Portion #2: A starting from the first element to the second-last element
We place the first portion into a new array and add 0 at the end of this array, and check to see which locations are equal to 1 in this new array. This essentially shifts the array A over to the left by 1. Whichever locations in this first portion are equal to 1, we set the corresponding locations in A to be 1. The same thing for the second portion where we are effectively shifting the array A over to the right by 1. To shift to the right by 1, we prepend a 0 at the beginning, then extract out the second portion of the array. Whichever locations in this second portion are equal to 1 are also set to 1.
At the end of this operation, you would essentially shift A to the left by 1 and save this as a separate array. Also, you would shift to the right by 1 and save this as another array. With these two, you simply overlap on top of the original to obtain the final result.
The benefit of this method over its predecessors in this post is that this doesn't require computations of any kind (bsxfun, conv, imdilate etc.) and purely relies on indexing into arrays and using logical operators1. This also handles boundary conditions and can work on either row or column vectors.
Some more examples with boundary cases
>> A = [0 0 1 1 0];
>> A([A(2:end) 0] == 1 | [0 A(1:end-1)] == 1) = 1
A =
0 1 1 1 1
>> A = [0 0 0 0 1];
>> A([A(2:end) 0] == 1 | [0 A(1:end-1)] == 1) = 1
A =
0 0 0 1 1
>> A = [1 0 1 0 1];
>> A([A(2:end) 0] == 1 | [0 A(1:end-1)] == 1) = 1
A =
1 1 1 1 1
1: This post is dedicated to Troy Haskin, one who believes that almost any question (including this one) can be answered by logical indexing.
Lets say I have a multiple bar, which looks smth like that:
aa = repmat([1 2 10 5 15 3], 5,1)
aa =
1 2 10 5 15 3
1 2 10 5 15 3
1 2 10 5 15 3
1 2 10 5 15 3
1 2 10 5 15 3
bar(aa)
What I need is to put a star or a label on some certain column, which sutisfies some conditions. Another option is to change the colour of that bar.
If I could get the coordinates of each column I could use plot. Or maybe I can modify errorbar somehow?
Thanks for any advices.
Problem
You can get the x and y values of the bars (x=horizontal position, y=height of each bar) using:
hb=bar(aa);
x=cell2mat(get(hb,'Xdata'));
y=cell2mat(get(hb,'Ydata'));
which you can then use to plot a textlabel with text,
or even just plot the mark symbols with plot:
plot(x,y,'*',Markersize',12)
Unfortunately, this only works correctly if you only have one single serie of data, because Xdata contains the index in the series (1,2,3,etc). For multiple series matlab spreads the bars around that index, but the Xdata values are all the same (despite in the plot, they aren't plotted at exact the same position).
Solution
Add the option 'hist' to the bar plotting:
hb=bar(aa,'hist')
this creates patches rather than barseries, and
x=cell2mat(get(hb,'Xdata'));
y=cell2mat(get(hb,'Ydata'));
now contains the (actual) corners of those patches. Extract the x-center as follows:
xcenter = 0.5*(x(2:4:end,:)+x(3:4:end,:));
The height is obtainable with one of the upper corners of the patch:
ytop = y(2:4:end,:);
Now you can use that for the plotting:
idx_mark = 3;
plot(xcenter(idx_mark ,:),ytop(idx_mark ,:),'*','Markersize',12)
or for annotation:
text(xcenter(idx_mark ,2),ytop(idx_mark ,2),'MARKED',...
'HorizontalAlignment','center', ...
'VerticalAlignment','bottom' )
I think that what you could do that (for the colors) with playing a little with the bar function properties.
It also all depends if you know more or less how your plot will look like; if you know beforehand I think you could use XTick and XTicklabel to label you columns.
http://www.mathworks.nl/help/techdoc/ref/bar.html
For example:
a=[1 1 0 0 1 1 0 1 1 1 0 0];
Now i want to sum only the ones which are divides by the zeros:
ones=[2 2 3] - That means two ones,then we have 2 zeros which we do not count,then again two ones etc.
How can i do this?
Well, I would suggest finding all places where it switches from 0 to 1 and then finding all places where it switches from 1 to 0, and using those indices to find those lengths. The problem arises at the edges where if the first entry is 1, it doesn't switch to one from zero, and if the last entry is 1, we never find it because nothing switches to 0 at the end. In order to avoid this problem easily, we can add a 0 in the beginning and one at the end. This way we're guaranteed to find each one of those bursts of ones. In essence:
b = [0 a 0];
d = diff(b);
posEdge = find(d==1);
negEdge = find(d==-1);
countOnes = negEdge - posEdge