Y Axis autoscaling

Y Axis autoscaling

Postby des » Tue Jun 23, 2009 9:35 am

I would to set my data and not need to worry about setting ranges or steps. The scaling should be calculated for me.

As a bonus feature labels should not overlap. Autostepping would be nice too in cases where the range is large. This should be simple to calculate.
des
 
Posts: 1
Joined: Tue Jun 23, 2009 9:29 am

Re: Y Axis autoscaling

Postby monk.e.boy » Thu Jun 25, 2009 9:49 pm

des wrote:This should be simple to calculate.


Awaiting simple algorithm.

Here are some sets of test Y values:

[1,2,3]
[9,10,11]
[-1,0,1]
[1,000,001, -99, 29,000,000]
monk.e.boy
Founder & Project Lead
 
Posts: 653
Joined: Thu Sep 04, 2008 10:06 pm

Autoscaling, Incerement

Postby aykurtis » Tue Oct 06, 2009 5:13 pm

I write some methods in c# for my project. It may be helpfull. You may found a better solution in one open source chart project.

Calculate max and min value of series for axis, then call PickScale method. PickScale calculates scale, scaleMult, majorStep min and max.

Code: Select all

private static double CalcStepSize(double range, double targetSteps)
      {
         // Calculate an initial guess at step size
         double tempStep = range / targetSteps;

         // Get the magnitude of the step size
         double mag = Math.Floor(Math.Log10(tempStep));
         double magPow = Math.Pow((double)10.0, mag);

         // Calculate most significant digit of the new step size
         double magMsd = ((int)(tempStep / magPow + .5));

         // promote the MSD to either 1, 2, or 5
         if (magMsd > 5.0)
            magMsd = 10.0;
         else if (magMsd > 2.0)
            magMsd = 5.0;
         else if (magMsd > 1.0)
            magMsd = 2.0;

         return magMsd * magPow;
      }

      private static void _pickScale(ref double min, ref double max)
      {
         double minVal = min;
         double maxVal = max;

         double _min = min;
         double _max = max;
         double _minGrace = 0.1;
         double _maxGrace = 0.1;

         // Make sure that minVal and maxVal are legitimate values
         if (Double.IsInfinity(minVal) || Double.IsNaN(minVal) || minVal == Double.MaxValue)
            minVal = 0.0;
         if (Double.IsInfinity(maxVal) || Double.IsNaN(maxVal) || maxVal == Double.MaxValue)
            maxVal = 0.0;

         // if the scales are autoranged, use the actual data values for the range
         double range = maxVal - minVal;

         // "Grace" is applied to the numeric axis types only
         bool numType = true; // !IsAnyOrdinal;

         // For autoranged values, assign the value.  If appropriate, adjust the value by the
         // "Grace" value.
         _min = minVal;
         // Do not let the grace value extend the axis below zero when all the values were positive
         if (numType && (_min < 0 || minVal - _minGrace * range >= 0.0))
            _min = minVal - _minGrace * range;
         _max = maxVal;
         // Do not let the grace value extend the axis above zero when all the values were negative
         if (numType && (_max > 0 || maxVal + _maxGrace * range <= 0.0))
            _max = maxVal + _maxGrace * range;


         if (_max == _min)
         {
            if (Math.Abs(_max) > 1e-100)
            {
               _max *= (_min < 0 ? 0.95 : 1.05);
               _min *= (_min < 0 ? 1.05 : 0.95);
            }
            else
            {
               _max = 1.0;
               _min = -1.0;
            }
         }

         if (_max <= _min)
         {
            _max = _min + 1.0;

         }
         min = _min;
         max = _max;

      }



      private static double CalcBoundedStepSize(double range, double maxSteps)
      {
         // Calculate an initial guess at step size
         double tempStep = range / maxSteps;

         // Get the magnitude of the step size
         double mag = Math.Floor(Math.Log10(tempStep));
         double magPow = Math.Pow((double)10.0, mag);

         // Calculate most significant digit of the new step size
         double magMsd = Math.Ceiling(tempStep / magPow);

         // promote the MSD to either 1, 2, or 5
         if (magMsd > 5.0)
            magMsd = 10.0;
         else if (magMsd > 2.0)
            magMsd = 5.0;
         else if (magMsd > 1.0)
            magMsd = 2.0;

         return magMsd * magPow;
      }

      private static double MyMod(double x, double y)
      {
         double temp;

         if (y == 0)
            return 0;

         temp = x / y;
         return y * (temp - Math.Floor(temp));
      }

      private static double SetScaleMag(double min, double max, double step)
      {
         double _mag = 0;
         bool _magAuto = true;
         // set the scale magnitude if required
         if (_magAuto)
         {
            // Find the optimal scale display multiple
            double mag = -100;
            double mag2 = -100;

            if (Math.Abs(min) > 1.0e-30)
               mag = Math.Floor(Math.Log10(Math.Abs(min)));
            if (Math.Abs(max) > 1.0e-30)
               mag2 = Math.Floor(Math.Log10(Math.Abs(max)));

            mag = Math.Max(mag2, mag);

            // Do not use scale multiples for magnitudes below 4
            if (mag == -100 || Math.Abs(mag) <= 3)
               mag = 0;

            // Use a power of 10 that is a multiple of 3 (engineering scale)
            _mag = (int)(Math.Floor(mag / 3.0) * 3.0);
         }

         // Calculate the appropriate number of dec places to display if required
         /*   
              if (_formatAuto)
              {
                  int numDec = 0 - (int)(Math.Floor(Math.Log10(_majorStep)) - _mag);
                  if (numDec < 0)
                      numDec = 0;
                  _format = "f" + numDec.ToString();
              }
          */
         return _mag;
      }

      public static void PickScale(out double scale, out double scaleMult, out double majorStep, ref double min, ref double max)
      {
         bool _minAuto = true;
         bool _maxAuto = true;
         bool _minorStepAuto = true;
         bool _majorStepAuto = true;

         majorStep = 0.1;

         double _minorStep = 0.1;
         double targetSteps = 7.0;
         // call the base class first
         _pickScale(ref min, ref max);
         // Test for trivial condition of range = 0 and pick a suitable default
         if (max - min < 1.0e-30)
         {
            if (_maxAuto)
               max = max + 0.2 * (max == 0 ? 1.0 : Math.Abs(max));
            if (_minAuto)
               min = min - 0.2 * (min == 0 ? 1.0 : Math.Abs(min));
         }

         // This is the zero-lever test.  If minVal is within the zero lever fraction
         // of the data range, then use zero.


         if (_minAuto && min > 0 &&
             min / (max - min) < 0)
            min = 0;

         // Repeat the zero-lever test for cases where the maxVal is less than zero

         if (_maxAuto && max < 0 &&
           Math.Abs(max / (max - min)) < 0)
            max = 0;


         // Calculate the new step size

         if (_majorStepAuto)
         {
            // Calculate the step size based on target steps
            majorStep = CalcStepSize(max - min, targetSteps);

         }


         // Calculate the new step size
         if (_minorStepAuto)
         {
            _minorStep = CalcStepSize(majorStep, targetSteps);
         }

         // Calculate the scale minimum
         if (_minAuto)
            min = min - MyMod(min, majorStep);

         // Calculate the scale maximum
         if (_maxAuto)
            max = MyMod(max, majorStep) == 0.0 ? max :
                max + majorStep - MyMod(max, majorStep);


         double _mag = SetScaleMag(min, max, majorStep);
         scaleMult = Math.Pow((double)10.0, _mag);
         if (_mag > 3)
         {
            scale = Math.Pow((double)10.0, _mag - 3);
         }
         else
            if (_mag > 3)
            {
               scale = Math.Pow((double)10.0, _mag + 3);
            }
            else
            {
               scale = 1;
            }
      }


