Simple? surface plot question

I'm trying to work out how to do a surface plot, but I'm not sure how to go about it. The data from which I want to create the surface is as follows.

I have variable A plotted against variable B. Variable A's values (independent) are stored in one column. Variable B's values are the dependant ones. They are stored in a dozen columns, each column calculated from variable A for a particular value of (independent) variable C.

The simple 2D plot consists of a series of plots of A vs B, each curve corresponding to a value of C.

How can I fit a surface to these curves?

The help file says this:

2D Waves: Sometimes called "matrix of z-values", these are M rows by N columns waves where each entry represents a scalar z-value. You can apply wave scaling (see SetScale) to associate an X value with every row and a Y value with each column.

I can concatnate the columns of B data into a Z-wave, but I don't know how to use wave scaling to associate an X value with rows (from variable A?) and a Y value with the columns (from variable C?). If that's what I should be doing?

Thanks

DN
Hello DN,

I'm not a big fan of the "dependent" terminology and before we start building surfaces we need to make sure that there is some significance to connecting between point i in column j and point i in column (j+1). If that is not the case then your options are to use a waterfall plot or a set of path plots in 3D.

If your data should be plotted as a surface and if each column represents samples that are taken at equal intervals along each one of the axes you can apply wave scaling to the concatenated wave. You can do that programmatically using the SetScale operation or by going to Data Menu->Change Wave Scaling. Once you applied wave scaling you can simply select the concatenated wave in the Data Browser and choose Gizmo Plot from the contextual menu (right-click on Windows or Ctrl-click on Macintosh).

If you are having difficulty understanding these concepts feel free to contact me directly.

A.G.
WaveMetrics, Inc.
I interpret your description to mean that your data wave "A" is like the X data, "C" is like the Y data, and "B" is like the Z data. There are several kinds of ways to plot this data, including Surface Plots, Contour Plots, and Image Plots.

An image plot is the simplest, but usually requires that your X and Y data be evenly spaced. You say that you have a dozen columns, which I take to mean you already have a 2D wave (matrix) of the data (the B values), which I will assume is called "B". In that case, you want to scale the B wave to match the scaling of the A and C data. This means that if the A values are {3,5,7,9,10} and the C values are {1.0,1.1,1.2,1.3,1.4,1.5}, you would do:

SetScale /p x,3,2,B // The first row of the B matrix will have an index of 3, with each subsequent row and index of 2 more.  
SetScale /p y,1,0.1,B // Ditto for the columns of B.  
NewImage B // Makes an image plot of B.  The colors correspond to the B data, and the axis values correspond to the scaling you just applied.  


A contour plot can be done even if your X and Y data are not evenly spaced:
Display
AppendMatrixContour B vs {A,C}


If they are evenly spaced, you can also just do something similar to what we did with the Image Plot:
SetScale /p x,3,2,B // The first row of the B matrix will have an index of 3, with each subsequent row and index of 2 more.  
SetScale /p y,1,0.1,B // Ditto for the columns of B.  
Display
AppendMatrixContour B


Surface plots are the trickiest. If the Gizmo and Surface Plot XOPs are already installed (they should be in a recent version of Igor), you can use a graphical interface to make your surface plot, which will help you learn the commands:
SetScale /p x,3,2,B // The first row of the B matrix will have an index of 3, with each subsequent row and index of 2 more.  
SetScale /p y,1,0.1,B // Ditto for the columns of B.
CreateSurfer
// Then click source, "Matrix of Z-values" and pick your wave B.  Click "Do It", and check "Always Update".  


You can then export a surface plot to Gizmo, which uses OpenGL to give your an incredibly versatile graphics engine, at the expense of being tricky to use.

Update:
It may be easier and better to use Gizmo directly:
SetScale /p x,3,2,B // The first row of the B matrix will have an index of 3, with each subsequent row and index of 2 more.  
SetScale /p y,1,0.1,B // Ditto for the columns of B.
NewGizmo
AppendToGizmo defaultSurface=B


Rick
dcnicholls wrote:
I can concatnate the columns of B data into a Z-wave, but I don't know how to use wave scaling to associate an X value with rows (from variable A?) and a Y value with the columns (from variable C?). If that's what I should be doing?


Each 1D wave has an internal x0 and dx properties. These properties are set using the SetScale operation and are used to map a point number to a computed X value: x = x0 + dx*pointNumber. Choose File->Example Experiments->Tutorial->X Scaling Tutorial for a demonstration or see "Waves - The Key Igor Concept" at the start of the Getting Started help file.

