Need to make a 4D plot (3D + Colour) - matlab

I need to make a 3D surface where colour will represent the fourth variable. I know "surf" is SIMILAR to what I need, but that did not work fine. Basically my data obtained from photododie sensor scanning along x,y,z and the forth variable is the intensity( data). The data are stored in text files in the following order.
Total files=2380
in each file there are 4 columns and 480 rows. the columns represent x,y,z,data
I was trying to plot the 3D surface but got this error " Error using
matlab.graphics.chart.primitive.Surface/set
Value must be a vector or 2D array of numeric
type". Please help
Here is the code
close all;
close all;
Axstep=2.5; % scanning with 2.5 micron step along x and y directions
Axlines=2380; %number of text files( in each file there are 4 column of equal
sized data (x,y,z,data) and 480 rows)
Path = 'C:\Users\asay0001\Google Drive\matlab\exp2_27-11-17_CONF09\all data - Copy';
Data = zeros(480,Axlines); % 480 rows in one file out of 2380
for i = 1:Axlines
DataTemp = importdata([Path '\DATA (' num2str(i) ').txt']);
Data(:,i) = DataTemp(:,4); % read column 4 which represents data to be ploted
end
[x y,z] = meshgrid([-3200:2.5:-2602.5],[325:2.5:672.5],[-800:100:800]);
surf(x,y,z,Data')

Related

Smooth edge contour plot

Hello
I want to represent data with 2 variables (latitude and longitude) in 2D format. The value is represented by color and the 2 variables as the 2 axis and I am using the contourf function to plot my data. All the data comes from a xlsx file and I put it in a matrix.
Locations = xlsread('Availability results.xlsx');
column_numberloc = 1; % Column in the locations file containing the number of the locations
column_latitude = 2; % Column in the locations file containing the latitude of the locations
column_longitude = 3; % Column in the locations file containing the longitude of the locations
column_availability = 4; % Column in the locations file containing the availability of the locations
min_latitude = min(Locations(:,column_latitude));
max_latitude = max(Locations(:,column_latitude));
min_longitude = min(Locations(:,column_longitude));
max_longitude = max(Locations(:,column_longitude));
max_availability = max(Locations(:,column_availability));
min_availability = min(Locations(:,column_availability));
longitude = Locations(:,column_longitude);
latitude = Locations(:,column_latitude);
Contour = zeros(23,17);
for numerofile=1:204
[coord_x,coord_y] =transformation(Locations(numerofile,column_latitude),Locations(numerofile,column_longitude));
Contour(coord_x,coord_y) = Locations(numerofile,column_availability);
end
for i=1:23
for j=1:17
if Contour(i,j) == 0
Contour(i,j) = NaN;
end
end
end
cMap=jet(256);
figure(1);
x = linspace(min_longitude,max_longitude,17);
y = linspace(min_latitude,max_latitude,23);
newpoints = 100;
[xq,yq] = meshgrid(linspace(min(x),max(x),newpoints),linspace(min(y),max(y),newpoints ));
Contourq = interp2(x,y,Contour,xq,yq,'linear',max_availability);
[c,h]=contourf(xq,yq,Contourq,100);
%[c,h]=contourf(x,y,Contour,50);
set(h, 'edgecolor','none');
colormap(cMap);
cb=colorbar;
caxis([min_availability max_availability]);
The transformation function allows me to place all the data in the Contour matrix as it associate a longitude and a latitude to a row and a column.
I've putted a NaN for every data equal to zero to have a better look at my data and I obtained this :
interpolation_linear
Which is nice but I wanted this data to be close to :
Without interpolation
So, I decided to change the linear interpolation to a 'nearest' interpolation and I got this :
interpolation_nearest
I can see more data but the contour plot isn't as smooth as with the linear interpolation.
I've seen many posts about how to make smooth contour plot (that's how I found the function 'interp2') but I think that my problem comes from the NaN data which prevent me from having a smooth contour plot at the edge between NaN values and the rest like the first image but with enough data like the third image.
My question is : Do you know how can I get a smooth edge contour plot with enough data thanks to the nearest interpolation but with a nice visual like the first image ?
Thank you very much
Since you are doing an interpolation on a square grid, you could directly display a 2D image with imagesc.
The advantage is that you can access the AlphaData property of image objects, which can be used as a display mask.
r=rand(50); % random 50x50 array
r(11:20,11:20)=NaN; % some hole filled with NaN
imagesc(r) % show the image, with NaN considered as the lowest value in color scale
imagesc(r,'AlphaData',~isnan(r)) % show the image, with NaN values set as fully transparent
You may also then:
set a display mask first
replace zeros or NaN with some meaningful values (nearest non NaN value?)
interpolate with interp2, perhaps even with the 'cubic' parameter for improved smoothness
display only the meaningful part of the image thanks to the display mask set in AlphaData.

multiple matlab contour plots with one level

