Creating scattered 2D Contour Plot

Hello, I’m having an issue creating a 2D contour plot in Scilab. My data comes from the following table. The x-axis represents the intrinsic viscosity, the y-axis shows the concentration, and the color bar should represent the complex viscosity.

Why do the values in my contour plot not match the measured values?
Why is the bottom-left area of the plot not filled, even though I have measured data points there?
How can I set the axis labels to show only two decimal places?

IV Konz Visc
2,57 5 2,04
2,57 6,5 3,71
2,57 7 4,785
2,57 10 6,285
2,57 12 7,285
2,96 5 3,00
2,96 6 4,30
2,96 8 8,00
2,96 10 11,84
3,18 5 3,31
3,18 6,5 5,64
3,18 9 12,19

Hello,

Can you give the code producing the graph ?

S.

IV = [2.57; 2.57; 2.57; 2.57; 2.57;
2.96; 2.96; 2.96; 2.96;
3.18; 3.18; 3.18];
Conc = [5; 6.5; 7; 10; 12;
5; 6; 8; 10;
5; 6.5; 9];
Eta = [2.04; 3.71; 4.785; 6.285; 7.285;
3.00; 4.30; 8.00; 11.84;
3.31; 5.64; 12.19];

xyz = [IV, Conc, Eta];

tl = cshep2d(xyz);

xg = linspace(min(IV), max(IV), 100);
yg = linspace(min(Conc), max(Conc), 100);
[Xg,Yg] = ndgrid(xg, yg);

Zg = eval_cshep2d(Xg, Yg, tl);
f = scf();
f.color_map = jet(64);

contourf(xg, yg, Zg, 60);

colorbar(1, 12);

xlabel(“Intrinsische Viskosität / m³/kg”);
ylabel(“Konzentration / mg/mL”);

Ok. There are two facts:

  1. your (x,y) data is organized on a trapezoidal domain, hence using a rectangular grid to later interpolate will give you (x,y) data outside this domain and thus, extrapolate.
  2. cshep2d is not well fitted to your (x,y) data: considering the very small number of data points, the cubic interpolation creates artifacts which are irrelevant (see the small “waves” on the left part of your graph above).

For your data a better approach should be to accept an approximate polynomial model. In the below code, a fine trapezoidal grid is constructed by squeezing a rectangular grid by means of a bilinear transformation, then the z data is fitted w.r.t. a bivariate polynomial constructed on the basis

\{1,x,y,xy,x^2,y^2,xy^2, x^2y, x^2y^2,y^3,y^4\}

You can try other basis but be warned about overfitting ! With the above model the fit is not bad at all

    x      y      z      fitted       error  
   ____   ___   _____   _________   _________
                                             
   2.57   5     2.04    2.0029712   0.0370288
   2.57   6.5   3.71    3.9171544   0.2071544
   2.57   7     4.785   4.6055525   0.1794475
   2.57   10    6.285   6.2935451   0.0085451
   2.57   12    7.285   7.2857768   0.0007768
   2.96   5     3       3.0398772   0.0398772
   2.96   6     4.3     4.2252302   0.0747698
   2.96   8     8       8.0498465   0.0498465
   2.96   10    11.84   11.825046   0.014954 
   3.18   5     3.31    3.31        4.441D-16
   3.18   6.5   5.64    5.64        0        
   3.18   9     12.19   12.19       0   

and the reconstructed data has no artifact:


I am sorry for the length of the code, but contour lines and pseudo-color plot on a general (non rectangular) mesh are not an easy task in Scilab. Functions to be used are typically: mesh2d for the generation of the structured triangular mesh, fec for the pseudo-color plot, and contour2dm which only computes the contour lines (they have to be drawn and labeled by the user himself):

function mat = model(x,y)
    mat = [ones(x) x y x.*y x.^2 y.^2 x.^2.*y y.^2.*x x.^2.*y.^2 y.^3 y.^4];
endfunction

data=[2.57	5	2.04
2.57	6.5	3.71
2.57	7	4.785
2.57	10	6.285
2.57	12	7.285
2.96	5	3.00
2.96	6	4.30
2.96	8	8.00
2.96	10	11.84
3.18	5	3.31
3.18	6.5	5.64
3.18	9	12.19];

x=data(:,1);
y=data(:,2);
z=data(:,3);

// limits of the (x,y) domain
ymin = 5;
ymax1 = 12;
ymax2 = 9;
xmin = 2.57;
xmax = 3.18;

A = model(x-xmin,y-ymin);
coeffs = A\z;

tab = table([x y z A*coeffs abs(z-A*coeffs)], ...
    "VariableNames",["x","y","z","fitted","error"]);
disp(tab)

// create trapezoidal mesh with a bilinear transformation
[u,v]=meshgrid(0:0.01:1);
tri = mesh2d(u, v);
X = xmin+u*(xmax-xmin);
Y = ymin+v*(ymax1-ymin)+u.*v*(ymax2-ymax1);
X = X(:);
Y = Y(:);
// reconstruct data on mesh
Z = model(X-xmin,Y-ymin)*coeffs;

scf(0)
clf
// change nc set the number of colors/contour lines
nc=11;
// change vmin and vmax to set the first and the last contour line
vmin=2.1;
vmax=13;

gcf().color_map=spring(nc);

// pseudo color plot on mesh
polygons = [1:size(tri,2); tri; ones(1,size(tri,2))]';
fec(X,Y,polygons,Z,zminmax=[vmin vmax],colminmax=[1 nc-1]);
colorbar(vmin,vmax,[1 nc-1]);

// compute and plot contour lines on color plot
[xc, yc] = contour2dm(X,Y,polygons,Z,linspace(vmin,vmax,nc))

k=1;n=yc(k);
while k<size(xc,'*')
  n=yc(k);
  value = xc(k);
  xd = xc(k+(1:n));
  yd = yc(k+(1:n));
  plot(xd,yd,'k')
  [y_max,ind] = max(yd);
  xstring(xd(ind),yd(ind),msprintf("%5.2f",value)) 
  k=k+n+1;
end

Now it worked, thank you!!

Don’t hesitate to test other simpler polynomial basis, considering the maximum error that you may accept.

S.