IMSL C# Programmers Guide
|
2D Drawing Elements >> AxisXY >> Custom Transform |
Custom Transform
A custom transformation allows a user-defined mapping of data to an axis. A
custom transform is used when the Transform
attribute has the value
TRANSFORM_CUSTOM
. The custom transform is the value of the
CustomTransform
attribute.
A custom transform implements the Transform
interface. This interface has three
methods. One, SetupMapping
, is called first to allow the transformation to initialize
itself. The other two, MapUserToUnit
and MapUnitToUser
, specify a
mapping from the window interval onto [0,1]
. These methods must each be the
inverse of the other.
Example: Normal Probability Plot
A normal probability plot maps normally distributed data into a straight line, just as a semilog plot maps exponential data into a straight line.
In this example, 400 normally distributed random numbers are grouped into 20 bins. The bin counts are normalized by dividing by the number of samples (400). Cumulative probabilities are computed by summing the probabilities in all of the bins to the left of the current bin.
The custom transformation is the normal cumulative distribution function,
Cdf.Normal
, and its inverse, Cdf.InverseNormal
, scaled to map the probability
range [0.001,0.999]
onto [0,1]
.
Autoscaling is turned off on the probability (y) axis and a fixed set of probability tick marks are specified.
The plot is of the bin center on the x-axis versus the cumulative probabilities on the y-axis. The points are not in an exactly straight line because with only a finite number of samples, the distribution does not exactly match the normal distribution.
(Download Code)
using Imsl.Chart2D; using Imsl.Stat; using System.Drawing; public class SampleProbability : FrameChart { public SampleProbability() { Chart chart = this.Chart; AxisXY axis = new AxisXY(chart); double[] ticks = {0.001, 0.005, 0.01, 0.02, 0.05, 0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90, 0.95, 0.98, 0.99, 0.995, 0.999}; double a = ticks[0]; double b = ticks[ticks.Length-1]; axis.AxisX.AxisTitle.SetTitle(x); axis.AxisY.AxisTitle.SetTitle(Probability); axis.AxisY.Transform = Axis.TRANSFORM_CUSTOM; axis.AxisY.CustomTransform = new NormalTransform(); axis.AxisY.AutoscaleInput = Axis.AUTOSCALE_OFF; axis.AxisY.SetWindow(a, b); axis.AxisY.TextFormat = 0.000; axis.AxisY.SetTicks(ticks); axis.AxisY.MinorTick.IsVisible = false; int nSamples = 400; int nBins = 20; // Setup the bins double[] bins = new double[nBins]; double dx = 6.0/nBins; double[] x = new double[nBins]; for (int k = 0; k < x.Length; k++) { x[k] = -3.0 + (k+0.5)*dx; } // Generate random normal deviates and sort into bins Random r = new Random(123457); for (int k = 0; k < nSamples; k++) { double t = r.NextNormal(); int j = (int)System.Math.Round((t+3.0-0.5*dx)/dx); if (j <= 0) { bins[0]++; } else if (j >= nBins-1) { bins[nBins-1]++; } else { bins[j]++; } } // Compute the cumulative distribution // y[k] is the sum of bins[j] for j=0,...,k divided by the nSamples. double[] y = new double[nBins]; y[0] = bins[0]/nSamples; for (int k = 1; k < nBins; k++) { y[k] = y[k-1] + bins[k]/nSamples; } // Plot the data using markers Data data = new Data(axis, x, y); data.DataType = Data.DATA_TYPE_MARKER; data.MarkerType = Data.MARKER_TYPE_FILLED_CIRCLE; data.MarkerColor = Color.Blue; } public static void Main(string[] argv) { System.Windows.Forms.Application.Run(new SampleProbability()); } } class NormalTransform : Transform { private double scaleA, scaleB; // Initializes the mappings between user and coordinate space. public void SetupMapping(Axis1D axis1d) { double[] w = axis1d.GetWindow(); double t = Cdf.InverseNormal(w[0]); scaleB = 1.0 / (Cdf.InverseNormal(w[1]) - t); scaleA = -scaleB * t; } // Maps a point in [0,1] to a probability. public double MapUnitToUser(double unit) { return Cdf.Normal((unit - scaleA) / scaleB); } // Maps a probablity to the interval [0,1]. public double MapUserToUnit(double p) { return scaleA + scaleB * Cdf.InverseNormal(p); } }
© Visual Numerics, Inc. All rights reserved. |