I have a number of 2d probability mass functions from 2 categories. I am trying to plot the contours to visualise them (for example at their half height, but doesn't really matter).
I don't want to use contourf to plot directly because I want to control the fill colour and opacity. So I am using contourc to generate xy coordinates, and am then using fill with these xy coordinates.
The problem is that the xy coordinates from the contourc function have strange numbers in them which cause the following strange vertices to be plotted.
At first I thought it was the odd contourmatrix format, but I don't think it is this as I am only asking for one value from contourc. For example...
contourmatrix = contourc(x, y, Z, [val, val]);
h = fill(contourmatrix(1,:), contourmatrix(2,:), 'r');
Does anyone know why the contourmatrix has these odd values in them when I am only asking for one contour?
UPDATE:
My problem seems might be a failure mode of contourc when the input 2D matrix is not 'smooth'. My source data is a large set of (x,y) points. Then I create a 2D matrix with some hist2d function. But when this is noisy the problem is exaggerated...
But when I use a 2d kernel density function to result in a much smoother 2D function, the problem is lessened...
The full process is
a) I have a set of (x,y) points which form samples from a distribution
b) I convert this into a 2D pmf
c) create a contourmatrix using contourc
d) plot using fill
Your graphic glitches are because of the way you use the data from the ContourMatrix. Even if you specify only one isolevel, this can result in several distinct filled area. So the ContourMatrix may contain data for several shapes.
simple example:
isolevel = 2 ;
[X,Y,Z] = peaks ;
[C,h] = contourf(X,Y,Z,[isolevel,isolevel]);
Produces:
Note that even if you specified only one isolevel to be drawn, this will result in 2 patches (2 shapes). Each has its own definition but they are both embedded in the ContourMatrix, so you have to parse it if you want to extract each shape coordinates individually.
To prove the point, if I simply throw the full contour matrix to the patch function (the fill function will create patch objects anyway so I prefer to use the low level function when practical). I get the same glitch lines as you do:
xc = X(1,:) ;
yc = Y(:,1) ;
c = contourc(xc,yc,Z,[isolevel,isolevel]);
hold on
hp = patch(c(1,1:end),c(2,1:end),'r','LineWidth',2) ;
produces the same kind of glitches that you have:
Now if you properly extract each shape coordinates without including the definition column, you get the proper shapes. The example below is one way to extract and draw each shape for inspiration but they are many ways to do it differently. You can certainly compact the code a lot but here I detailed the operations for clarity.
The key is to read and understand how the ContourMatrix is build.
parsed = false ;
iShape = 1 ;
while ~parsed
%// get coordinates for each isolevel profile
level = c(1,1) ; %// current isolevel
nPoints = c(2,1) ; %// number of coordinate points for this shape
idx = 2:nPoints+1 ; %// prepare the column indices of this shape coordinates
xp = c(1,idx) ; %// retrieve shape x-values
yp = c(2,idx) ; %// retrieve shape y-values
hp(iShape) = patch(xp,yp,'y','FaceAlpha',0.5) ; %// generate path object and save handle for future shape control.
if size(c,2) > (nPoints+1)
%// There is another shape to draw
c(:,1:nPoints+1) = [] ; %// remove processed points from the contour matrix
iShape = iShape+1 ; %// increment shape counter
else
%// we are done => exit while loop
parsed = true ;
end
end
grid on
This will produce:

How to reorientation as axial axis of raw image from brainweb

I have a raw image with the information such as
image dimensions: zspace yspace xspace
dimension name length step start
-------------- ------ ---- -----
zspace 181 1 -72
yspace 217 1 -126
xspace 181 1 -90
should be interpreted as follows:
the file scans the 3D image volume such that the 'X' coordinate changes fastest, and the 'Z' changes slowest.
the image sizes along the X-Y-Z axes are 181x217x181 voxels (pixels).
the voxel sizes along the X-Y-Z axes are 1x1x1 mm.
One (unsigned) byte is used for each voxel, and the data is scaled such that it will use the entire 0...255 range of values.
Currently, I am using below code to read that raw file. It can be read the raw image and display as right figure. However, it does not look like my expected result where image is reorientation as axial axis.
Could you help me solving it by Matlab code?
filepath=strcat('t1_icbm_normal_1mm_pn5_rf20.rawb');
fid = fopen(filepath,'r');
rima=zeros(dim(1:3));
for z=1:dim(3),
rima(:,:,z) = fread(fid,dim(1:2),'uchar');
end;
fclose(fid);
imshow(rima(:,:,91),[]); %% Show slice 91th
The reference link is http://brainweb.bic.mni.mcgill.ca/about_data_formats.html .
The input file can be downloaded from here or brainweb
The reason why is because when MATLAB reads in data, it places the data in column major order. This means that the data you read in via rows get placed in columns. Therefore, this has the appearance that your image gets rotated 90 degrees and reflected.
One easy solution would be to take your matrix and transpose each slice individually. A simple call to permute should do the trick:
rima = permute(rima, [2 1 3]);
The above code swaps the second and first dimensions over each slice of your matrix, effectively performing a transpose of each slice independently. I've also noticed that when you do this, there is a reflection across the horizontal axis. Make a call to flipdim to fix this:
rima = flipdim(permute(rima, [2 1 3]), 1);
To reproduce, I've downloaded the file and ran the code on my computer. I show the 91th slice before and after I permute and flipdim:
filepath=strcat('t1_icbm_normal_1mm_pn5_rf20.rawb');
fid = fopen(filepath,'r');
dim = [181 217 281]; %// Added for code to run
rima=zeros(dim(1:3));
for z=1:dim(3),
rima(:,:,z) = fread(fid,dim(1:2),'uchar');
end;
fclose(fid);
imshow(rima(:,:,91),[]); %% Show slice 91th
%// New - Permute dimensions and flip rows
rima = flipdim(permute(rima, [2 1 3]), 1);
figure;
imshow(rima(:,:,91),[]); %%// Show corrected slice
Here's what we get for before and after:

