Derivatives : Math Functions « Advanced Graphics « Java






Derivatives

Derivatives
/*************************************************************************
*                                                                        *
*  This source code file, and compiled classes derived from it, can      *
*  be used and distributed without restriction, including for commercial *
*  use.  (Attribution is not required but is appreciated.)               * 
*                                                                        *
*   David J. Eck                                                         *
*   Department of Mathematics and Computer Science                       *
*   Hobart and William Smith Colleges                                    *
*   Geneva, New York 14456,   USA                                        *
*   Email: eck@hws.edu          WWW: http://math.hws.edu/eck/            *
*                                                                        *
*************************************************************************/


// Draws the graph of a function and its first derivative (and optionally
// its second derivative).  It shows the tangent line to the graph and
// marks the corresponding point on the graph of the derivative.  The
// user controls the position of the tangent line with a slider and/or
// a number-input box.  A formula for the derivative can be displayed 
// at the bototm of the applet.

import java.awt.*;
import java.awt.event.*;
import java.applet.Applet;
import java.util.StringTokenizer;
import edu.hws.jcm.draw.*;
import edu.hws.jcm.data.*;
import edu.hws.jcm.functions.*;
import edu.hws.jcm.awt.*;


public class Derivatives extends GenericGraphApplet {

   private String functionName;  // name of the fuction beging graphed, 'f' by default; used in labels etc
   private Function func;   // The function that is graphed.
   private Function deriv;         // derivative of func
   private Expression derivExpression;  // The Expression that defines the derivative
   private Function deriv2;        // if non-null, second derivative of func
   private Controller subController = new Controller();  // Respond to changes in x-coord input; won't redraw graph

   private VariableInput xInput; // x-coord of point of tangency
   
   private class ExprLbl extends Label implements Computable {
          // A class for displaying the formula for deriv
      String label;
      ExprLbl(String label) {
         this.label = label;
         compute();
      }
      public void compute() {
         setText(label + derivExpression.toString());
      }
   }
   
   protected void setUpParameterDefaults() { // I don't want to use abs(x)^x as the default function, since it's derivative is so funny
      parameterDefaults = new java.util.Hashtable();
      parameterDefaults.put("Function", " tan(" + getParameter("Variable","x") + ")");
   }
   
   protected void setUpMainPanel() {  // add a bunch of extra components at the end
      super.setUpMainPanel();
      
      // now that limitsPanel has been set up, add the two extra coordinate rects to it
      
      if (limitsPanel != null) {
         limitsPanel.addCoords(canvas.getCoordinateRect(1));  
         if (deriv2 != null)
            limitsPanel.addCoords(canvas.getCoordinateRect(2));  
      }
      else {  // CoordinateRects must synchronize with each other
         Tie coordTie = new Tie(canvas.getCoordinateRect(0),canvas.getCoordinateRect(1));
         if (deriv2 != null)
            coordTie.add(canvas.getCoordinateRect(2));
         canvas.getCoordinateRect(0).setSyncWith(coordTie);
         canvas.getCoordinateRect(1).setSyncWith(coordTie);
         if (deriv2 != null)
            canvas.getCoordinateRect(2).setSyncWith(coordTie);
      }
      
      
      // Add controls at the bottom of the panel for setting the value of x.
      // Also add the derivative formula, if it's supposed to be displayed
   
      Value xMin = canvas.getCoordinateRect().getValueObject(CoordinateRect.XMIN);
      Value xMax = canvas.getCoordinateRect().getValueObject(CoordinateRect.XMAX);
      canvas.getCoordinateRect().setOnChange(subController);
      VariableSlider xSlider = new VariableSlider(xMin,xMax);
      xSlider.setOnUserAction(subController);
      xInput.setOnTextChange(subController);
      subController.add(xSlider);
      subController.add(xInput);
      subController.add( new Tie(xSlider,xInput) );
      
      Panel p = new Panel();
      p.setLayout(new BorderLayout(5,5));
      p.add(xInput.withLabel(), BorderLayout.WEST);
      p.add(xSlider, BorderLayout.CENTER);
      
      // If there is no limits panel, make it possible to add a RestoreLimits button to the input panel
      
      if (limitsPanel == null && ! "no".equalsIgnoreCase(getParameter("UseRestoreButton","no"))) {
               // add button to left of slider
           Button res = new Button("Restore Limits");
           p.add(res, BorderLayout.EAST);
           res.setBackground(Color.lightGray);
           res.addActionListener( new ActionListener() {
                   public void actionPerformed(ActionEvent evt) {
                      canvas.getCoordinateRect(0).restore();
                      canvas.getCoordinateRect(1).restore();
                      if (deriv2  != null) 
                         canvas.getCoordinateRect(2).restore();
                   }
              });
      }

      if ("yes".equalsIgnoreCase(getParameter("ShowFormula", "yes"))) { // add derivative formula
         Panel s = new Panel();
         s.setLayout(new GridLayout(2,1,3,3));
         s.add(p);
         ExprLbl lbl = new ExprLbl(" " + functionName + "'(" + xVar.getName() + ") = ");
         mainController.add(lbl);
         s.add(lbl);
         p = s;
      }
      
      if (inputPanel == null) {
            // Add the control panel directly to the main panel
         p.setBackground(getColorParam("PanelBackground",Color.lightGray));
         mainPanel.add(p,BorderLayout.SOUTH);
      }
      else {
            // Add control panel to bottom of input panel.
         inputPanel.add(p,BorderLayout.SOUTH);
      }
      

   } // end setUpMainPanel


