Smoothing of a 3d-geometry - matlab

figure
isovals = shiftdim(xPhys,2);
isovals = smooth3(isovals,'box',1);
patch(isosurface(isovals,0.8),'FaceColor',[0 0 1],'EdgeColor','none'); % blue
patch(isocaps(isovals,0.8),'FaceColor',[1 0 0],'EdgeColor','none'); % red
view(3); axis equal tight off; camlight;
The above code transforms this 3d-geometry
in this geometry
xPhys (variable in the second line of the code) is a 3d matrix whose elements indicate the density of a square, zero means the square is empty, one means it is completely filled with material. And in between there are infinitely different intermediate levels.
I have created a code that causes there to be only one intermediate value (e.g. 0.5), this can be seen here as light grey.
I would like to rewrite the code so that the last geometry shown is smoothed, but one should be able to distinguish the light grey from the black areas. In the code above, no distinction is made, all squares get the colour blue.
What can i do to achieve this goal?

Related

Border of a scatter plot in Matlab: constructing it and colouring it

I would like your help to plot the border of a scatter in Matlab and fill it with a specified colour.
Let me firstly show you how the scatter looks like.
scatter(x,y)
Now, let me show you what I have tried to design the border.
k = boundary(x,y);
plot(x(k),y(k));
which produces this
This is not what I want. Firstly, the scatter is nicely convex and I don't understand why boundary produces that weird shape. Secondly, I want to colour with blue inside the border.
Could you kindly advise on how to proceed? Also, when building the border I would prefer not to rely on the convexity of the scatter, because in some of my real examples the scatter is not convex.
Boundary
There is no easy way to get the boundary of a non-convex shape without any information on what is expected. When should the boundary follow the convex hull and when should deviate from it?
Matlab function boundary is generic, made to work with arbitrary input coordinates. It has a 'shrink factor' parameter s that can be tuned between 0 (convex hull) and 1 (highly non-convex), depending on the expected result.
% Make some x,y data with a missing corner
[x,y]=meshgrid(1:20);
sel=~(x>15 & y<=5);
x=x(sel);y=y(sel);
% Compute boundary with several values for s
k=boundary([x,y]); %Default shrink factor : 0.5
k_convhull=boundary([x,y],0);
k_closest=boundary([x,y],1);
% Plot the boundary:
plot(x,y,'ok') %black circles
hold on
plot(x(k),y(k),'-r') %red line
plot(x(k_convhull),y(k_convhull),'-g') %green line
plot(x(k_closest),y(k_closest),'-b') %blue line
The re-entrant corner is still somewhat cut, even with the 'shrink factor' set to 1. If this does not suit you, you will need to make your own function to compute the coordinates of the border.
Plot a surface
You need to use a patch object there.
p=patch(x(k3),y(k3),[1 .8 .8]);
uistack(p,'bottom')
[1 .8 .8] is the RGB color of the patch surface (light pink)
uistack is there to move the patch below the other graphic objects, because it is not transparent. It will still cover the axes grid, if any. Another option is :
p=patch(x(k3),y(k3),[1 0 0],'FaceAlpha',.2);
Here, the patch will be plain red and drawn on top of other objects, but has 80% transparency set through the alpha channel (0 is fully transparent, 1 is solid color).
Beware, the patch object class has so many options that is somewhat complex to handle beyond basic use cases like this one.

Scatter plot color thresholding

