Logo Search packages:      
Sourcecode: wims version File versions

synchronized void ptolemy::plot::PlotBox::_drawPlot ( Graphics  graphics,
boolean  clearfirst,
Rectangle  drawRect 
) [inline, protected]

Draw the axes using the current range, label, and title information, at the size of the specified rectangle. If the second argument is true, clear the display before redrawing. This method is called by paintComponent(). To cause it to be called you would normally call repaint(), which eventually causes paintComponent() to be called.

Note that this is synchronized so that points are not added by other threads while the drawing is occurring. This method should be called only from the event dispatch thread, consistent with swing policy.

Parameters:
graphics The graphics context.
clearfirst If true, clear the plot before proceeding.
drawRect A specification of the size.

Reimplemented in ptolemy::plot::Plot.

Definition at line 1834 of file PlotBox.java.

References _bottomPadding, _foreground, _grid, _labelFont, _labelFontMetrics, _leftPadding, _lrx, _lry, _rightPadding, _specifiedPlotRectangle, _superscriptFont, _superscriptFontMetrics, _title, _titleFont, _titleFontMetrics, _topPadding, _ulx, _uly, _xBottom, _xExp, _xlabel, _xlog, _xscale, _xticklabels, _xtickMax, _xtickMin, _xticks, _xtickscale, _xTop, _yBottom, _yExp, _ylabel, _ylog, _yscale, _yticklabels, _ytickMax, _ytickMin, _yticks, _ytickscale, and _yTop.

                                                    {
        // Ignore if there is no graphics object to draw on.
        if (graphics == null) {
            return;
        }

        graphics.setPaintMode();

        /* NOTE: The following seems to be unnecessary with Swing...
         if (clearfirst) {
         // NOTE: calling clearRect() here permits the background
         // color to show through, but it messes up printing.
         // Printing results in black-on-black title and axis labels.
         graphics.setColor(_background);
         graphics.drawRect(0, 0, drawRect.width, drawRect.height);
         graphics.setColor(Color.black);
         }
         */

        // If an error message has been set, display it and return.
        if (_errorMsg != null) {
            int fheight = _labelFontMetrics.getHeight() + 2;
            int msgy = fheight;
            graphics.setColor(Color.black);

            for (int i = 0; i < _errorMsg.length; i++) {
                graphics.drawString(_errorMsg[i], 10, msgy);
                msgy += fheight;
                System.err.println(_errorMsg[i]);
            }

            return;
        }

        // Make sure we have an x and y range
        if (!_xRangeGiven) {
            if (_xBottom > _xTop) {
                // have nothing to go on.
                _setXRange(0, 0);
            } else {
                _setXRange(_xBottom, _xTop);
            }
        }

        if (!_yRangeGiven) {
            if (_yBottom > _yTop) {
                // have nothing to go on.
                _setYRange(0, 0);
            } else {
                _setYRange(_yBottom, _yTop);
            }
        }

        // If user specified a plot rectangle, compute
        // a working plot rectangle which lies inside the
        // drawRect at the user specified coordinates
        Rectangle workingPlotRectangle = null;

        if (_specifiedPlotRectangle != null) {
            workingPlotRectangle = new Rectangle(Math.max(0,
                    _specifiedPlotRectangle.x), Math.max(0,
                    _specifiedPlotRectangle.y), Math.min(drawRect.width,
                    _specifiedPlotRectangle.width), Math.min(drawRect.height,
                    _specifiedPlotRectangle.height));
        }

        // Vertical space for title, if appropriate.
        // NOTE: We assume a one-line title.
        int titley = 0;
        int titlefontheight = _titleFontMetrics.getHeight();

        if (_title == null) {
            // NOTE: If the _title is null, then set it to the empty
            // string to solve the problem where the fill button overlaps
            // the legend if there is no title.  The fix here would
            // be to modify the legend printing text so that it takes
            // into account the case where there is no title by offsetting
            // just enough for the button.
            _title = "";
        }

        if ((_title != null) || (_yExp != 0)) {
            titley = titlefontheight + _topPadding;
        }

        // Number of vertical tick marks depends on the height of the font
        // for labeling ticks and the height of the window.
        Font previousFont = graphics.getFont();
        graphics.setFont(_labelFont);
        graphics.setColor(_foreground); // foreground color not set here  --Rob.

        int labelheight = _labelFontMetrics.getHeight();
        int halflabelheight = labelheight / 2;

        // Draw scaling annotation for x axis.
        // NOTE: 5 pixel padding on bottom.
        int ySPos = drawRect.height - 5;
        int xSPos = drawRect.width - _rightPadding;

        if (_xlog) {
            _xExp = (int) Math.floor(_xtickMin);
        }

        if ((_xExp != 0) && (_xticks == null)) {
            String superscript = Integer.toString(_xExp);
            xSPos -= _superscriptFontMetrics.stringWidth(superscript);
            graphics.setFont(_superscriptFont);

            if (!_xlog) {
                graphics
                        .drawString(superscript, xSPos, ySPos - halflabelheight);
                xSPos -= _labelFontMetrics.stringWidth("x10");
                graphics.setFont(_labelFont);
                graphics.drawString("x10", xSPos, ySPos);
            }

            // NOTE: 5 pixel padding on bottom
            _bottomPadding = ((3 * labelheight) / 2) + 5;
        }

        // NOTE: 5 pixel padding on the bottom.
        if ((_xlabel != null) && (_bottomPadding < (labelheight + 5))) {
            _bottomPadding = labelheight + 5;
        }

        // Compute the space needed around the plot, starting with vertical.
        // NOTE: padding of 5 pixels below title.
        if (workingPlotRectangle != null) {
            _uly = workingPlotRectangle.y;
        } else {
            _uly = titley + 5;
        }

        // NOTE: 3 pixels above bottom labels.
        if (workingPlotRectangle != null) {
            _lry = workingPlotRectangle.y + workingPlotRectangle.height;
        } else {
            _lry = drawRect.height - labelheight - _bottomPadding - 3;
        }

        int height = _lry - _uly;
        _yscale = height / (_yMax - _yMin);
        _ytickscale = height / (_ytickMax - _ytickMin);

        ////////////////// vertical axis
        // Number of y tick marks.
        // NOTE: subjective spacing factor.
        int ny = 2 + (height / (labelheight + 10));

        // Compute y increment.
        double yStep = _roundUp((_ytickMax - _ytickMin) / ny);

        // Compute y starting point so it is a multiple of yStep.
        double yStart = yStep * Math.ceil(_ytickMin / yStep);

        // NOTE: Following disables first tick.  Not a good idea?
        // if (yStart == _ytickMin) yStart += yStep;
        // Define the strings that will label the y axis.
        // Meanwhile, find the width of the widest label.
        // The labels are quantized so that they don't have excess resolution.
        int widesty = 0;

        // These do not get used unless ticks are automatic, but the
        // compiler is not smart enough to allow us to reference them
        // in two distinct conditional clauses unless they are
        // allocated outside the clauses.
        String[] ylabels = new String[ny];
        int[] ylabwidth = new int[ny];

        int ind = 0;

        if (_yticks == null) {
            Vector ygrid = null;

            if (_ylog) {
                ygrid = _gridInit(yStart, yStep, true, null);
            }

            // automatic ticks
            // First, figure out how many digits after the decimal point
            // will be used.
            int numfracdigits = _numFracDigits(yStep);

            // NOTE: Test cases kept in case they are needed again.
            // System.out.println("0.1 with 3 digits: " + _formatNum(0.1, 3));
            // System.out.println("0.0995 with 3 digits: " +
            //                    _formatNum(0.0995, 3));
            // System.out.println("0.9995 with 3 digits: " +
            //                    _formatNum(0.9995, 3));
            // System.out.println("1.9995 with 0 digits: " +
            //                    _formatNum(1.9995, 0));
            // System.out.println("1 with 3 digits: " + _formatNum(1, 3));
            // System.out.println("10 with 0 digits: " + _formatNum(10, 0));
            // System.out.println("997 with 3 digits: " + _formatNum(997, 3));
            // System.out.println("0.005 needs: " + _numFracDigits(0.005));
            // System.out.println("1 needs: " + _numFracDigits(1));
            // System.out.println("999 needs: " + _numFracDigits(999));
            // System.out.println("999.0001 needs: "+_numFracDigits(999.0001));
            // System.out.println("0.005 integer digits: " +
            //                    _numIntDigits(0.005));
            // System.out.println("1 integer digits: " + _numIntDigits(1));
            // System.out.println("999 integer digits: " + _numIntDigits(999));
            // System.out.println("-999.0001 integer digits: " +
            //                    _numIntDigits(999.0001));
            double yTmpStart = yStart;

            if (_ylog) {
                yTmpStart = _gridStep(ygrid, yStart, yStep, _ylog);
            }

            for (double ypos = yTmpStart; ypos <= _ytickMax; ypos = _gridStep(
                    ygrid, ypos, yStep, _ylog)) {
                // Prevent out of bounds exceptions
                if (ind >= ny) {
                    break;
                }

                String yticklabel;

                if (_ylog) {
                    yticklabel = _formatLogNum(ypos, numfracdigits);
                } else {
                    yticklabel = _formatNum(ypos, numfracdigits);
                }

                ylabels[ind] = yticklabel;

                int lw = _labelFontMetrics.stringWidth(yticklabel);
                ylabwidth[ind++] = lw;

                if (lw > widesty) {
                    widesty = lw;
                }
            }
        } else {
            // explicitly specified ticks
            Enumeration nl = _yticklabels.elements();

            while (nl.hasMoreElements()) {
                String label = (String) nl.nextElement();
                int lw = _labelFontMetrics.stringWidth(label);

                if (lw > widesty) {
                    widesty = lw;
                }
            }
        }

        // Next we do the horizontal spacing.
        if (workingPlotRectangle != null) {
            _ulx = workingPlotRectangle.x;
        } else {
            if (_ylabel != null) {
                _ulx = widesty + _labelFontMetrics.stringWidth("W")
                        + _leftPadding;
            } else {
                _ulx = widesty + _leftPadding;
            }
        }

        int legendwidth = _drawLegend(graphics, drawRect.width - _rightPadding,
                _uly);

        if (workingPlotRectangle != null) {
            _lrx = workingPlotRectangle.x + workingPlotRectangle.width;
        } else {
            _lrx = drawRect.width - legendwidth - _rightPadding;
        }

        int width = _lrx - _ulx;
        _xscale = width / (_xMax - _xMin);

        _xtickscale = width / (_xtickMax - _xtickMin);

        // Background for the plotting rectangle.
        // Always use a white background because the dataset colors
        // were designed for a white background.
        graphics.setColor(Color.white);
        graphics.fillRect(_ulx, _uly, width, height);

        graphics.setColor(_foreground);
        graphics.drawRect(_ulx, _uly, width, height);

        // NOTE: subjective tick length.
        int tickLength = 5;
        int xCoord1 = _ulx + tickLength;
        int xCoord2 = _lrx - tickLength;

        if (_yticks == null) {
            // auto-ticks
            Vector ygrid = null;
            double yTmpStart = yStart;

            if (_ylog) {
                ygrid = _gridInit(yStart, yStep, true, null);
                yTmpStart = _gridStep(ygrid, yStart, yStep, _ylog);
                ny = ind;
            }

            ind = 0;

            // Set to false if we don't need the exponent
            boolean needExponent = _ylog;

            for (double ypos = yTmpStart; ypos <= _ytickMax; ypos = _gridStep(
                    ygrid, ypos, yStep, _ylog)) {
                // Prevent out of bounds exceptions
                if (ind >= ny) {
                    break;
                }

                int yCoord1 = _lry - (int) ((ypos - _ytickMin) * _ytickscale);

                // The lowest label is shifted up slightly to avoid
                // colliding with x labels.
                int offset = 0;

                if ((ind > 0) && !_ylog) {
                    offset = halflabelheight;
                }

                graphics.drawLine(_ulx, yCoord1, xCoord1, yCoord1);
                graphics.drawLine(_lrx, yCoord1, xCoord2, yCoord1);

                if (_grid && (yCoord1 != _uly) && (yCoord1 != _lry)) {
                    graphics.setColor(Color.lightGray);
                    graphics.drawLine(xCoord1, yCoord1, xCoord2, yCoord1);
                    graphics.setColor(_foreground);
                }

                // Check to see if any of the labels printed contain
                // the exponent.  If we don't see an exponent, then print it.
                if (_ylog && (ylabels[ind].indexOf('e') != -1)) {
                    needExponent = false;
                }

                // NOTE: 4 pixel spacing between axis and labels.
                graphics.drawString(ylabels[ind], _ulx - ylabwidth[ind++] - 4,
                        yCoord1 + offset);
            }

            if (_ylog) {
                // Draw in grid lines that don't have labels.
                Vector unlabeledgrid = _gridInit(yStart, yStep, false, ygrid);

                if (unlabeledgrid.size() > 0) {
                    // If the step is greater than 1, clamp it to 1 so that
                    // we draw the unlabeled grid lines for each
                    //integer interval.
                    double tmpStep = (yStep > 1.0) ? 1.0 : yStep;

                    for (double ypos = _gridStep(unlabeledgrid, yStart,
                            tmpStep, _ylog); ypos <= _ytickMax; ypos = _gridStep(
                            unlabeledgrid, ypos, tmpStep, _ylog)) {
                        int yCoord1 = _lry
                                - (int) ((ypos - _ytickMin) * _ytickscale);

                        if (_grid && (yCoord1 != _uly) && (yCoord1 != _lry)) {
                            graphics.setColor(Color.lightGray);
                            graphics.drawLine(_ulx + 1, yCoord1, _lrx - 1,
                                    yCoord1);
                            graphics.setColor(_foreground);
                        }
                    }
                }

                if (needExponent) {
                    // We zoomed in, so we need the exponent
                    _yExp = (int) Math.floor(yTmpStart);
                } else {
                    _yExp = 0;
                }
            }

            // Draw scaling annotation for y axis.
            if (_yExp != 0) {
                graphics.drawString("x10", 2, titley);
                graphics.setFont(_superscriptFont);
                graphics.drawString(Integer.toString(_yExp), _labelFontMetrics
                        .stringWidth("x10") + 2, titley - halflabelheight);
                graphics.setFont(_labelFont);
            }
        } else {
            // ticks have been explicitly specified
            Enumeration nt = _yticks.elements();
            Enumeration nl = _yticklabels.elements();

            while (nl.hasMoreElements()) {
                String label = (String) nl.nextElement();
                double ypos = ((Double) (nt.nextElement())).doubleValue();

                if ((ypos > _yMax) || (ypos < _yMin)) {
                    continue;
                }

                int yCoord1 = _lry - (int) ((ypos - _yMin) * _yscale);
                int offset = 0;

                if (ypos < (_lry - labelheight)) {
                    offset = halflabelheight;
                }

                graphics.drawLine(_ulx, yCoord1, xCoord1, yCoord1);
                graphics.drawLine(_lrx, yCoord1, xCoord2, yCoord1);

                if (_grid && (yCoord1 != _uly) && (yCoord1 != _lry)) {
                    graphics.setColor(Color.lightGray);
                    graphics.drawLine(xCoord1, yCoord1, xCoord2, yCoord1);
                    graphics.setColor(_foreground);
                }

                // NOTE: 3 pixel spacing between axis and labels.
                graphics.drawString(label, _ulx
                        - _labelFontMetrics.stringWidth(label) - 3, yCoord1
                        + offset);
            }
        }

        //////////////////// horizontal axis
        int yCoord1 = _uly + tickLength;
        int yCoord2 = _lry - tickLength;
        int charwidth = _labelFontMetrics.stringWidth("8");

        if (_xticks == null) {
            // auto-ticks
            // Number of x tick marks.
            // Need to start with a guess and converge on a solution here.
            int nx = 10;
            double xStep = 0.0;
            int numfracdigits = 0;

            if (_xlog) {
                // X axes log labels will be at most 6 chars: -1E-02
                nx = 2 + (width / ((charwidth * 6) + 10));
            } else {
                // Limit to 10 iterations
                int count = 0;

                while (count++ <= 10) {
                    xStep = _roundUp((_xtickMax - _xtickMin) / nx);

                    // Compute the width of a label for this xStep
                    numfracdigits = _numFracDigits(xStep);

                    // Number of integer digits is the maximum of two endpoints
                    int intdigits = _numIntDigits(_xtickMax);
                    int inttemp = _numIntDigits(_xtickMin);

                    if (intdigits < inttemp) {
                        intdigits = inttemp;
                    }

                    // Allow two extra digits (decimal point and sign).
                    int maxlabelwidth = charwidth
                            * (numfracdigits + 2 + intdigits);

                    // Compute new estimate of number of ticks.
                    int savenx = nx;

                    // NOTE: 10 additional pixels between labels.
                    // NOTE: Try to ensure at least two tick marks.
                    nx = 2 + (width / (maxlabelwidth + 10));

                    if (((nx - savenx) <= 1) || ((savenx - nx) <= 1)) {
                        break;
                    }
                }
            }

            xStep = _roundUp((_xtickMax - _xtickMin) / nx);
            numfracdigits = _numFracDigits(xStep);

            // Compute x starting point so it is a multiple of xStep.
            double xStart = xStep * Math.ceil(_xtickMin / xStep);

            // NOTE: Following disables first tick.  Not a good idea?
            // if (xStart == _xMin) xStart += xStep;
            Vector xgrid = null;
            double xTmpStart = xStart;

            if (_xlog) {
                xgrid = _gridInit(xStart, xStep, true, null);

                //xgrid = _gridInit(xStart, xStep);
                xTmpStart = _gridRoundUp(xgrid, xStart);
            }

            // Set to false if we don't need the exponent
            boolean needExponent = _xlog;

            // Label the x axis.  The labels are quantized so that
            // they don't have excess resolution.
            for (double xpos = xTmpStart; xpos <= _xtickMax; xpos = _gridStep(
                    xgrid, xpos, xStep, _xlog)) {
                String xticklabel;

                if (_xlog) {
                    xticklabel = _formatLogNum(xpos, numfracdigits);

                    if (xticklabel.indexOf('e') != -1) {
                        needExponent = false;
                    }
                } else {
                    xticklabel = _formatNum(xpos, numfracdigits);
                }

                xCoord1 = _ulx + (int) ((xpos - _xtickMin) * _xtickscale);
                graphics.drawLine(xCoord1, _uly, xCoord1, yCoord1);
                graphics.drawLine(xCoord1, _lry, xCoord1, yCoord2);

                if (_grid && (xCoord1 != _ulx) && (xCoord1 != _lrx)) {
                    graphics.setColor(Color.lightGray);
                    graphics.drawLine(xCoord1, yCoord1, xCoord1, yCoord2);
                    graphics.setColor(_foreground);
                }

                int labxpos = xCoord1
                        - (_labelFontMetrics.stringWidth(xticklabel) / 2);

                // NOTE: 3 pixel spacing between axis and labels.
                graphics
                        .drawString(xticklabel, labxpos, _lry + 3 + labelheight);
            }

            if (_xlog) {
                // Draw in grid lines that don't have labels.
                // If the step is greater than 1, clamp it to 1 so that
                // we draw the unlabeled grid lines for each
                // integer interval.
                double tmpStep = (xStep > 1.0) ? 1.0 : xStep;

                // Recalculate the start using the new step.
                xTmpStart = tmpStep * Math.ceil(_xtickMin / tmpStep);

                Vector unlabeledgrid = _gridInit(xTmpStart, tmpStep, false,
                        xgrid);

                if (unlabeledgrid.size() > 0) {
                    for (double xpos = _gridStep(unlabeledgrid, xTmpStart,
                            tmpStep, _xlog); xpos <= _xtickMax; xpos = _gridStep(
                            unlabeledgrid, xpos, tmpStep, _xlog)) {
                        xCoord1 = _ulx
                                + (int) ((xpos - _xtickMin) * _xtickscale);

                        if (_grid && (xCoord1 != _ulx) && (xCoord1 != _lrx)) {
                            graphics.setColor(Color.lightGray);
                            graphics.drawLine(xCoord1, _uly + 1, xCoord1,
                                    _lry - 1);
                            graphics.setColor(_foreground);
                        }
                    }
                }

                if (needExponent) {
                    _xExp = (int) Math.floor(xTmpStart);
                    graphics.setFont(_superscriptFont);
                    graphics.drawString(Integer.toString(_xExp), xSPos, ySPos
                            - halflabelheight);
                    xSPos -= _labelFontMetrics.stringWidth("x10");
                    graphics.setFont(_labelFont);
                    graphics.drawString("x10", xSPos, ySPos);
                } else {
                    _xExp = 0;
                }
            }
        } else {
            // ticks have been explicitly specified
            Enumeration nt = _xticks.elements();
            Enumeration nl = _xticklabels.elements();

            // Code contributed by Jun Wu (jwu@inin.com.au)
            double preLength = 0.0;

            while (nl.hasMoreElements()) {
                String label = (String) nl.nextElement();
                double xpos = ((Double) (nt.nextElement())).doubleValue();

                // If xpos is out of range, ignore.
                if ((xpos > _xMax) || (xpos < _xMin)) {
                    continue;
                }

                // Find the center position of the label.
                xCoord1 = _ulx + (int) ((xpos - _xMin) * _xscale);

                // Find  the start position of x label.
                int labxpos = xCoord1
                        - (_labelFontMetrics.stringWidth(label) / 2);

                // If the labels are not overlapped, proceed.
                if (labxpos > preLength) {
                    // calculate the length of the label
                    preLength = xCoord1
                            + (_labelFontMetrics.stringWidth(label) / 2) + 10;

                    // Draw the label.
                    // NOTE: 3 pixel spacing between axis and labels.
                    graphics.drawString(label, labxpos, _lry + 3 + labelheight);

                    // Draw the label mark on the axis
                    graphics.drawLine(xCoord1, _uly, xCoord1, yCoord1);
                    graphics.drawLine(xCoord1, _lry, xCoord1, yCoord2);

                    // Draw the grid line
                    if (_grid && (xCoord1 != _ulx) && (xCoord1 != _lrx)) {
                        graphics.setColor(Color.lightGray);
                        graphics.drawLine(xCoord1, yCoord1, xCoord1, yCoord2);
                        graphics.setColor(_foreground);
                    }
                }
            }
        }

        //////////////////// Draw title and axis labels now.
        // Center the title and X label over the plotting region, not
        // the window.
        graphics.setColor(_foreground);

        if (_title != null) {
            graphics.setFont(_titleFont);

            int titlex = _ulx
                    + ((width - _titleFontMetrics.stringWidth(_title)) / 2);
            graphics.drawString(_title, titlex, titley);
        }

        graphics.setFont(_labelFont);

        if (_xlabel != null) {
            int labelx = _ulx
                    + ((width - _labelFontMetrics.stringWidth(_xlabel)) / 2);
            graphics.drawString(_xlabel, labelx, ySPos);
        }

        int charcenter = 2 + (_labelFontMetrics.stringWidth("W") / 2);

        if (_ylabel != null) {
            int yl = _ylabel.length();

            if (graphics instanceof Graphics2D) {
                int starty = (_uly + ((_lry - _uly) / 2) + (_labelFontMetrics
                        .stringWidth(_ylabel) / 2))
                        - charwidth;
                Graphics2D g2d = (Graphics2D) graphics;

                // NOTE: Fudge factor so label doesn't touch axis labels.
                int startx = (charcenter + halflabelheight) - 2;
                g2d.rotate(Math.toRadians(-90), startx, starty);
                g2d.drawString(_ylabel, startx, starty);
                g2d.rotate(Math.toRadians(90), startx, starty);
            } else {
                // Not graphics 2D, no support for rotation.
                // Vertical label is fairly complex to draw.
                int starty = (_uly + ((_lry - _uly) / 2))
                        - (yl * halflabelheight) + labelheight;

                for (int i = 0; i < yl; i++) {
                    String nchar = _ylabel.substring(i, i + 1);
                    int cwidth = _labelFontMetrics.stringWidth(nchar);
                    graphics.drawString(nchar, charcenter - (cwidth / 2),
                            starty);
                    starty += labelheight;
                }
            }
        }

        graphics.setFont(previousFont);
    }


Generated by  Doxygen 1.6.0   Back to index