   protected void setUpCanvas() {  // Override this to add more stuff to the canvas.
                                   // I don't call super.setUpCanvas(), since
                                   // the canvas in this case is quite a bit different
                                   // from the standard one.

      boolean showSecond = ! "no".equalsIgnoreCase(getParameter("SecondDerivative","no"));

      xInput = new VariableInput(xVar.getName(), getParameter("X","1"));
      
      if (functionInput != null) {
         func = functionInput.getFunction(xVar);
         derivExpression = functionInput.getExpression().derivative(xVar);
      }
      else {
         String def = getParameter("Function");
         Expression exp = parser.parse(def);
         Function f = new SimpleFunction( exp, xVar );
         derivExpression = exp.derivative(xVar);
         func = new WrapperFunction(f);
      }
      Graph1D graph = new Graph1D(func);
      Color color = getColorParam("GraphColor",Color.black);
      graph.setColor(color);
      deriv = func.derivative(1);
      Graph1D derivGraph = new Graph1D(deriv);
      derivGraph.setColor(color);
      Graph1D deriv2Graph = null;
      if (showSecond) {
         deriv2 = deriv.derivative(1);
         deriv2Graph = new Graph1D(deriv2);
         deriv2Graph.setColor(color);
      }

      // Set up 2 or 3 coordinate retcs
      
      if (showSecond) {
         canvas.addNewCoordinateRect(0, 1.0/3.0, 0, 1);
         canvas.addNewCoordinateRect(1.0/3.0, 2.0/3.0, 0, 1);
         canvas.addNewCoordinateRect(2.0/3.0, 1, 0, 1);
      }
      else {
         canvas.addNewCoordinateRect(0, 0.5, 0, 1);
         canvas.addNewCoordinateRect(0.5, 1, 0, 1);
      }

      // do the type of stuff that's usually done in super.setUpCanvas
      
      color = getColorParam("CanvasColor");
      if (color != null)
         canvas.setBackground(color);
      if (! "no".equalsIgnoreCase(getParameter("UsePanner", "no")) ) {
         canvas.add(new Panner(),0);
         canvas.add(new Panner(),1);
         if (showSecond)
            canvas.add(new Panner(),2);
      }
      if ( ! "no".equalsIgnoreCase(getParameter("UseGrid", "no")) ) {
         Grid g = new Grid();
         color = getColorParam("GridColor");
         if (color != null)
            g.setColor(color);
         canvas.add(g,0);
         g = new Grid();
         color = getColorParam("GridColor");
         if (color != null)
            g.setColor(color);
         canvas.add(g,1);
         if (showSecond) {
            g = new Grid();
            color = getColorParam("GridColor");
            if (color != null)
               g.setColor(color);
            canvas.add(g,2);
         }
      }
      canvas.add(makeAxes(),0);
      canvas.add(makeAxes(),1);
      if (showSecond)
         canvas.add(makeAxes(),2);
      if ( ! "no".equalsIgnoreCase(getParameter("UseMouseZoom", "no")) )
         canvas.setHandleMouseZooms(true);
      if ( "yes".equalsIgnoreCase(getParameter("UseOffscreenCanvas", "yes")) )
         canvas.setUseOffscreenCanvas(true);
      mainController.setErrorReporter(canvas);
      mainPanel.add(canvas, BorderLayout.CENTER);
      
      // add graphs, tangent lines etc.
      
      canvas.add(graph,0);
      canvas.add(derivGraph,1);
      if (showSecond)
         canvas.add(deriv2Graph,2);
         
      Color tangentColor = getColorParam("TangentColor", Color.red);
      Color tangentColor2 = getColorParam("TangentColor2", new Color(0, 180, 0));
            
      mainController.remove(canvas);
      mainController.add(graph);
      mainController.add(derivGraph);
      if (showSecond)
         mainController.add(deriv2Graph);
      
      subController = new Controller();
      mainController.add(subController);
      
      TangentLine tan = new TangentLine(xInput, func);
      Crosshair cross = new Crosshair(xInput,deriv);
      tan.setColor(tangentColor);
      cross.setColor(tangentColor);
      canvas.add(tan, 0);
      canvas.add(cross, 1);
      subController.add(tan);
      subController.add(cross);
      
      if (showSecond) {
         tan = new TangentLine(xInput, deriv);
         cross = new Crosshair(xInput, deriv2);
         tan.setColor(tangentColor2);
         cross.setColor(tangentColor2);
         canvas.add(tan, 1);
         canvas.add(cross, 2);
         subController.add(tan);
         subController.add(cross);
      }

      functionName = getParameter("FunctionName", "f");

      String yName = getParameter("YName","y");
      Color textColor = getColorParam("TextColor",Color.black);
      Color bgColor = getColorParam("TextBackground",Color.white);
      DrawString str;
      
      if ("yes".equalsIgnoreCase(getParameter("ShowGraphLabels","yes"))) {
         str = new DrawString(yName + " = " + functionName + "(" + xVar.getName() + ")");
         str.setColor(textColor);
         str.setBackgroundColor(bgColor);
         str.setFrameWidth(1);
         canvas.add(str,0);
         str = new DrawString(yName + " = " + functionName + " ' (" + xVar.getName() + ")");
         str.setColor(textColor);
         str.setBackgroundColor(bgColor);
         str.setFrameWidth(1);
         canvas.add(str,1);
         if (showSecond) {
             str = new DrawString(yName + " = " + functionName + " ' ' (" + xVar.getName() + ")");
             str.setColor(textColor);
             str.setBackgroundColor(bgColor);
             str.setFrameWidth(1);
             canvas.add(str,2);
         }
      }
      if ("yes".equalsIgnoreCase(getParameter("ShowValues","yes"))) {
          str = new DrawString(functionName + "(#) = #", DrawString.BOTTOM_LEFT, new Value[] { xInput, new ValueMath(func,xInput) });
          str.setColor(textColor);
          str.setBackgroundColor(bgColor);
          str.setFrameWidth(1);
          str.setNumSize(7);
          canvas.add(str,0);
          subController.add(str);
          str = new DrawString(functionName + " ' (#) = #", DrawString.BOTTOM_LEFT, new Value[] { xInput, new ValueMath(deriv,xInput) });
          str.setColor(textColor);
          str.setBackgroundColor(bgColor);
          str.setFrameWidth(1);
          str.setNumSize(7);
          canvas.add(str,1);
          subController.add(str);
          if (showSecond) {
             str = new DrawString(functionName + " ' ' (#) = #", DrawString.BOTTOM_LEFT, new Value[] { xInput, new ValueMath(deriv2,xInput) });
             str.setColor(textColor);
             str.setBackgroundColor(bgColor);
             str.setFrameWidth(1);
             str.setNumSize(7);
             canvas.add(str,2);
             subController.add(str);
          }
      }

   } // end setUpCanvas()
   
   
   protected void addCanvasBorder() { // override to add the border to each coordinate rect, and make default width equal to 1
      int borderWidth;
      double[] bw = getNumericParam("BorderWidth");
      if (bw == null || bw.length == 0 || bw[0] > 25)
         borderWidth = 2;
      else
         borderWidth = (int)Math.round(bw[0]);
      if (borderWidth > 0) {
         canvas.add( new DrawBorder( getColorParam("BorderColor", Color.black), borderWidth  ), 0 );
         canvas.add( new DrawBorder( getColorParam("BorderColor", Color.black), borderWidth  ), 1 );
         if (deriv2 != null)
            canvas.add( new DrawBorder( getColorParam("BorderColor", Color.black), borderWidth  ), 2 );
      }
   }



