Skip to content

Home / DOE / Charts / Contour Plot / Math Details

Math Details

This page gives the values a contour plot draws and how each one is formed: where the grid points sit, what number each one carries, how the contoured value axis is chosen, and which cells of a grid report are drawn at all.

One engine builds the Contour Plot and the Surface Plot. The two compute the same numbers from the same inputs. A contour is that grid of heights seen from directly above, with lines joining equal values, and the only arithmetic difference between the two pages is that a contour refuses a categorical axis, so several cases the surface page has to describe cannot arise here.

Notation

Term Description
\(A\) the factor on the horizontal axis, which the product calls Factor1
\(B\) the factor on the series axis, Factor2
\(A_{\text{lo}}\), \(A_{\text{hi}}\) the From and to values of \(A\)'s plotted range
\(B_{\text{lo}}\), \(B_{\text{hi}}\) the same two values for \(B\)
\(M\) the number of positions on each axis, fixed at \(41\)
\(u_i\) the \(i\)th position along \(A\), for \(i = 0, 1, \dots, M - 1\)
\(v_m\) the \(m\)th position along \(B\), for \(m = 0, 1, \dots, M - 1\). The index letter \(m\) is used because \(j\) below belongs to the model term
\(t_k\) the set point typed or picked for factor \(k\)
\(\mathbf{z}\), \(z_k\) the vector of factor settings handed to the prediction equation, and its entry for factor \(k\)
\(\hat{y}_{im}\) the contoured value at \((u_i, v_m)\): a fitted response on the response level, a fitted standard deviation on the standard deviation level, a fitted probability on a binary or nominal level
\(c_j\), \(b_j\) the coded value and the coefficient of model term \(j\)
\(\hat{y}_{\min}\), \(\hat{y}_{\max}\) the smallest and the largest value on one chart
\(\Delta\) the tick spacing of the value axis
\(r\) the rounded range the value axis is built from
\(\hat{y}_{\text{low}}\), \(\hat{y}_{\text{high}}\) the two ends of the value axis
\(n\) the number of ticked factors in a grid report

Where the grid points sit

Every position is computed, not read from the runs. This is the deepest difference between this chart and the interaction family, which puts its points only at settings the experiment actually visited. A contour sweeps its two axes across a range and predicts at every intersection, so most of its points sit at factor settings no run ever used.

Both axes of a contour are quantitative, and each carries 41 positions. The count is fixed in the engine and no dialog control changes it. The positions are evenly spaced from the From value to the to value inclusive, which is 40 steps between them:

\[ M = 41, \qquad u_i = A_{\text{lo}} + i \cdot \frac{A_{\text{hi}} - A_{\text{lo}}}{M - 1}, \qquad i = 0, 1, \dots, M - 2 \]
\[ u_{M - 1} = A_{\text{hi}} \]

The last position is assigned rather than computed, so the top of the range is exactly the number you typed, with no rounding drift. Every other position is the low value plus a whole multiple of the step, formed by multiplication rather than by adding the step repeatedly, so the positions can be reproduced one at a time without accumulating error. The series axis is built the same way from \(B_{\text{lo}}\) and \(B_{\text{hi}}\).

So one contour chart is always \(41 \times 41 = 1681\) predictions. Unlike a surface, which can take a categorical series axis and then carries one position per level, a contour has no such case: the dialog offers only quantitative factors to its two pickers and a grid cell involving a categorical factor is left undrawn.

The value at a grid point

The engine takes the set points as they stand, overwrites the two entries belonging to the plotted factors with that point's own position, and hands the result to the prediction equation:

\[ z_k = \begin{cases} u_i, & k = A \\ v_m, & k = B \\ t_k, & \text{otherwise} \end{cases} \]

The set points of \(A\) and \(B\) are overwritten before every prediction, so they are never read on this chart. In the single-pair layout the dialog hides those two rows for exactly that reason. In a grid report the rows stay visible and stay editable, because a factor that is an axis in one cell is held in every cell that does not plot it.

The vector is copied afresh for each chart, and only that chart's own two entries are replaced. In a grid report that means one set-point box can move most of the sheet and leave a few cells alone: the factor is swept on the cells that plot it and held at its set point everywhere else.

Each entry is then coded, and the coded values are combined with the coefficients already on the regression sheet:

Every quantitative factor is put on a common scale before the regression runs. One expression does it, whichever coding is in force, using a centre \(m_c\) and a scale \(s_c\) that the coding chooses:

\[ x_{\text{coded}} = \frac{x - m_c}{s_c} \]

A categorical factor is never coded this way. Its coded value is \(1\), and the level it sits at selects which coefficient is used instead.

An interaction's coded value is the product of the coded values of the factors in it.

A prediction is the sum, over every term in the model, of that term's coded value times its coefficient:

\[ \hat{y} = \sum_{j} c_j \, b_j \]

where \(c_j\) is the coded value of term \(j\) at the settings you asked about and \(b_j\) is its coefficient from the regression table. The constant term has \(c_j = 1\), so its coefficient enters as itself.

A term that is absent from the regression table, or switched off for the level being predicted, contributes \(b_j = 0\).

For a binary output the same sum is formed and passed through the logistic function:

For a binary output the same sum is formed first, then passed through the logistic function to give a probability:

\[ p = \frac{1}{1 + e^{-\sum_j c_j b_j}} \]

That is the probability of the first level. The probability of the second is \(1 - p\).

For a nominal output there is one sum per level:

For a nominal output with \(L\) non-reference levels there is one sum per level, \(\eta_k = \sum_j c_j b_{jk}\), and the probability of level \(k\) is

\[ p_k = \frac{e^{\eta_k}}{1 + \sum_{l=1}^{L} e^{\eta_l}} \]

The \(1\) in the denominator is the reference level, whose \(e^{\eta}\) is \(1\) by construction. So the reference level's own probability is

\[ p_{\text{ref}} = \frac{1}{1 + \sum_{l=1}^{L} e^{\eta_l}} \]

and the probabilities across all levels sum to \(1\).

Which coefficients are used follows the level you ticked. On a quantitative output the Y-Hat level reads the response model's coefficients and the S-Hat level reads the standard deviation model's, so on that level the contour lines are lines of equal fitted standard deviation. The set-point vector, the coding and the sum are the same either way.

A held factor left at its default set point codes to zero under Autocode. The set-point box opens at the midpoint of the factor's own low and high, and Autocode centres its coding on that same midpoint, so the default value makes the factor's coded entry exactly \(0\) and drops its term, and every interaction it appears in, out of the sum. Under Standardize the coding is centred on the mean of the observed values instead, which is the midpoint only on a symmetric design, so the same box left alone does not generally code to zero. See Design Coding.

Where the contour lines fall

The engine computes no contour lines. It computes the 1681 values and writes them onto the worksheet as a 41 by 41 block, one row per position of \(B\) and one column per position of \(A\), and Excel draws the bands from that block. So a contour line is a path through grid values rather than an exact solution of the fitted equation. It follows the fit closely where the fit changes gently and becomes visibly angular only where the fit changes fast relative to the spacing of the 41 positions.

Narrowing the two ranges puts the same 41 positions across a smaller span and so draws smoother lines over that region. It does not add resolution to the region you left out.

The value axis

The axis is computed from the chart's own grid and no other. The engine takes the smallest and the largest of that chart's 1681 values and rounds them out to nice numbers. A grid report therefore gives every cell its own value axis, computed from that cell alone, and the bands of two cells on one sheet are not to be read against each other by eye. This is the opposite of the interaction family, whose charts share one value axis across the sheet, and it is the opposite of the Trellis, which deliberately forces one shared scale onto all of its panels.

The ends are chosen by rounding to a nice number. Write

\[ e = \lfloor \log_{10} r \rfloor, \qquad \phi = \frac{r}{10^{e}}, \qquad \mathrm{nice}(r) = f \cdot 10^{e} \]

where \(e\) is the base ten exponent of \(r\), \(\phi\) is its leading fraction, and \(f\) is a nice fraction read from \(\phi\) by one of two tables. Rounding to the nearest takes \(f = 1, 2, 5, 10\) as \(\phi\) falls below \(1.5\), below \(3\), below \(7\), or higher; rounding up takes \(f = 1, 2, 5, 10\) as \(\phi\) is at most \(1\), at most \(2\), at most \(5\), or higher. The range is rounded up and the tick spacing to the nearest:

\[ r = \mathrm{nice}_{\text{up}}\left(\hat{y}_{\max} - \hat{y}_{\min}\right), \qquad \Delta = \mathrm{nice}_{\text{near}}\!\left(\frac{r}{10}\right) \]
\[ \hat{y}_{\text{low}} = \Delta \left\lfloor \frac{\hat{y}_{\min}}{\Delta} \right\rfloor, \qquad \hat{y}_{\text{high}} = \Delta \left\lceil \frac{\hat{y}_{\max}}{\Delta} \right\rceil \]

Three guards follow. A range below \(10^{-5}\) is replaced by the largest power of ten not exceeding the larger of \(\lvert \hat{y}_{\min} \rvert\) and \(\lvert \hat{y}_{\max} \rvert\), and failing that by \(10^{-5}\), so a flat fit still gets an axis. An end that rounding moved inside the data is pulled back to the data, so the axis can never cut off a plotted value. And if the two ends come out equal, each of them is moved by \(r/2\), the low end down and the high end up.

\(\hat{y}_{\text{low}}\) and \(\hat{y}_{\text{high}}\) are then written onto the chart as the value axis minimum and maximum, and the axis is made to cross at \(\hat{y}_{\text{low}}\).

The tick spacing that reaches the chart is not \(\Delta\). \(\Delta\) is used to place the two ends and then dropped. What is written as the major unit is the finished span divided by ten:

\[ \text{major unit} = \frac{\hat{y}_{\text{high}} - \hat{y}_{\text{low}}}{10} \]

so the value axis always carries ten intervals between \(\hat{y}_{\text{low}}\) and \(\hat{y}_{\text{high}}\), whatever the data. The rule is applied to every contour without exception. It has one exception on a surface, described on the Surface Plot Math Details page.

The chart is drawn with a legend, on the right. What the engine writes is the axis span, the major unit and the grid of values; how many shaded bands Excel then renders from them is Excel's, and the code sets nothing else about it.

The axis labels

The two factor axes are labelled from the positions themselves, written with the product's nice-number formatting. Both factor axes and the value axis carry the General number format, so the number of decimals shown is Excel's.

The engine does compute a decimal count for each of the three axes, but nothing in the drawing code reads them. They reach the report structure and stop there.

Cells that are not drawn

In a grid report the ticked factors are laid out as an \(n\) by \(n\) square. The diagonal carries factor names rather than charts, and each off-diagonal cell is the ordered pair with the column's factor on the horizontal axis and the row's factor on the series axis, so \(n\) ticked factors give \(n(n-1)\) charts.

A cell is written as NA rather than a chart when its pair fails the axis rule:

  • On a contour grid both factors must be quantitative. One categorical factor is enough to make a cell NA, so a ticked categorical factor leaves a whole row and a whole column undrawn.
  • The block is categorical for this purpose, always, so ticking it onto a contour grid adds a row and a column of NA and nothing else.

Every drawn cell is the same compute as the single chart for that pair. The grid calls the per-pair engine once per valid cell with the same set points and the same ranges, so a cell and a single chart of the same pair hold the same numbers.

A grid cell always uses the factor's own experimental range. The From and to boxes belong to the single-pair layout, so a grid sweeps each axis from the lowest to the highest value that factor took in the data.

What the heading block reports

Above the chart the engine writes the chart type, the name of the regression sheet the coefficients came from, the output level, and a Constant values: line listing each held factor as name and value, separated by semicolons. A quantitative value is written with the nice-number formatting; a categorical one is written as the level's own value. The block's entry is named block, spelled lower case as the product spells it, and its value is the block number, which is the level index plus one.

A grid report lists only the factors that are not on the grid at all. A ticked factor is held constant in the cells that do not plot it, but it is not on the constants line, because it is not constant across the sheet.

Shared Math Details used here

This chart uses shared formulas defined once in Shared Math Details. See those pages for the exact definitions.

Shared concept Used here for Reference
Prediction equation the value at every grid point Prediction Equation
Design coding turning an axis position or a set point into the coded value the prediction uses Design Coding

See Also

References

  1. Montgomery, D. C. (2013). Design and Analysis of Experiments, 8th edition. Wiley.
  2. Heckbert, P. S. (1990). Nice Numbers for Graph Labels. In A. S. Glassner (Ed.), Graphics Gems. Academic Press.