plotSetXRange is not working

I cannot control the plot range in my version of GAUSS16 (Kernel Rev: 16.0.5 build 4242). The MWE in the GAUSS16 help

//Declare plotControl structure
struct plotControl myPlot;

//Initialize plotControl structure
myPlot = plotGetDefaults("scatter");

//Set X-axis to to range from -5 to +5
plotSetXRange(&myPlot, -5, 5);

//Create and plot data using our x-range
x_1 = rndn(100, 1);
x_2 = rndn(100, 1);

plotScatter(myPlot, x_1, x_2);

produces a plot where the horizontal axis starts at -6 and ends at 6.

I am running GAUSS16 on Ubuntu 14.04 (Linux).

Is this a bug? And more importantly: do I now have no control over the plot-range at all?

Thanks in advance for your reply.

1 Answer



0



The GAUSS graphics package makes use of the 'Nice Numbers' algorithm by Paul Heckbert (Heckbert, P.S., 1990, August. Nice numbers for graph labels. In Graphics gems (pp. 61-63). Academic Press Professional, Inc..). This algorithm determines the best min and max in order to display more friendly labels. This means that values passed into the plotSetXRange function are suggestions for the general range.

However, we can manipulate the algorithm by specifying the tick count with the plotSetXTicCount function.

Below is the exact code (ported to GAUSS) used to determine the modified range based on the min, max, and tic count.

// (Heckbert, P.S., 1990, August. Nice numbers for graph labels. In Graphics gems (pp. 61-63). Academic Press Professional, Inc..)
proc (3) = looseNiceNumbers(min, max, tics);
    local range, step;
    range = niceNumber(max - min, 1); //range with ceiling
    step = niceNumber(range / (tics - 1), 0);
    min = floor(min / step);
    max = ceil(max / step);
    tics = floor(max - min) + 1;
    min = min * step;
    max = max * step;
    retp(min, max, tics);
endp;

//nice numbers can be expressed as form of 1*10^n, 2* 10^n or 5*10^n
proc (1) = niceNumber(x, ceiling);
    local z, q;
    z = 10^(floor(log(x))); //find corresponding number of the form of 10^n than is smaller than x
    q = x / z; //q<10 && q>=1;

    if ceiling;
        if (q <= 1.0); q = 1;
        elseif (q <= 2.0); q = 2;
        elseif (q <= 5.0); q = 5;
        else; q = 10;
        endif;
    else;
        if (q < 1.5); q = 1;
        elseif (q < 3.0); q = 2;
        elseif (q < 7.0); q = 5;
        else; q = 10;
        endif;
    endif;
    
    retp(q * z);
endp;

Using this code, we can determine that for the range -5 => 5, if we supply '3' or '11' for the initial tic count, our resulting range stays at -5 => 5.

print looseNiceNumbers(-5, 5, 3);
print looseNiceNumbers(-5, 5, 11);

Since iterating manually is inefficient, below are a couple convenience functions to determine (starting at 6) which tick count will provide the desired range.

proc (1) = findBestHighTics(min, max);
    local tics;
    local best_tic, lowest_range;
    local min_tmp, max_tmp, tics_tmp;
    lowest_range = -1;
    best_tic = -1;
    tics = 6;
    
    do while tics < 15;
        tics_tmp = tics;
        { min_tmp, max_tmp, tics_tmp } = looseNiceNumbers(min, max, tics);
        
        if min == min_tmp and max == max_tmp;
            retp(tics_tmp);
        elseif lowest_range < 0 or max_tmp - min_tmp < lowest_range;
            lowest_range = max_tmp - min_tmp;
            best_tic = tics_tmp;
        endif;
        
        tics = tics + 1;
    endo;
    
    // No suitable tic count for exact range found
    retp(best_tic);
endp;

proc (1) = findBestLowTics(min, max);    
    local tics;
    local best_tic, lowest_range;
    local min_tmp, max_tmp, tics_tmp;
    lowest_range = -1;
    best_tic = -1;
    tics = 5;
    
    do while tics > 1;
        tics_tmp = tics;
        { min_tmp, max_tmp, tics_tmp } = looseNiceNumbers(min, max, tics);
        
        if min == min_tmp and max == max_tmp;
            retp(tics_tmp);
        elseif lowest_range < 0 or max_tmp - min_tmp < lowest_range;
            lowest_range = max_tmp - min_tmp;
            best_tic = tics_tmp;
        endif;
        
        tics = tics - 1;
    endo;
    
    // No suitable tic count for exact range found
    retp(best_tic);
endp;

Given this code, we can directly specify the 'best' tic count:

struct plotControl myPlot;
min = -5;
max = 5;
plotSetXRange(&myPlot, min, max);
plotSetXTicCount(&myPlot, findBestHighTics(min, max));

Sometimes the algorithm is not able to determine a tic count for an exact match, so the findBest*Tics procs have been coded to return the shortest range found.

