58 views (last 30 days)

Show older comments

I'm trying to make a contour plot using three vectors. I want to contour chlorophyll as a function of depth and time. Each vector is a different length and so I keep getting an error when using interp2. I've also tried using griddata and I'm still getting errors, As well as TriScatterInterp. Can some help me de-bug one of the three ways.

x=dntime

x1=min(dntime)

y=depth_corrected

y1=min(depth_corrected)

%[X,Y]=meshgrid(x,y); %gives the depth/time mesh grid

%chloro

%Z=interp2(X,Y,chloro,x1,y1); %2d interpolation

F=TriScatteredInterp(dntime(:),depth_corrected(:),chloro(:));

dielcycle=F(dntime,depth_corrected);

contour(X,Y,Z)

% x=dntime

% y=depth_corrected

% xq=1:16

% yq=0:0.3500:max(depth_corrected) % depth range

% z=chloro

%vq=griddata(x,y,z,xq,yq) %not gonna work until you change time columns

Star Strider
on 30 Jan 2021

I was able to import these and get an actual datetime array out of the first column:

T1 = readtable('Data.csv');

T1.Var1 = cellfun(@(x)datetime(x,'InputFormat','''''MM-dd-yyyy HH:mm:ss.SSSS''''', 'Format','MM-dd-yyyy HH:mm:ss.SSSS'),T1.Var1);

[Ut,ia,ix] = unique(T1.Var1,'stable');

and an overview of the file:

Segments = diff(ia);

GS = groupsummary(T1,'Var1');

producing:

GS =

16×2 table

Var1 GroupCount

________________________ __________

08-16-2016 02:01:01.0000 1170

08-16-2016 03:56:28.0000 497

08-16-2016 05:56:36.0000 374

08-16-2016 07:57:30.0000 491

08-16-2016 10:02:23.0000 532

08-16-2016 11:59:36.0000 325

08-16-2016 11:59:37.0000 412

08-17-2016 01:56:15.0000 763

08-17-2016 02:03:10.0000 335

08-17-2016 03:59:40.0000 684

08-17-2016 04:00:04.0000 452

08-17-2016 04:53:44.0000 358

08-17-2016 05:58:19.0000 324

08-17-2016 08:00:14.0000 380

08-17-2016 09:59:44.0000 326

08-17-2016 10:56:04.0000 347

The problem is that since there are unequal numbers of each time, using reshape or griddata or any other function to create uniform arrays that contour would be able to use is simply not possible as the data currently exists.

This works for ‘TimeVector’:

TimeVector = linspace(min(T1.Var1), max(T1.Var1), 2000);

however this:

Cols23 = interp1(T1.Var1, T1{:,2:3}, TimeVector(:));

throws the expected error:

Sample points must be unique and sorted in ascending order.

I have no idea what to suggest.

Star Strider
on 30 Jan 2021

I couldn’t make the delimiters work using character arrays, the reason I went with cellfun. Using string representations in the detectImportOptions customisation is definitely the only usable approach here. I’ll keep that in mind.

I agree that the data are not organised in a way that makes contour an option.

Cris LaPierre
on 30 Jan 2021

Edited: Cris LaPierre
on 30 Jan 2021

I found myself bored, so played some more.

Challenges (not an exhaustive list)

- varying number of samples for a given time stamp
- no simple way to resample the data
- datetimes are not a valid input for some of the obvious functions, including contour
- data is not sorted
- inconsistent values of depth
- contour requires V to be a matrix, where rows correspond to depth and columns correspond to date.

After some playing around, I got something working. Key points are

- Obtain one value for each datetime and depth combination. I used groupsummary for this. A side benefit is that it returns a sorted table of increasing values (no duplicates). There are often multiple chloro values for a datetime-depth combination. In this case, I elected to use the median value, though there are many possible options (min, max, mean, custom function)
- I created a fixed depth increment using linspace. This is used to compute new chloro values at known depths for all dates.
- Since there is no obvious relationship day to day, I created a new matrix (rows=depth, columns=unique datetimes) and populated each column with the corresponding chloro values, obtained using interp1 with the known depths and chloro values, and interpolating to the fixed depth values.
- Contour does not allow an input of datetimes. I therefore convert the datetime to a numeric value representing elapsed time in days from the first date. This was arbitrary. I could have used seconds, minutes, hours, etc. The important thing is that it be a numeric value that retains the relative spacing between the dates.

% Load the data

opts = detectImportOptions("JCData.csv");

opts.VariableNames = ["dntime","depth","chloro"];

opts.Delimiter=["'",","];

opts.ConsecutiveDelimitersRule="join";

opts.LeadingDelimitersRule="ignore";

opts=setvartype(opts,"dntime","datetime");

opts=setvaropts(opts,"dntime","InputFormat","MM-dd-yyyy HH:mm:ss.SSSS");

data = readtable("JCData.csv",opts);

% Simplify the data to a single chloro value for each unqiue dntime and depth combination

dtTbl=groupsummary(data,["dntime","depth"],"median","chloro");

% Create uniformly sampled depth

dp=linspace(min(data.depth),max(data.depth));

% Extract unique datetime values

dt = unique(dtTbl.dntime)';

% Resample chloro values at each date using uniform depth vector and interp1

V=zeros(length(dp),length(dt));

for d = 1:length(dt)

ind = dtTbl.dntime==dt(d);

V(:,d) = interp1(dtTbl.depth(ind),dtTbl.median_chloro(ind),dp);

end

% Convert datetime to numeric representation

X = days(dt-dt(1));

% plot

contour(X,dp,V)

colorbar

Jacqueline Chrabot
on 30 Jan 2021

Walter Roberson
on 31 Jan 2021

Alternately, use griddedInterpolant or scatteredInterpolant to create an interpolated grid of output, and contour that. I seem to recall someone contributed a File Exchange contribution for that purpose.

However, the scatter plot that Cris posted on https://www.mathworks.com/matlabcentral/answers/730953-contouring-of-3-vectors?s_tid=srchtitle#comment_1296278 implies to me that you do not have enough continuity of data to be doing a contour plot.

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!