Creating a movie in MATLAB with point data for a simple N-body simulation

I am trying to write a simple n-body gravity simulation with 4 particles in C++. I am outputting the positions of the 4 particles to .mat files labeled "time_X.mat" (where X=1,2,3.... indicates the time-stamp) in the form of a 4x2 matrix where
i'th row indicates (x,y) cooridinates of the ith particle at time X .
Now for a particular time-step I am able load the .mat file into MATLAB and get a scatterplot of the points in the matrix, showing me particle positions. But I would like to create a movie out of all the .mat files / scatter-plots of the time_X.mat files which shows me the evolution of the 4 particle syestem . How should I do that in MATLAB?
First you have to make frames (images) of each time step of your simulation.
Since you have Cartesian coordinates, you have to convert your x and y coordinates to pixel indices, and make an image matrix from them. See my answer to a relevant question for an example of how to do this. You could also modify the code to make your points larger than a pixel, have shapes, etc., perhaps with strel or [a,b,~] = sphere(N).
Once you have the frames, you can easily make an AVI file (uncompressed or MPEG) in MATLAB:
aviOutput = fullfile('path','to','file.avi');
aviobj = VideoWriter(aviOutput);
aviobj.Quality = 100;
aviobj.FrameRate = 24; %# arbitrary
open(aviobj);
for i=1:length(frames)
writeVideo(aviobj,frames{i}); %# or frames(:,:,i) etc.
end
close(aviobj);
Update
The above assumes the time steps are all available. For example:
files = dir('path/to/dir');
files(1:2) = []; %# . and ..
orderedfiles = cell(length(files),1);
for i=1:length(files)
ind = sscanf(files(i).name,[name '%*[_]%u%*s']);
orderedfiles{ind+1} = files(i).name;
end
timeSteps = zeros(numPoints,2,length(orderedfiles));
for i=1:length(orderedfiles)
temp = load(orderedfiles(i).name);
timeSteps(:,:,i) = temp.matrixName %# All the same name?
end
The code from the linked answer is written to operate on two vectors x and y with the coordinates, which you would get with timeSteps(:,1,i) and timeSteps(:,2,i), and do for each time step.

Drawing and filling different polygons at the same time in MATLAB

I have the code below. It load a CSV file into memory. This file contains the coordinates for different polygons.Each row of this file has X,Y coordinates and a string which tells that to which polygon this datapoint belongs. for example a polygone named "Poly1" with 100 data points has 100 rows in this file like :
Poly1,X1,Y1
Poly1,X2,Y2
...
Poly1,X100,Y100
Poly2,X1,Y1
.....
The index.csv file has the number of datapoint(number of rows) for each polygon in file Polygons.csv. These details are not important. The thing is:
I can successfully extract the datapoints for each polygon using the code below.
However, When I plot the lines of different polygons are connected to each other and the plot looks crappy. I need the polygons to be separated(they are connected and overlapping the some areas though). I thought by using "fill" I can actually see them better. But "fill" just filles every polygon that it can find and that is not desirable. I only want to fill inside the polygons. Can someone help me? I can also send you my datapoint if necessary, they are less than 200Kb.
Thanks
[coordinates,routeNames,polygonData] = xlsread('Polygons.csv');
index = dlmread('Index.csv');
firstPointer = 0
lastPointer = index(1)
for Counter=2:size(index)
firstPointer = firstPointer + index(Counter) + 1
hold on
plot(coordinates(firstPointer:lastPointer,2),coordinates(firstPointer:lastPointer,1),'r-')
lastPointer = lastPointer + index(Counter)
end
This solution may work for you:
[coordinates,routeNames,polygonData] = xlsread('Polygons.csv'); %# Load the data
for polyName = unique(routeNames(:).') %'# Loop over unique polygons
polyIndex = ismember(routeNames,polyName); %# Find index of polygon points
x = coordinates(polyIndex,:); %# Get x coordinates
y = coordinates(polyIndex,:); %# Get y coordinates
patch(x,y); %# Plot a patch
hold on; %# Add to the existing plot
end
This creates the polygons using the PATCH function. To color the patches differently, check out this MATLAB documentation.
I think patch is a better tool for drawing filled polygons. Check it out!