Each 2D wave has internal x0, dx, y0 and dy properties from which Igor computes X values and Y values.

If your X and Y values are evenly-spaced then you can use wave scaling. Choose Data->Change Wave Scaling to generate the required SetScale commands.

If your X and Y values are not evenly-spaced then you can not use wave scaling.

Quote:
How can I fit a surface to these curves?


If you select a multi-variate curve-fitting function and a 2D wave as your data, Curve Fitting dialog allows you to choose _calculated_ or an explicit wave for both your X and Y values. _calculated_ means "use the X or Y values calculated from the wave scaling properties".

Given a 5x5 2D wave named mat, a 5-point 1D wave named xData and a 5-point 2D wave named yData, I am able to generate the following command using the Curve Fitting dialog:
CurveFit Gauss2D mat /X=xData /Y=yData /D


If you are still stuck, send an experiment with your data to support@wavemetrics.com.

Igor wrote:

I'm not a big fan of the "dependent" terminology and before we start building surfaces we need to make sure that there is some significance to connecting between point i in column j and point i in column (j+1).


Yes, that is the case. The values in row i in consecutive columns differ only in the value of C used to calculate them.

Quote:
If your data should be plotted as a surface and if each column represents samples that are taken at equal intervals along each one of the axes you can apply wave scaling to the concatenated wave. You can do that programmatically using the SetScale operation or by going to Data Menu->Change Wave Scaling. Once you applied wave scaling you can simply select the concatenated wave in the Data Browser and choose Gizmo Plot from the contextual menu (right-click on Windows or Ctrl-click on Macintosh).


The data are calculated, not observed, so the spacing is even.

Actually the equation is:

B = log(InverseErf(C)/k1 - k2) + k3 + 2*log(A)

with B plotted against A for a range of C values (the k's are constants).

I tried the process and I think I'm getting somewhere. Certainly this has opened a few more doors, although I'm still blundering around a bit :-)

That's the best way to learn!

Thanks.
A further question, following from the above equation,
B = log(InverseErf(C)/k1 - k2) + k3 + 2*log(A)

A and C are equal size column vectors.

How do I calculate a 2D matrix B such that

B(i,j) = log(InverseErf(C(j))/k1 - k2) + k3 + 2*log(A(i))

for all i, j?

Do I need to do that in a loop? Along the lines of

for j= 0 to jmax
for i= 0 to imax
B(i,j) = log(InverseErf(C(j))/k1 - k2) + k3 + 2*log(A(i))
next i
next j

DN
OK, the for loop works:

Function mH(m1, c1, d1)
Wave m1, c1, d1
Variable i, j
for(j=0;j<128;j+=1)
for(i=0;i<128;i+=1)
m1[i][j] = log(InverseErf(c1[j])/0.12 -6.4) + 5.371 +2*log(d1[i])
endfor
endfor
End

but is there a more elegant way to do it?
dcnicholls wrote:
but is there a more elegant way to do it?


Yes:
Function mH(m1, c1, d1)
  Wave m1, c1, d1
  m1 = log(InverseErf(c1[q])/0.12 -6.4) + 5.371 +2*log(d1[p]) // Here I assume you want to iterate over all rows and column of m1.  If you only want to go to [0,127] (and there are more than 128 rows and columns), do m1[0,127][0,127]=...
End


"p" and "q" are a shortcut for accessing the row and column indices of the left-hand side. This allows you to do wave assignments that would otherwise require a loop.

Rick
RGerkin wrote:


"p" and "q" are a shortcut for accessing the row and column indices of the left-hand side. This allows you to do wave assignments that would otherwise require a loop.

Rick


Splendid! Thanks.

DN
Quote:
"p" and "q" are a shortcut for accessing the row and column indices of the left-hand side. This allows you to do wave assignments that would otherwise require a loop.


For an explanation of this feature:

DisplayHelpTopic "Waveform Arithmetic and Assignment"
hrodstein][quote wrote:
"p" and "q" are a shortcut for accessing the row and column indices of the left-hand side. This allows you to do wave assignments that would otherwise require a loop.


Thanks. I used the command line version of the equation rather than as a function and it worked perfectly (in fact I have now inverted the equation with c as the calculated matrix).

It is certainly a lot neater than writing a set of for loops. I knew Igor had to have a clean way to do the calculation, but didn't know what to look for.

DN