I am trying to write a script to plot florescence intensity from some microscopy data as a scatter plot and threshold this data based on cells that respond greater than a certain amount in CFPMAX and plot these in green and cells that do not in red. When I try to plot this, I am unable to really assign proper colors to points and they end up being blue and red. I need each cell in the image to be assigned 4 values, (3 values for for each florescence channel and one value to determine whether or not it responded (green or red). Thus I was wondering if it was possible to assign the proper color to the 4th column of the matrix, or if I am going about this the wrong way all together. I have attached my code below.
MCHR=csvread('data1.csv');
MYFP=csvread('data2.csv');
MCFP=csvread('data3.csv');
CFPMAX=(max(MCFP))';
MCHMAX=(max(MCHR))';
YFPMAX=(max(MYFP))';
c=zeros(length(CFPMAX));
for i=1:length(c)
if CFPMAX(i)>40
c(i)='g'; %// green responders
else
c(i)='r'; %// red non-responders
end
end
MM=horzcat(MCHMAX,YFPMAX,CFPMAX,c);
scatter(MM(:,1),MM(:,2),100,MM(:,4),'filled','MarkerEdgeColor',[0 0 0])
title('Responders vs Non-Responders ')
xlabel('[TF1]') %// x-axis label
ylabel('[TF2]') %// y-axis label
As far as I can tell from the documentation, the input parameter c (assuming scatter(x,y,a,c,...)) can be one of:
A single character specifying a colour e.g. 'g' or 'r'. But just one single scalar colouring all of you points.
A single RGB triple colouring all of your points so [1,0,0] for red or [0,1,0] for green.
A three column matrix of RGB triples. This is likely what you want. I will demonstrate this to you.
A one column matrix of numbers which will colour the points according to a colormap. This one will also work for you but less explicitly. Incidentally, I would guess that this is option that MATLAB though your vector of characters was.
So in order to create the matrix of RGB triples you can modify your code to be
c=zeros(length(CFPMAX),3);
for i = 1:length(CFPMAX)
if CFPMAX(i)>40
c(i,:)=[0,1,0]; %// green responders
else
c(i,:)=[1,0,0]; %// red non-responders
end
end
However, you could actually do away with the for-loop completely in MATLAB and construct c in a vectorized approach using logical indexing:
c=zeros(length(CFPMAX),3);
c(CFPMAX > 40, 2) = 1; %// green responders
c(CFPMAX <= 40, 1) = 1; %// red responders
This is a more idiomatic way to do this in MATLAB.

How to make a heat map on top of worldmap using hist3 in MATLAB?

My x-axis is latitudes, y-axis is longitudes, and z-axis is the hist3 of the two. It is given by: z=hist3(location(:,1:2),[180,360]), where location(:,1) is the latitude column, and location(:,2) is the longitude column.
What I now want is, instead of plotting on a self-created XY plane, I want to plot the same on a worldmap. And instead of representing the frequency of each latitude-longitude pair with the height of the bars of hist3, I want to represent the frequency of each location by a heat map on top of the world map, corresponding to each latitude-longitude pair's frequency on the dataset. I have been searching a lot for this, but have not found much help. How to do this? I could only plot the skeleton of the worldmap like this:
worldmap world
load geoid
geoshow(geoid, geoidrefvec, 'DisplayType', 'texturemap');
load coast
geoshow(lat, long)
I don't know what the colour is being produced based on.
Additionally, if possible, I would also like to know how to plot the hist3 on a 3D map of the world (or globe), where each bar of the hist3 would correspond to the frequency of each location (i.e., each latitude-longitude pair). Thank you.
The hist3 documentation, which you can find here hist3, says:
Color the bars based on the frequency of the observations, i.e. according to the height of the bars. set(get(gca,'child'),'FaceColor','interp','CDataMode','auto');
If that's not what you need, you might wanna try it with colormap. More info about it here colormap. I haven't tried using colormap on histograms directly, so If colormap doesn't help, then you can try creating a new matrix manually which will have values in colors instead of the Z values the histogram originally had.
To do that, you need to first calculate the maximum Z value with:
maxZ=max(Z);
Then, you need to calculate how much of the colors should overlap. For example, if you use RGB system and you assign Blue for the lowest values of the histogram, then Green for the middle and Red for the High, and the green starts after the Blue with no overlap, than it will look artificial. So, if you decide that you will have, for example overlapping of 10 values, than, having in mind that every R, G and B component of the RGB color images have 255 values (8 bits) and 10 of each overlap with the former, that means that you will have 255 values (from the Blue) + 245 values (From the Green, which is 255 - 10 since 10 of the Green overlap with those of the Blue) + 245 (From the Red, with the same comment as for the Green), which is total amount of 745 values that you can assign to the new colored Histogram.
If 745 > maxZ there is no logic for you to map the new Z with more than maxZ values. Then you can calculate the number of overlaping values in this manner:
if 745 > maxZ
overlap=floor(255- (maxZ-255)/2)
end
At this point you have 10 overlapping values (or more if you still think that it doesn't looks good) if the maximum value of the Z is bigger than the total amount of values you are trying to assign to the new Z, or overlap overlapping values, if the maximum of Z is smaller.
When you have this two numbers (i.e. 745 and maxZ), you can write the following code so you can create the newZ.
First you need to specify that newZ is of the same size as Z. You can achieve that by creating a zero matrix with the same size as Z, but having in mind that in order to be in color, it has to have an additional dimension, which will specify the three color components (if you are working with RGB).
This can be achieved in the following manner:
newZ=zeros(size(Z),3)
The number 3 is here, as I said, so you would be able to give color to the new histogram.
Now you need to calculate the step (this is needed only if maxZ > The number of colors you wish to assign). The step can be calculated as:
stepZ=maxZ/Total_Number_of_Colors
If maxZ is, for example 2000 and Total_Number_of_Colors is (With 10 overlaping colours) 745, then stepZ=2.6845637583892617449664429530201. You will also need a counter so you would know what color you would assign to the new matrix. You can initialize it here:
count=0;
Now, finally the assignment is as follows:
For i=1:stepZ:maxZ
count=count+1;
If count>245
NewZ(Z==stepz,3)=count;
elseif count>245 && count<256
NewZ(Z==stepz,3)=count;
NewZ(Z==stepz,2)=count-245;
elseif count>255
NewZ(Z==stepz,2)=count-245;
elseif count>500 && count<511
NewZ(Z==stepz,2)=count-245;
NewZ(Z==stepz,1)=count-500;
else
NewZ(Z==stepz,1)=count-500;
end
end
At this point you have colored your histogram. Note that you can manually color it in different colors than red, green and blue (even if you are working in RGB), but it would be a bit harder, so if you don't like the colors you can experiment with the last bit of code (the one with the for loops), or check the internet of some other automatic way to color your newZ matrix.
Now, how do you think to superimpose this matrix (histogram) over your map? Do you want only the black lines to be shown over the colored histogram? If that's the case, than it can be achieved by resampling the NewZ matrix (the colored histogram) with the same precision as the map. For example, if the map is of size MxN, then the histogram needs to be adjusted to that size. If, on the other hand, their sizes are the same, then you can directly continue to the next part.
Your job is to find all pixels that have black in the map. Since the map is not binary (blacks and whites), it will be a bit more harder, but still achievable. You need to find a satisfactory threshold for the three components. All the lines under this threshold should be the black lines that are shown on the map. You can test these values with imshow(worldmap) and checking the values of the black lines you wish to preserve (borders and land edges, for example) by pointing the cross tool on the top of the figure, in the tools bar on every pixel which is of interest.
You don't need to test all black lines that you wish to preserve. You just need to have some basic info about what values the threshold should have. Then you continue with the rest of the code and if you don't like the result so much, you just adjust the threshold in some trial and error manner. When you have figured that this threshold is, for example, (40, 30, 60) for all of the RGB values of the map that you wish to preserve (have in mind that only values that are between (0,0,0) and (40,30,60) will be kept this way, all others will be erased), then you can add the black lines with the following few commands:
for i = 1:size(worldmap,1)
for j = 1:size(worldmap,2)
if worldmap(i,j,1)<40 && worldmap(i,j,2)<30 && worldmap(i,j,3)<60
newZ(i,j,:)=worldmap(i,j,:)
end
end
I want to note that I haven't tested this code, since I don't have Matlab near me atm, so It can have few errors, but those should be easily debugable.
Hopes this is what you need,
Cheers!

Matlab: Gradient color spots according to percentage

I want to paint some edges on my plot using gradient color according to their repetition percentage.
So the most repeated edge on my graph to be red, the next lesser to be orange and the edge with the less repetitions to be light beige.
The Percentage of the repetition can be obtained from a txt file.
The rest area of the plot i would like to stay intact in white color. Something like the next image (consider objects shape and size irrelevant, just the color gradient is what i am interested for).
How can i do this with matlab?
My approach so far:
EDIT it works with the addition of the hold all cmd
for jkl=1:size(edges,1)
plot(edges(jkl,1), edges(jk,2),'^','Color',[edgespercentage(jkl)/100 0 1], 'LineWidth', 2.5,'DisplayName', 'Edges with gradient color'); hold all
end
But as i see plot cant keep each iteration's color and plots at the end the last calculated color only (as expected).
Thank you in advance.
Solution found with the tip of David K (Thank you!)
I'm not sure if this is exactly what you want, but give it a shot:
mesh(xvals,yvals,zvals,repititionVals);
colormap('hot');
You can play around with colormap to get the exact shading you want, but I think either hot or autumn is the closest predefined map to what you're looking for

color triangles with exceptions to some

I am trying to draw a 2D mesh of triangles. I want to color each triangle according to a given array A of positive scalars, one per triangle; For instance assume the A holds the area of each triangle, and I want large triangles to be pinker than smaller ones. I know how to do this:
patch('Faces',tri,'Vertices',V,'FaceColor','flat',
'FaceVertexCData',A,...
'CDataMapping','scaled');
colormap(pink);
However, I also have another boolean array B, one boolean per triangle. For instance it marks which of the triangles are isosceles triangles.
In case a triangle is marked as 1 in B, I want to color it yellow.
I assume this can be achieved by something like A(B==1)=-1, changing the colormap and clever setting of caxis, but is this the most elegant way?
Do you want to skip coloring of some triangles (color them with one color), or use a different colormap for those triangles?
The first case is relatively simple for 2D plots. You can set A in those triangles to NaN, and patch will not draw them. Additionally, changing the background color of the plot will effectively show the non-drawn triangles in the color you want
A(B)=NaN;
set(gca,'Color',[1 0 0]); % red
If you want to use a different color, or a range of colors, you have to append the colormaps and set the values in A for the respective triangles to be 'larger enough' than A for any other triangles:
cmap = [colormap; [1 0 0]]; % red
colormap(cmap);
A(B) = max(A)+1;
No need to play with axis.
Otherwise, if you want to include two different color scales, you have to play with CData property of your patch plots, see a good tutorial here for drawing two plots, one in grayscale and one in color on the same figure.
There is also this post about how to plot two different data sets with two different colormaps. It is done by appending two colormaps and making sure that two datasets access distinct parts of the final colormap.