Learn how easy it is to sync an existing GitHub or Google Code repo to a SourceForge project! See Demo


Prevent Scale/Axis labels jumping

  • Nigel Paton
    Nigel Paton


    I've been looking at preventing the axis labels from jumping values when scrolling and have some changes that seem to do the job. If you are unsure what I mean by jumping values try scrolling a graph which is at a zoom level that has some axis ticks that do not have labels. As you scroll the ticks that have labels will change. For example if the ticks at values 1, 3 and 5 have labels and you scroll such that 1 is no longer visible the labels will jump to being on 2, 4 and 6. It is nicer if the labels stay on the same ticks.

    Extract of code from a y-axis plotting routine (based on mpScaleY::Plot but with bits I don't need removed for speed).

            // Modified from original, bit more accurate. The + 0.5 is for pixel rounding errors
            double n = ceil( (w.GetPosY() - (double)((extend - w.GetMarginBottom()) + 0.5)/ w.GetScaleY()) / step ) * step ;
            wxCoord endPx   = w.GetScrX() - w.GetMarginRight();
            wxCoord minYpx  = w.GetMarginTop();
            wxCoord maxYpx  = w.GetScrY() - w.GetMarginBottom();
            int labelW = 0;
            // Before staring cycle, calculate label height
            int labelHeigth = 0;
            dc.GetTextExtent(s, &tx, &labelHeigth);
            // Calculate how often to print a tick label
            int labelNumStep = (int)ceil((labelHeigth + mpMIN_Y_AXIS_LABEL_SEPARATION)/(w.GetScaleY() * step));
            // Prevent tick label drawing until the first label index is found
            int labelStepCount = labelNumStep + 1;
            // Calculate the first point at which to display a tick label
            double labelStep = step * labelNumStep;
            double firstLabel = ceil(n / labelStep) * labelStep;
            int firstLabelIndex = (int)(((firstLabel - n) + (step / 2)) / step);
            int stepCount = 0;
            for (;n < end; n += step) 
                // Check whether to trigger the first label
                if (stepCount == firstLabelIndex)
                    labelStepCount = labelNumStep;
                const int p = (int)((w.GetPosY() - n) * w.GetScaleY());
                if ((p >= minYpx) && (p <= maxYpx)) 
                    if (m_ticks) 
                    { // Draw axis ticks
                        if (m_flags == mpALIGN_BORDER_LEFT) 
                            dc.DrawLine( orgx, p, orgx+4, p);
                            dc.DrawLine( orgx-4, p, orgx, p); //( orgx, p, orgx+4, p);
                        dc.SetPen( m_pen);
                        if (m_flags == mpALIGN_LEFT)
                            dc.DrawLine( orgx-4, p, endPx, p);
                        else if (m_flags == mpALIGN_RIGHT) 
                            dc.DrawLine( minYpx, p, orgx+4, p);
                            dc.DrawLine( 0/*-w.GetScrX()*/, p, w.GetScrX(), p);
                        dc.SetPen( m_pen);
                    // Print ticks labels
                    if (labelStepCount == labelNumStep)
                        s.Printf(fmt, n);
                        dc.GetTextExtent(s, &tx, &ty);
                        labelW = (labelW <= tx) ? tx : labelW;
                        if ((m_flags == mpALIGN_BORDER_LEFT) || (m_flags == mpALIGN_RIGHT))
                            dc.DrawText( s, orgx+4, p-ty/2);
                            dc.DrawText( s, orgx-4-tx, p-ty/2); 
                        labelStepCount = 1;

    Can be modified for use in other axis/scale plotting routines.