   protected void doLoadExample(String example) {
         // This method is called when the user loads an example from the 
         // example menu (if there is one).  It overrides an empty method
         // in GenericGraphApplet.
         //   For the SecantTangent applet, the example string should contain
         // an expression that defines the function to be graphed.  This can optionally
         // be followed by a semicoloon and a list of four or five numbers.
         // The first four numbers give the x- and y-limits to be used for the
         // example.  If they are not present, then -5,5,-5,5 is used.  The
         // fifth number, if present, gives the x-coord where the tangent line
         // is drawn initially.
   
      int pos = example.indexOf(";");

      double[] limits = { -5,5,-5,5 };  // x- and y-limits to use
      
      if (pos > 0) { // get limits from example text
         String limitsText = example.substring(pos+1);
         example = example.substring(0,pos);
         StringTokenizer toks = new StringTokenizer(limitsText, " ,");
         if (toks.countTokens() >= 4) {
            for (int i = 0; i < 4; i++) {
               try {
                   Double d = new Double(toks.nextToken());
                   limits[i] = d.doubleValue();
               }
               catch (NumberFormatException e) {
               }
            }
            if (toks.countTokens() > 0) { // Get point for tangent line
               try {
                   Double d = new Double(toks.nextToken());
                   xInput.setVal( d.doubleValue() );
               }
               catch (NumberFormatException e) {
               }
            }
         }
      }
      
      // Set up the example data and recompute everything.

      if (functionInput != null) {
            // If there is a function input box, put the example text in it.
         functionInput.setText(example);
      }
      else { 
           // If there is no user input, set the function in the graph directly.
           // Also, in this case, func is a "WrapperFunction".  Set the
           // definition of that WrapperFunction to be the same as f
         try {
            Expression exp = parser.parse(example);
            derivExpression = exp.derivative(xVar);
            Function f = new SimpleFunction( exp, xVar );
            ((WrapperFunction)func).setFunction(f);
         }
         catch (ParseError e) {  
             // There should't be parse error's in the Web-page
             // author's examples!  If there are, the function
             // just won't change.
         }
      }
      CoordinateRect coords = canvas.getCoordinateRect(0);
      coords.setLimits(limits);
      coords.setRestoreBuffer();
      canvas.getCoordinateRect(1).setRestoreBuffer();
      if (deriv2 != null)
         canvas.getCoordinateRect(0).setRestoreBuffer();
      mainController.compute();
      
   } // end doLoadExample()
   
      public static void main(String[] a){
         javax.swing.JFrame f = new javax.swing.JFrame();
         Applet app = new Derivatives();
         app.init();
         
         f.getContentPane().add (app);

         f.pack();
         f.setSize (new Dimension (500, 500));
         f.setVisible(true);
      }   


} // end class SimpleGraph

           
       








jcm1-source.zip( 532 k)

Related examples in the same category

1.Math Function ChartMath Function Chart
2.Draw Your Own Contour FunctionDraw Your Own Contour Function
3.Draw Math Function Your OwnDraw Math Function Your Own
4.Draw Math Function In CoordinateDraw Math Function In Coordinate
5.ContouringContouring
6.Display the graph of a single function of one variableDisplay the graph of a single function of one variable
7.Function CompositionFunction Composition
8.Draw the functionDraw the function
9.Math function graph 1Math function graph 1
10.Draw math function on the coordinateDraw math function on the coordinate
11.Calculate the arithmetic functionCalculate the arithmetic function
12.Math function and barMath function and bar
13.Science Parser