/// <summary>
        /// Draw the plot on the drawing surface
        /// </summary>
        /// <param name="g">The GDI+ drawing surface on which to render.</param>
        /// <param name="bounds">The bounding rectangle on the drawing surface to be considered the plot area.</param>
        public void Draw(Graphics g, Rectangle bounds)
        {
            if (plots_.Count == 0)
            {
                return;
                // TODO: better output in this case.
            }

            float scale = (float)DetermineScaleFactor(bounds.Width, bounds.Height);

            if (xAxis1_ == null)
            {
                xAxis1_ = (Axis)xAxis2_.Clone();
                xAxis1_.HideTickText = true;
                xAxis1_.TicksAngle   = -Math.PI / 2.0f;
            }

            if (xAxis2_ == null)
            {
                xAxis2_ = (Axis)xAxis1_.Clone();
                xAxis2_.HideTickText = true;
                xAxis2_.TicksAngle   = Math.PI / 2.0f;
            }

            if (yAxis1_ == null)
            {
                yAxis1_ = (Axis)yAxis2_.Clone();
                yAxis1_.HideTickText = true;
                yAxis1_.TicksAngle   = Math.PI / 2.0f;
            }

            if (yAxis2_ == null)
            {
                yAxis2_ = (Axis)yAxis1_.Clone();
                yAxis2_.HideTickText = true;
                yAxis2_.TicksAngle   = -Math.PI / 2.0f;
            }

            // TODO: fix this so these not automatically overwritten.
            xAxis1_.TickScale = scale;
            xAxis1_.FontScale = scale;
            yAxis1_.TickScale = scale;
            yAxis1_.FontScale = scale;
            xAxis2_.TickScale = scale;
            xAxis2_.FontScale = scale;
            yAxis2_.TickScale = scale;
            yAxis2_.FontScale = scale;

            // now have axes world info. set physical limits.
            // first guess axes positions, then find bounding box, then change
            // to align nicely with side of control.
            System.Drawing.Rectangle cb = bounds;
            RectangleF bb;

            // guess physical x axis (bottom). Put it at the bottom of the plot
            PhysicalAxis pXAxis1 = new PhysicalAxis(xAxis1_,
                                                    new Point(cb.Left, cb.Bottom), new Point(cb.Right, cb.Bottom));
            int bottomIndent = (int)(padding_);

            if (!pXAxis1.Axis.Hidden)
            {
                // evaluate its bounding box
                bb = pXAxis1.GetBoundingBox();
                // finally determine its indentation from the bottom
                bottomIndent = (int)(bottomIndent + bb.Bottom - cb.Bottom);
            }

            // guess physical y axis (left). Put it at the left side.
            PhysicalAxis pYAxis1 = new PhysicalAxis(yAxis1_,
                                                    new Point(cb.Left, cb.Bottom), new Point(cb.Left, cb.Top));
            int leftIndent = (int)(padding_);

            if (!pYAxis1.Axis.Hidden)
            {
                // evaluate its bounding box
                bb = pYAxis1.GetBoundingBox();
                // finally determine its indentation from the left
                leftIndent = (int)(leftIndent - bb.Left + cb.Left);
            }

            // guess secondary x axis (top).
            PhysicalAxis pXAxis2 = new PhysicalAxis(xAxis2_,
                                                    new Point(cb.Left, cb.Top), new Point(cb.Right, cb.Top));
            int    topIndent   = (int)(padding_);
            double titleHeight = FontScaler.scaleFont(titleFont_, scale).Height;

            if (!pXAxis2.Axis.Hidden)
            {
                // evaluate its bounding box
                bb        = pXAxis2.GetBoundingBox();
                topIndent = (int)(topIndent - bb.Top + cb.Top);

                // finally determine its indentation from the top
                // correct top indendation to take into account plot title
                if (title_ != "")
                {
                    topIndent += (int)((double)titleHeight * 1.3f);
                }
            }

            // guess secondary y axis (right). Put it at the right side.
            PhysicalAxis pYAxis2 = new PhysicalAxis(yAxis2_,
                                                    new Point(cb.Right, cb.Bottom), new Point(cb.Right, cb.Top));
            int rightIndent = (int)(padding_);

            if (!pYAxis2.Axis.Hidden)
            {
                // evaluate its bounding box
                bb = pYAxis2.GetBoundingBox();

                // finally determine its indentation from the right
                rightIndent = (int)(rightIndent + bb.Right - cb.Right);
            }

            // now determine if legend should change any of these (legend should be fully
            // visible at all times), and draw legend.
            Legend legend = null;
            float  lXPos  = 0.0f;
            float  lYPos  = 0.0f;

            if (showLegend_)
            {
                legend             = new Legend();
                legend.BorderStyle = LegendBorderStyle;
                RectangleF legendWidthHeight = legend.GetBoundingBox(0, 0, plots_, scale);

                // calculate legend position.

                lYPos = legendOffsetY_;

                if (legendOffsetXAxis_ == XAxisPosition.Bottom)
                {
                    lYPos += cb.Bottom - bottomIndent;
                    if (horizontalEdgeLegendPlacement_ == Legend.Placement.Inside)
                    {
                        lYPos -= legendWidthHeight.Height;
                    }
                }
                else
                {
                    lYPos += cb.Top + topIndent;
                    if (horizontalEdgeLegendPlacement_ == Legend.Placement.Outside)
                    {
                        lYPos -= legendWidthHeight.Height;
                    }
                }

                lXPos = legendOffsetX_;

                if (legendOffsetYAxis_ == YAxisPosition.Left)
                {
                    if (verticalEdgeLegendPlacement_ == Legend.Placement.Outside)
                    {
                        lXPos -= legendWidthHeight.Width;
                    }
                    lXPos += cb.Left + leftIndent;
                }
                else
                {
                    if (verticalEdgeLegendPlacement_ == Legend.Placement.Inside)
                    {
                        lXPos -= legendWidthHeight.Width;
                    }
                    lXPos += cb.Right - rightIndent;
                }

                // update axes positions if need to for legend position.

                if (lXPos < padding_)
                {
                    int changeAmount = -(int)lXPos + padding_;
                    // only allow axes to move away from bounds.
                    if (changeAmount > 0)
                    {
                        leftIndent += changeAmount;
                    }
                    lXPos += changeAmount;
                }

                if (lXPos + legendWidthHeight.Width > bounds.Right - padding_)
                {
                    int changeAmount = ((int)lXPos - bounds.Right + (int)legendWidthHeight.Width + padding_);
                    // only allow axes to move away from bounds.
                    if (changeAmount > 0)
                    {
                        rightIndent += changeAmount;
                    }
                    lXPos -= changeAmount;
                }

                if (lYPos < padding_)
                {
                    int changeAmount = -(int)lYPos + padding_;
                    // only allow axes to move away from bounds.
                    if (changeAmount > 0)
                    {
                        topIndent += changeAmount;
                    }
                    lYPos += changeAmount;
                }

                if (lYPos + legendWidthHeight.Height > bounds.Bottom - padding_)
                {
                    int changeAmount = ((int)lYPos - bounds.Bottom + (int)legendWidthHeight.Height + padding_);
                    // only allow axes to move away from bounds.
                    if (changeAmount > 0)
                    {
                        bottomIndent += changeAmount;
                    }
                    lYPos -= changeAmount;
                }
            }


            // now we have all the positions and we can proceed to "move" the axes to their
            // right places
            // primary axes (bottom, left)
            pXAxis1.PhysicalMin = new Point(cb.Left + leftIndent, cb.Bottom - bottomIndent);
            pXAxis1.PhysicalMax = new Point(cb.Right - rightIndent, cb.Bottom - bottomIndent);
            pYAxis1.PhysicalMin = new Point(cb.Left + leftIndent, cb.Bottom - bottomIndent);
            pYAxis1.PhysicalMax = new Point(cb.Left + leftIndent, cb.Top + topIndent);
            // secondary axes (top, right)
            pXAxis2.PhysicalMin = new Point(cb.Left + leftIndent, cb.Top + topIndent);
            pXAxis2.PhysicalMax = new Point(cb.Right - rightIndent, cb.Top + topIndent);
            pYAxis2.PhysicalMin = new Point(cb.Right - rightIndent, cb.Bottom - bottomIndent);
            pYAxis2.PhysicalMax = new Point(cb.Right - rightIndent, cb.Top + topIndent);


            // now we are ready to define the bounding box for the plot area (to use in clipping
            // operations.

            plotAreaBoundingBoxCache_ = new Rectangle(cb.Left + leftIndent, cb.Top + topIndent,
                                                      cb.Width - leftIndent - rightIndent,
                                                      cb.Height - topIndent - bottomIndent);

#if _IWANNASEE_
            bb = pXAxis1.GetBoundingBox();
            g.DrawRectangle(new Pen(Color.Orange), bb.X, bb.Y, bb.Width, bb.Height);
            bb = pXAxis2.GetBoundingBox();
            g.DrawRectangle(new Pen(Color.Orange), bb.X, bb.Y, bb.Width, bb.Height);
            bb = pYAxis1.GetBoundingBox();
            g.DrawRectangle(new Pen(Color.Orange), bb.X, bb.Y, bb.Width, bb.Height);
            bb = pYAxis2.GetBoundingBox();
            g.DrawRectangle(new Pen(Color.Orange), bb.X, bb.Y, bb.Width, bb.Height);
            g.DrawRectangle(new Pen(Color.Red, 5.0F), plotAreaBoundingBox_);
#endif


            // Fill in the background.
            if (plotBackColor_ != null)
            {
                g.FillRectangle(new System.Drawing.SolidBrush((Color)plotBackColor_),
                                pYAxis1.PhysicalMin.X,
                                pXAxis2.PhysicalMax.Y,
                                pXAxis1.PhysicalMax.X - pXAxis1.PhysicalMin.X,
                                pYAxis1.PhysicalMin.Y - pYAxis1.PhysicalMax.Y);
            }

            // draw title
            StringFormat drawFormat = new StringFormat();
            drawFormat.Alignment = StringAlignment.Center;
            g.DrawString(title_, FontScaler.scaleFont(titleFont_, scale),
                         titleBrush_,
                         new PointF((pXAxis2.PhysicalMax.X + pXAxis2.PhysicalMin.X) / 2.0f, cb.Top + padding_),
                         drawFormat);

            // now draw grid.
            DrawGrid(g, pXAxis1, pYAxis1, pXAxis2, pYAxis2);

            // now draw axes.
            pXAxis1.Draw(g);
            pXAxis2.Draw(g);
            pYAxis1.Draw(g);
            pYAxis2.Draw(g);

            // draw plots.
            for (int i = 0; i < plots_.Count; ++i)
            {
                IPlot         plot = (IPlot)plots_[i];
                XAxisPosition xap  = (XAxisPosition)xAxisPositions_[i];
                YAxisPosition yap  = (YAxisPosition)yAxisPositions_[i];

                PhysicalAxis xAxis;
                PhysicalAxis yAxis;

                if (xap == XAxisPosition.Bottom)
                {
                    xAxis = pXAxis1;
                }
                else
                {
                    xAxis = pXAxis2;
                }

                if (yap == YAxisPosition.Left)
                {
                    yAxis = pYAxis1;
                }
                else
                {
                    yAxis = pYAxis2;
                }

                // set the clipping region.. (necessary for zoom)
                g.Clip = new Region((Rectangle)plotAreaBoundingBoxCache_);
                // plot..
                plot.Draw(g, xAxis, yAxis);
                // reset it..
                g.ResetClip();

                // cache the physical axes we used on this draw;
                pXAxis1Cache_ = pXAxis1;
                pYAxis1Cache_ = pYAxis1;
                pXAxis2Cache_ = pXAxis2;
                pYAxis2Cache_ = pYAxis2;
            }

            if (legend != null)
            {
                legend.Draw(g, (int)lXPos, (int)lYPos, plots_, scale);
            }
        }