GAUSS 17 actually (coming soon) uses a more optimized algorithm called Wilkinson, based on the work by Heckbert (An Extension of Wilkinson’s Algorithm for Positioning Tick Labels on Axes by Justin Talbot, Sharon Lin, Pat Hanrahan [1]). This should be less of an issue as it has proven to return a decidedly better range and tic count.

aptech

1,773

Your Answer

1 Answer

0

The GAUSS graphics package makes use of the 'Nice Numbers' algorithm by Paul Heckbert (Heckbert, P.S., 1990, August. Nice numbers for graph labels. In Graphics gems (pp. 61-63). Academic Press Professional, Inc..). This algorithm determines the best min and max in order to display more friendly labels. This means that values passed into the plotSetXRange function are suggestions for the general range.

However, we can manipulate the algorithm by specifying the tick count with the plotSetXTicCount function.

Below is the exact code (ported to GAUSS) used to determine the modified range based on the min, max, and tic count.

// (Heckbert, P.S., 1990, August. Nice numbers for graph labels. In Graphics gems (pp. 61-63). Academic Press Professional, Inc..)
proc (3) = looseNiceNumbers(min, max, tics);
    local range, step;
    range = niceNumber(max - min, 1); //range with ceiling
    step = niceNumber(range / (tics - 1), 0);
    min = floor(min / step);
    max = ceil(max / step);
    tics = floor(max - min) + 1;
    min = min * step;
    max = max * step;
    retp(min, max, tics);
endp;

//nice numbers can be expressed as form of 1*10^n, 2* 10^n or 5*10^n
proc (1) = niceNumber(x, ceiling);
    local z, q;
    z = 10^(floor(log(x))); //find corresponding number of the form of 10^n than is smaller than x
    q = x / z; //q<10 && q>=1;

    if ceiling;
        if (q <= 1.0); q = 1;
        elseif (q <= 2.0); q = 2;
        elseif (q <= 5.0); q = 5;
        else; q = 10;
        endif;
    else;
        if (q < 1.5); q = 1;
        elseif (q < 3.0); q = 2;
        elseif (q < 7.0); q = 5;
        else; q = 10;
        endif;
    endif;
    
    retp(q * z);
endp;

Using this code, we can determine that for the range -5 => 5, if we supply '3' or '11' for the initial tic count, our resulting range stays at -5 => 5.

print looseNiceNumbers(-5, 5, 3);
print looseNiceNumbers(-5, 5, 11);

Since iterating manually is inefficient, below are a couple convenience functions to determine (starting at 6) which tick count will provide the desired range.

proc (1) = findBestHighTics(min, max);
    local tics;
    local best_tic, lowest_range;
    local min_tmp, max_tmp, tics_tmp;
    lowest_range = -1;
    best_tic = -1;
    tics = 6;
    
    do while tics < 15;
        tics_tmp = tics;
        { min_tmp, max_tmp, tics_tmp } = looseNiceNumbers(min, max, tics);
        
        if min == min_tmp and max == max_tmp;
            retp(tics_tmp);
        elseif lowest_range < 0 or max_tmp - min_tmp < lowest_range;
            lowest_range = max_tmp - min_tmp;
            best_tic = tics_tmp;
        endif;
        
        tics = tics + 1;
    endo;
    
    // No suitable tic count for exact range found
    retp(best_tic);
endp;

proc (1) = findBestLowTics(min, max);    
    local tics;
    local best_tic, lowest_range;
    local min_tmp, max_tmp, tics_tmp;
    lowest_range = -1;
    best_tic = -1;
    tics = 5;
    
    do while tics > 1;
        tics_tmp = tics;
        { min_tmp, max_tmp, tics_tmp } = looseNiceNumbers(min, max, tics);
        
        if min == min_tmp and max == max_tmp;
            retp(tics_tmp);
        elseif lowest_range < 0 or max_tmp - min_tmp < lowest_range;
            lowest_range = max_tmp - min_tmp;
            best_tic = tics_tmp;
        endif;
        
        tics = tics - 1;
    endo;
    
    // No suitable tic count for exact range found
    retp(best_tic);
endp;

Given this code, we can directly specify the 'best' tic count:

struct plotControl myPlot;
min = -5;
max = 5;
plotSetXRange(&myPlot, min, max);
plotSetXTicCount(&myPlot, findBestHighTics(min, max));

Sometimes the algorithm is not able to determine a tic count for an exact match, so the findBest*Tics procs have been coded to return the shortest range found.

GAUSS 17 actually (coming soon) uses a more optimized algorithm called Wilkinson, based on the work by Heckbert (An Extension of Wilkinson’s Algorithm for Positioning Tick Labels on Axes by Justin Talbot, Sharon Lin, Pat Hanrahan [1]). This should be less of an issue as it has proven to return a decidedly better range and tic count.


You must login to post answers.

Have a Specific Question?

Get a real answer from a real person

Need Support?

Get help from our friendly experts.

Try GAUSS for 14 days for FREE

See what GAUSS can do for your data

© Aptech Systems, Inc. All rights reserved.

Privacy Policy