aykurtis
 
Posts: 2
Joined: Tue Oct 06, 2009 4:51 pm

Re: Y Axis autoscaling

Postby sim72 » Sat Jan 23, 2010 11:32 am

Hi all !
I spent some time google-ing for an Y-axix autoscale algorithm.
I found something and i write some PHP code.
I'll put here a function. I'm sure is not perfect but work for me (don't know why). It's not tested with decimal and negative values.
Code: Select all
<?php
/*
* Auto scale for OFC
*
* @param int $miny - lower chart value
* @param int $maxy - upper chart value
* @param int $step - number of Y division in chart
* @param int $d - output some data (debug)
* @return array
*
*/
function autoScaleY($miny=0,$maxy=100,$step=10,$d=0){
   $lower_bound = $miny;
   $upper_bound = $maxy;
   $range = $maxy - $miny;
   $tick_range = $range / $step;
   $i=0;
   $n=1;
   while($n>=1)
   {
      $n = $tick_range/pow(10,$i);
      $i++;
   }
   $i--;
   switch ($n){
      case (0.1):
         $n = 0.1;
         break;
      case ($n<0.2):
         $n = 0.2;
         break;   
      case ($n<0.25):
         $n = 0.25;
         break;   
      case ($n<0.3):
         $n = 0.3;
         break;   
      case ($n<0.4):
         $n = 0.4;
         break;   
      case ($n<0.5):
         $n = 0.5;
         break;   
      case ($n<0.6):
         $n = 0.6;
         break;   
      case ($n<0.7):
         $n = 0.7;
         break;   
      case ($n<0.75):
         $n = 0.75;
         break;   
      case ($n<0.8):
         $n = 0.8;
         break;   
      case ($n<0.9):
         $n = 0.9;
         break;   
      case ($n<1):
         $n = 1;
         break;
      default:
         print "Somethings is wrong !!! I don`t know what \n";
         $d=1;
         break;
   }
   
   $nice_tick = $n * pow(10,$i);
   $lower_bound = $nice_tick * floor($miny/$nice_tick);
   $upper_bound = $nice_tick * round(1+$maxy/$nice_tick);
   
   if($d==1){
      print "range = $range \n";
      print "tick_range = $tick_range \n";
      print "n = $n \n";
      print "nice_tick = $nice_tick \n";
      print "lower_bound = $lower_bound \n";
      print "upper_bound = $upper_bound \n";
   }
   $scale["minY"] = $lower_bound;
   $scale["maxY"] = $upper_bound;
   
   return $scale;
}

// call function with this param.
   $data = $aAbo;
   $maxY = max($data);
   $minY = min($data);
   $step = 5;
        $scale = autoScaleY($minY,$maxY,$step);
   $step = ceil($scale["maxY"] / $step);

        include '../../ofc/php-ofc-library/open-flash-chart.php';
        .
        .
        $y_axis = new y_axis();
   $y_axis->set_range($scale["minY"],$scale["maxY"],$step);
        .
        .
        $chart->add_y_axis( $y_axis );
        .
?>

Many thanks to OFC team. I'll drink a beer and i'll say a prayer for your.
sim72
 
Posts: 1
Joined: Sat Jan 23, 2010 10:50 am


Return to Feature Request

Who is online

Users browsing this forum: No registered users and 1 guest