Skip to content

How To Contour Plot

David Hägele edited this page Mar 24, 2021 · 5 revisions

How To Create a Contour Plot

Here is a short example on how to create and display a contour plot, aka isolines.

// formulate bivariate function that defines the 2D surface
DoubleBinaryOperator bivariateFn = (x,y)->(x*y + x*x - y*y -.01);
// sample the function
int hsamples=100, vsamples=100;
double[][] X = new double[vsamples][hsamples];
double[][] Y = new double[vsamples][hsamples];
double[][] Z = new double[vsamples][hsamples];
for(int i=0; i<vsamples; i++){
   for(int j=0; j<hsamples; j++){
      double x=j*1.0/(hsamples-1), y=i*1.0/(vsamples-1);
      x=x*2-1; y=y*2-1; /* range[-1,1] */
      X[i][j]=x; 
      Y[i][j]=y;
      Z[i][j]=bivariateFn.applyAsDouble(x,y);
   }
}
// define colors for isoline levels (3 levels)
ColorMap colormap = DefaultColorMap.D_COOL_WARM;
int[] colors = colormap.resample(3, 0, 1).getColors();
// calculate contour lines from samples for iso values -0.5, 0.0 and 0.5
List<SegmentDetails> contourA = Contours.computeContourLines(
      X,Y,Z, -0.5, colors[0]);
List<SegmentDetails> contourB = Contours.computeContourLines(
      X,Y,Z,  0.0, colors[1]);
List<SegmentDetails> contourC = Contours.computeContourLines(
      X,Y,Z,  0.5, colors[2]);
// put the contour segments into a Lines object
Lines contourlines = new Lines();
contourlines.getSegments().addAll(contourA);
contourlines.getSegments().addAll(contourB);
contourlines.getSegments().addAll(contourC);
// calculate contour bands in between lines
List<TriangleDetails> bandAB = Contours.computeContourBands(
      X,Y,Z, -0.5,0.0, colors[0],colors[1]);
List<TriangleDetails> bandBC = Contours.computeContourBands(
      X,Y,Z,  0.0,0.5, colors[1],colors[2]);
// put the band triangles into a Triangles object
Triangles contourbands = new Triangles();
contourbands.setGlobalAlphaMultiplier(0.3);
contourbands.getTriangleDetails().addAll(bandAB);
contourbands.getTriangleDetails().addAll(bandBC);
// use a coordinate system for display
CoordSysRenderer coordsys = new CoordSysRenderer();
coordsys.setCoordinateView(-1,-1,1,1);
// set the content renderer of the coordinate system 
// we want to render Lines and Triangles objects
CompleteRenderer content = new CompleteRenderer();
content.addItemToRender(contourbands).addItemToRender(contourlines);
coordsys.setContent(content);

// display within a JFrame
JFrame frame = new JFrame();
boolean useOpenGL = true;
JPlotterCanvas canvas = useOpenGL ? new BlankCanvas() : new BlankCanvasFallback();
canvas.setRenderer(coordsys);
canvas.asComponent().setPreferredSize(new Dimension(400, 400));
canvas.asComponent().setBackground(Color.WHITE);
frame.getContentPane().add(canvas.asComponent());
frame.setTitle("contourplot");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
canvas.addCleanupOnWindowClosingListener(frame);
// make visible on AWT event dispatch thread
SwingUtilities.invokeLater(()->{
   frame.pack();
   frame.setVisible(true);
});

The contour bands currently show a linear color gradient with 1 stop in the middle, but the color map in use has many more stops. In order to show colormap compliant contour bands, we need to create them a little different.

/* we cheated a bit before when creating the contour bands,
 * we assumed the colormap to be linear and just used the
 * 3 colors we extracted. Since the color map is not linear
 * we need to calculate bands for each step of the map so that
 * its color scheme is preserved.
 */
double loIso=-0.5, hiIso=0.5;
List<TriangleDetails> tris = new LinkedList<>();
for(int i=0; i<colormap.numColors()-1; i++){
   double m1 = colormap.getLocation(i);
   double m2 = colormap.getLocation(i+1);
   // calc iso values corresponding to locations in color map
   double iso1 = loIso+m1*(hiIso-loIso);
   double iso2 = loIso+m2*(hiIso-loIso);
   int color1 = colormap.getColor(i);
   int color2 = colormap.getColor(i+1);
   tris.addAll(Contours.computeContourBands(X,Y,Z, iso1, iso2, color1, color2));
}
// replace triangles
contourbands.removeAllTriangles();
contourbands.getTriangleDetails().addAll(tris);
canvas.scheduleRepaint();
Clone this wiki locally