/// <summary> /// Select a reasonable base 10 logarithmic axis scale given a range of data values. /// </summary> /// <remarks> /// This method only applies to <see cref="AxisType.Log"/> type axes, and it /// is called by the general <see cref="PickScale"/> method. The scale range is chosen /// based always on powers of 10 (full log cycles). This /// method honors the <see cref="Scale.MinAuto"/>, <see cref="Scale.MaxAuto"/>, /// and <see cref="Scale.MajorStepAuto"/> autorange settings. /// In the event that any of the autorange settings are false, the /// corresponding <see cref="Scale.Min"/>, <see cref="Scale.Max"/>, or <see cref="Scale.MajorStep"/> /// setting is explicitly honored, and the remaining autorange settings (if any) will /// be calculated to accomodate the non-autoranged values. For log axes, the MinorStep /// value is not used. /// <para>On Exit:</para> /// <para><see cref="Scale.Min"/> is set to scale minimum (if <see cref="Scale.MinAuto"/> = true)</para> /// <para><see cref="Scale.Max"/> is set to scale maximum (if <see cref="Scale.MaxAuto"/> = true)</para> /// <para><see cref="Scale.MajorStep"/> is set to scale step size (if <see cref="Scale.MajorStepAuto"/> = true)</para> /// <para><see cref="Scale.Mag"/> is set to a magnitude multiplier according to the data</para> /// <para><see cref="Scale.Format"/> is set to the display format for the values (this controls the /// number of decimal places, whether there are thousands separators, currency types, etc.)</para> /// </remarks> /// <param name="pane">A reference to the <see cref="GraphPane"/> object /// associated with this <see cref="Axis"/></param> /// <param name="g"> /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// </param> /// <param name="scaleFactor"> /// The scaling factor to be used for rendering objects. This is calculated and /// passed down by the parent <see cref="GraphPane"/> object using the /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust /// font sizes, etc. according to the actual size of the graph. /// </param> /// <seealso cref="PickScale"/> /// <seealso cref="AxisType.Log"/> public override void PickScale( GraphPane pane, IGraphics g, float scaleFactor ) { double minVal = _rangeMin; double maxVal = _rangeMax; // 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(minVal > maxVal) { double t = maxVal; maxVal = minVal; minVal = t; } // Check for bad data range if (minVal <= 0.0 && maxVal <= 0.0) { minVal = 1.0; maxVal = 10.0; } else if (minVal <= 0.0) { minVal = maxVal / 10.0; } double range = maxVal - minVal; // For autoranged values, assign the value. If appropriate, adjust the value by the // "Grace" value. if(_minAuto) { if(_minGrace < 0) { _minGrace = 0; } double graceVal = CalcMinValue(minVal, maxVal, _minGrace); double nextProperPowerOf10 = Math.Pow(10.0, Math.Floor(Math.Log10(minVal))); _min = graceVal < nextProperPowerOf10 ? nextProperPowerOf10 : graceVal; // don't use grace val if there is a power of 10 between the data start and the garce value } if(_maxAuto) { if(_maxGrace < 0) { _maxGrace = 0; } double graceVal = CalcMaxValue(minVal, maxVal, _maxGrace); double nextProperPowerOf10 = Math.Pow(10.0, Math.Ceiling(Math.Log10(maxVal))); _max = graceVal > nextProperPowerOf10 ? nextProperPowerOf10 : graceVal; } // if min == max and we are auto scaling, make the scale go from -5% to +5% if (_max == _min && _maxAuto && _minAuto) { 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; } } _mag = 0; // Never use a magnitude shift for log scales //this.numDec = 0; // The number of decimal places to display is not used // Test for trivial condition of range = 0 and pick a suitable default if ( _max - _min < SmallestValue ) { if ( _maxAuto ) _max = _max * 2.0; if ( _minAuto ) _min = _min / 2.0; } if(UsingLinearlySpacedTickMarks) // this method gets called again after the initial setup - so _linScale may already be set { //_linScale.PickScale(pane, g, scaleFactor); _min = _linScale._min; _max = _linScale._max; return; } int nTicks = CalcNumTics(); // get the number of ticks if (UseMostSuitableTickMarkSpacing && nTicks < MinimumNumberOfMajorTicks) // then we shall use a linear scale instead { // Calculate the new step size double majorStep = _majorStep; if (_majorStepAuto) { double targetSteps = (_ownerAxis is XAxis || _ownerAxis is X2Axis) ? Default.TargetXSteps : Default.TargetYSteps; // Calculate the step size based on target steps majorStep = CalcStepSize(_max - _min, targetSteps); if (_isPreventLabelOverlap) { // Calculate the maximum number of labels double maxLabels = (double)this.CalcMaxLabels(g, pane, scaleFactor); // Will this work? if (maxLabels < (_max - _min) / _majorStep) { majorStep = CalcBoundedStepSize(_max - _min, maxLabels); } } } LinearScale altLinScale = new LinearScale(this, _ownerAxis) { _rangeMin = this._rangeMin, _rangeMax = this._rangeMax, MajorStep = majorStep, _min = this._min, _max = this._max }; // Special case. If range is zero, then we have already adjusted our _min and max to 95% to 105%. // I do not want the linear scale to adda a grace on to this as well. if(range == 0) { altLinScale._minGrace = 0; altLinScale._maxGrace = 0; } _linScale = altLinScale; return; } // Majorstep is always 1 for log scales if (_majorStepAuto) _majorStep = 1.0; }
/// <summary> /// Select a reasonable base 10 logarithmic axis scale given a range of data values. /// </summary> /// <remarks> /// This method only applies to <see cref="AxisType.Log"/> type axes, and it /// is called by the general <see cref="PickScale"/> method. The scale range is chosen /// based always on powers of 10 (full log cycles). This /// method honors the <see cref="Scale.MinAuto"/>, <see cref="Scale.MaxAuto"/>, /// and <see cref="Scale.MajorStepAuto"/> autorange settings. /// In the event that any of the autorange settings are false, the /// corresponding <see cref="Scale.Min"/>, <see cref="Scale.Max"/>, or <see cref="Scale.MajorStep"/> /// setting is explicitly honored, and the remaining autorange settings (if any) will /// be calculated to accomodate the non-autoranged values. For log axes, the MinorStep /// value is not used. /// <para>On Exit:</para> /// <para><see cref="Scale.Min"/> is set to scale minimum (if <see cref="Scale.MinAuto"/> = true)</para> /// <para><see cref="Scale.Max"/> is set to scale maximum (if <see cref="Scale.MaxAuto"/> = true)</para> /// <para><see cref="Scale.MajorStep"/> is set to scale step size (if <see cref="Scale.MajorStepAuto"/> = true)</para> /// <para><see cref="Scale.Mag"/> is set to a magnitude multiplier according to the data</para> /// <para><see cref="Scale.Format"/> is set to the display format for the values (this controls the /// number of decimal places, whether there are thousands separators, currency types, etc.)</para> /// </remarks> /// <param name="pane">A reference to the <see cref="GraphPane"/> object /// associated with this <see cref="Axis"/></param> /// <param name="g"> /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// </param> /// <param name="scaleFactor"> /// The scaling factor to be used for rendering objects. This is calculated and /// passed down by the parent <see cref="GraphPane"/> object using the /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust /// font sizes, etc. according to the actual size of the graph. /// </param> /// <seealso cref="PickScale"/> /// <seealso cref="AxisType.Log"/> override public void PickScale(GraphPane pane, IGraphics g, float scaleFactor) { double minVal = _rangeMin; double maxVal = _rangeMax; // 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 (minVal > maxVal) { double t = maxVal; maxVal = minVal; minVal = t; } // Check for bad data range if (minVal <= 0.0 && maxVal <= 0.0) { minVal = 1.0; maxVal = 10.0; } else if (minVal <= 0.0) { minVal = maxVal / 10.0; } double range = maxVal - minVal; // For autoranged values, assign the value. If appropriate, adjust the value by the // "Grace" value. if (_minAuto) { if (_minGrace < 0) { _minGrace = 0; } double graceVal = CalcMinValue(minVal, maxVal, _minGrace); double nextProperPowerOf10 = Math.Pow(10.0, Math.Floor(Math.Log10(minVal))); _min = graceVal < nextProperPowerOf10 ? nextProperPowerOf10 : graceVal; // don't use grace val if there is a power of 10 between the data start and the garce value } if (_maxAuto) { if (_maxGrace < 0) { _maxGrace = 0; } double graceVal = CalcMaxValue(minVal, maxVal, _maxGrace); double nextProperPowerOf10 = Math.Pow(10.0, Math.Ceiling(Math.Log10(maxVal))); _max = graceVal > nextProperPowerOf10 ? nextProperPowerOf10 : graceVal; } // if min == max and we are auto scaling, make the scale go from -5% to +5% if (_max == _min && _maxAuto && _minAuto) { 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; } } _mag = 0; // Never use a magnitude shift for log scales //this.numDec = 0; // The number of decimal places to display is not used // Test for trivial condition of range = 0 and pick a suitable default if (_max - _min < 1.0e-20) { if (_maxAuto) { _max = _max * 2.0; } if (_minAuto) { _min = _min / 2.0; } } if (UsingLinearlySpacedTickMarks) // this method gets called again after the initial setup - so _linScale may already be set { //_linScale.PickScale(pane, g, scaleFactor); _min = _linScale._min; _max = _linScale._max; return; } int nTicks = CalcNumTics(); // get the number of ticks if (UseMostSuitableTickMarkSpacing && nTicks < MinimumNumberOfMajorTicks) // then we shall use a linear scale instead { // Calculate the new step size double majorStep = _majorStep; if (_majorStepAuto) { double targetSteps = (_ownerAxis is XAxis || _ownerAxis is X2Axis) ? Default.TargetXSteps : Default.TargetYSteps; // Calculate the step size based on target steps majorStep = CalcStepSize(_max - _min, targetSteps); if (_isPreventLabelOverlap) { // Calculate the maximum number of labels double maxLabels = (double)this.CalcMaxLabels(g, pane, scaleFactor); // Will this work? if (maxLabels < (_max - _min) / _majorStep) { majorStep = CalcBoundedStepSize(_max - _min, maxLabels); } } } LinearScale altLinScale = new LinearScale(this, _ownerAxis) { _rangeMin = this._rangeMin, _rangeMax = this._rangeMax, MajorStep = majorStep, _min = this._min, _max = this._max }; // Special case. If range is zero, then we have already adjusted our _min and max to 95% to 105%. // I do not want the linear scale to adda a grace on to this as well. if (range == 0) { altLinScale._minGrace = 0; altLinScale._maxGrace = 0; } _linScale = altLinScale; return; } // Majorstep is always 1 for log scales if (_majorStepAuto) { _majorStep = 1.0; } }