具有最小刻度的图表的尼斯标签算法

我需要手动计算Ticklabels和Tickrange for charts。

我知道好标记的“标准”算法(参见http://books.google.de/books?id=fvA7zLEFWZgC&pg=PA61&lpg=PA61&redir_esc=y#v=onepage&q&f=false ),我也知道这个Java实现 。

问题是,使用这种算法,滴答声“太聪明”了。 这意味着,该算法决定应显示多少刻度。 我的要求是,总有5个Ticks,但这些当然应该是“漂亮的”。 天真的方法是获得最大值,除以5并乘以ticknumber。 这里的值 – 当然 – 不是最优的,而且滴答非常难看。

有没有人知道问题的解决方案或有正式算法描述的提示?

您应该能够使用Java实现进行微小更正。

将maxticks更改为5。

将计算方法更改为:

private void calculate() { this.range = niceNum(maxPoint - minPoint, false); this.tickSpacing = niceNum(range / (maxTicks - 1), true); this.niceMin = Math.floor(minPoint / tickSpacing) * tickSpacing; this.niceMax = this.niceMin + tickSpacing * (maxticks - 1); // Always display maxticks } 

免责声明:请注意,我没有对此进行测试,因此您可能需要调整它以使其看起来很好。 我建议的解决方案在图表顶部增加了额外的空间,以便为5个刻度留出空间。 在某些情况下,这可能看起来很丑陋。

我是“ 图表轴上的最佳缩放算法 ”的作者。 它曾经托管在trollop.org上,但我最近移动了域名/博客引擎。 无论如何,我会在这里发布内容以便于访问。

我一直在研究一个用于分配的Android图表应用程序,并且在以精确缩放的格式呈现图表时遇到了一些问题。 我花了一些时间尝试自己创建这个算法并且非常接近,但最后我在Andrew S. Glassner的一本名为“Graphics Gems,Volume 1”的书中找到了一个伪代码示例。 有关问题的优秀描述在“ 图形标签的好数字 ”一章中给出:

在通过计算机创建图形时,最好用“漂亮”数字标记x和y轴:简单的十进制数字。 例如,如果数据范围是105到543,我们可能想要绘制范围从100到600并且每100个单位放置刻度线。 或者,如果数据范围是2.04到2.16,我们可能会绘制从2.00到2.20的范围,刻度间距为0.05。 人类擅长选择这样的“好”数字,但简单算法则不然。 朴素的标签选择算法获取数据范围并将其划分为n个相等的间隔,但这通常会导致丑陋的刻度标签。 我们在这里描述了一种生成漂亮图形标签的简单方法。

主要观察结果是十进制中“最好的”数字是1,2和5,以及这些数字的所有十次幂。 我们将仅使用这样的数字作为刻度线间距,并将刻度线放置在刻度线间距的倍数处…

我使用本书中的伪代码示例在Java中创建以下类:

 public class NiceScale { private double minPoint; private double maxPoint; private double maxTicks = 10; private double tickSpacing; private double range; private double niceMin; private double niceMax; /** * Instantiates a new instance of the NiceScale class. * * @param min the minimum data point on the axis * @param max the maximum data point on the axis */ public NiceScale(double min, double max) { this.minPoint = min; this.maxPoint = max; calculate(); } /** * Calculate and update values for tick spacing and nice * minimum and maximum data points on the axis. */ private void calculate() { this.range = niceNum(maxPoint - minPoint, false); this.tickSpacing = niceNum(range / (maxTicks - 1), true); this.niceMin = Math.floor(minPoint / tickSpacing) * tickSpacing; this.niceMax = Math.ceil(maxPoint / tickSpacing) * tickSpacing; } /** * Returns a "nice" number approximately equal to range Rounds * the number if round = true Takes the ceiling if round = false. * * @param range the data range * @param round whether to round the result * @return a "nice" number to be used for the data range */ private double niceNum(double range, boolean round) { double exponent; /** exponent of range */ double fraction; /** fractional part of range */ double niceFraction; /** nice, rounded fraction */ exponent = Math.floor(Math.log10(range)); fraction = range / Math.pow(10, exponent); if (round) { if (fraction < 1.5) niceFraction = 1; else if (fraction < 3) niceFraction = 2; else if (fraction < 7) niceFraction = 5; else niceFraction = 10; } else { if (fraction <= 1) niceFraction = 1; else if (fraction <= 2) niceFraction = 2; else if (fraction <= 5) niceFraction = 5; else niceFraction = 10; } return niceFraction * Math.pow(10, exponent); } /** * Sets the minimum and maximum data points for the axis. * * @param minPoint the minimum data point on the axis * @param maxPoint the maximum data point on the axis */ public void setMinMaxPoints(double minPoint, double maxPoint) { this.minPoint = minPoint; this.maxPoint = maxPoint; calculate(); } /** * Sets maximum number of tick marks we're comfortable with * * @param maxTicks the maximum number of tick marks for the axis */ public void setMaxTicks(double maxTicks) { this.maxTicks = maxTicks; calculate(); } } 

然后我们可以像这样使用上面的代码:

 NiceScale numScale = new NiceScale(-0.085, 0.173); System.out.println("Tick Spacing:\t" + numScale.getTickSpacing()); System.out.println("Nice Minimum:\t" + numScale.getNiceMin()); System.out.println("Nice Maximum:\t" + numScale.getNiceMax()); 

然后,它将输出格式良好的数字,以便在您需要创建漂亮比例的任何应用程序中使用。 = d

 Tick Spacing: 0.05 Nice Minimum: -0.1 Nice Maximum: 0.2 

我按照我的要求将上面的java代码转换为Python。

  import math class NiceScale: def __init__(self, minv,maxv): self.maxTicks = 6 self.tickSpacing = 0 self.lst = 10 self.niceMin = 0 self.niceMax = 0 self.minPoint = minv self.maxPoint = maxv self.calculate() def calculate(self): self.lst = self.niceNum(self.maxPoint - self.minPoint, False) self.tickSpacing = self.niceNum(self.lst / (self.maxTicks - 1), True) self.niceMin = math.floor(self.minPoint / self.tickSpacing) * self.tickSpacing self.niceMax = math.ceil(self.maxPoint / self.tickSpacing) * self.tickSpacing def niceNum(self, lst, rround): self.lst = lst exponent = 0 # exponent of range */ fraction = 0 # fractional part of range */ niceFraction = 0 # nice, rounded fraction */ exponent = math.floor(math.log10(self.lst)); fraction = self.lst / math.pow(10, exponent); if (self.lst): if (fraction < 1.5): niceFraction = 1 elif (fraction < 3): niceFraction = 2 elif (fraction < 7): niceFraction = 5; else: niceFraction = 10; else : if (fraction <= 1): niceFraction = 1 elif (fraction <= 2): niceFraction = 2 elif (fraction <= 5): niceFraction = 5 else: niceFraction = 10 return niceFraction * math.pow(10, exponent) def setMinMaxPoints(self, minPoint, maxPoint): self.minPoint = minPoint self.maxPoint = maxPoint self.calculate() def setMaxTicks(self, maxTicks): self.maxTicks = maxTicks; self.calculate() a=NiceScale(14024, 17756) print "a.lst ", a.lst print "a.maxPoint ", a.maxPoint print "a.maxTicks ", a.maxTicks print "a.minPoint ", a.minPoint print "a.niceMax ", a.niceMax print "a.niceMin ", a.niceMin print "a.tickSpacing ", a.tickSpacing 

目标C中的内容也是如此

YFRNiceScale.h

 #import  @interface YFRNiceScale : NSObject @property (nonatomic, readonly) CGFloat minPoint; @property (nonatomic, readonly) CGFloat maxPoint; @property (nonatomic, readonly) CGFloat maxTicks; @property (nonatomic, readonly) CGFloat tickSpacing; @property (nonatomic, readonly) CGFloat range; @property (nonatomic, readonly) CGFloat niceRange; @property (nonatomic, readonly) CGFloat niceMin; @property (nonatomic, readonly) CGFloat niceMax; - (id) initWithMin: (CGFloat) min andMax: (CGFloat) max; - (id) initWithNSMin: (NSDecimalNumber*) min andNSMax: (NSDecimalNumber*) max; @end 

YFRNiceScale.m

 #import "YFRNiceScale.h" @implementation YFRNiceScale @synthesize minPoint = _minPoint; @synthesize maxPoint = _maxPoint; @synthesize maxTicks = _maxTicks; @synthesize tickSpacing = _tickSpacing; @synthesize range = _range; @synthesize niceRange = _niceRange; @synthesize niceMin = _niceMin; @synthesize niceMax = _niceMax; - (id)init { self = [super init]; if (self) { } return self; } - (id) initWithMin: (CGFloat) min andMax: (CGFloat) max { if (self) { _maxTicks = 10; _minPoint = min; _maxPoint = max; [self calculate]; } return [self init]; } - (id) initWithNSMin: (NSDecimalNumber*) min andNSMax: (NSDecimalNumber*) max { if (self) { _maxTicks = 10; _minPoint = [min doubleValue]; _maxPoint = [max doubleValue]; [self calculate]; } return [self init]; } /** * Calculate and update values for tick spacing and nice minimum and maximum * data points on the axis. */ - (void) calculate { _range = [self niceNumRange: (_maxPoint-_minPoint) roundResult:NO]; _tickSpacing = [self niceNumRange: (_range / (_maxTicks - 1)) roundResult:YES]; _niceMin = floor(_minPoint / _tickSpacing) * _tickSpacing; _niceMax = ceil(_maxPoint / _tickSpacing) * _tickSpacing; _niceRange = _niceMax - _niceMin; } /** * Returns a "nice" number approximately equal to range Rounds the number if * round = true Takes the ceiling if round = false. * * @param range * the data range * @param round * whether to round the result * @return a "nice" number to be used for the data range */ - (CGFloat) niceNumRange:(CGFloat) aRange roundResult:(BOOL) round { CGFloat exponent; CGFloat fraction; CGFloat niceFraction; exponent = floor(log10(aRange)); fraction = aRange / pow(10, exponent); if (round) { if (fraction < 1.5) { niceFraction = 1; } else if (fraction < 3) { niceFraction = 2; } else if (fraction < 7) { niceFraction = 5; } else { niceFraction = 10; } } else { if (fraction <= 1) { niceFraction = 1; } else if (fraction <= 2) { niceFraction = 2; } else if (fraction <= 5) { niceFraction = 2; } else { niceFraction = 10; } } return niceFraction * pow(10, exponent); } - (NSString*) description { return [NSString stringWithFormat:@"NiceScale [minPoint=%.2f, maxPoint=%.2f, maxTicks=%.2f, tickSpacing=%.2f, range=%.2f, niceMin=%.2f, niceMax=%.2f]", _minPoint, _maxPoint, _maxTicks, _tickSpacing, _range, _niceMin, _niceMax ]; } @end 

用法:

 YFRNiceScale* niceScale = [[YFRNiceScale alloc] initWithMin:0 andMax:500]; NSLog(@"Nice: %@", niceScale); 

我在编写一些php时发现了这个post,所以现在php中也提供相同的代码!

 class CNiceScale { private $minPoint; private $maxPoint; private $maxTicks = 10; private $tickSpacing; private $range; private $niceMin; private $niceMax; public function setScale($min, $max) { $this->minPoint = $min; $this->maxPoint = $max; $this->calculate(); } private function calculate() { $this->range = $this->niceNum($this->maxPoint - $this->minPoint, false); $this->tickSpacing = $this->niceNum($this->range / ($this->maxTicks - 1), true); $this->niceMin = floor($this->minPoint / $this->tickSpacing) * $this->tickSpacing; $this->niceMax = ceil($this->maxPoint / $this->tickSpacing) * $this->tickSpacing; } private function niceNum($range, $round) { $exponent; /** exponent of range */ $fraction; /** fractional part of range */ $niceFraction; /** nice, rounded fraction */ $exponent = floor(log10($range)); $fraction = $range / pow(10, $exponent); if ($round) { if ($fraction < 1.5) $niceFraction = 1; else if ($fraction < 3) $niceFraction = 2; else if ($fraction < 7) $niceFraction = 5; else $niceFraction = 10; } else { if ($fraction <= 1) $niceFraction = 1; else if ($fraction <= 2) $niceFraction = 2; else if ($fraction <= 5) $niceFraction = 5; else $niceFraction = 10; } return $niceFraction * pow(10, $exponent); } public function setMinMaxPoints($minPoint, $maxPoint) { $this->minPoint = $minPoint; $this->maxPoint = $maxPoint; $this->calculate(); } public function setMaxTicks($maxTicks) { $this->maxTicks = $maxTicks; $this->calculate(); } public function getTickSpacing() { return $this->tickSpacing; } public function getNiceMin() { return $this->niceMin; } public function getNiceMax() { return $this->niceMax; } } 

我需要将此算法转换为C#,所以这里是……

 public static class NiceScale { public static void Calculate(double min, double max, int maxTicks, out double range, out double tickSpacing, out double niceMin, out double niceMax) { range = niceNum(max - min, false); tickSpacing = niceNum(range / (maxTicks - 1), true); niceMin = Math.Floor(min / tickSpacing) * tickSpacing; niceMax = Math.Ceiling(max / tickSpacing) * tickSpacing; } private static double niceNum(double range, bool round) { double pow = Math.Pow(10, Math.Floor(Math.Log10(range))); double fraction = range / pow; double niceFraction; if (round) { if (fraction < 1.5) { niceFraction = 1; } else if (fraction < 3) { niceFraction = 2; } else if (fraction < 7) { niceFraction = 5; } else { niceFraction = 10; } } else { if (fraction <= 1) { niceFraction = 1; } else if (fraction <= 2) { niceFraction = 2; } else if (fraction <= 5) { niceFraction = 5; } else { niceFraction = 10; } } return niceFraction * pow; } } 

这是一个javascript版本:

 var minPoint; var maxPoint; var maxTicks = 10; var tickSpacing; var range; var niceMin; var niceMax; /** * Instantiates a new instance of the NiceScale class. * * min the minimum data point on the axis * max the maximum data point on the axis */ function niceScale( min, max) { minPoint = min; maxPoint = max; calculate(); return { tickSpacing: tickSpacing, niceMinimum: niceMin, niceMaximum: niceMax }; } /** * Calculate and update values for tick spacing and nice * minimum and maximum data points on the axis. */ function calculate() { range = niceNum(maxPoint - minPoint, false); tickSpacing = niceNum(range / (maxTicks - 1), true); niceMin = Math.floor(minPoint / tickSpacing) * tickSpacing; niceMax = Math.ceil(maxPoint / tickSpacing) * tickSpacing; } /** * Returns a "nice" number approximately equal to range Rounds * the number if round = true Takes the ceiling if round = false. * * localRange the data range * round whether to round the result * a "nice" number to be used for the data range */ function niceNum( localRange, round) { var exponent; /** exponent of localRange */ var fraction; /** fractional part of localRange */ var niceFraction; /** nice, rounded fraction */ exponent = Math.floor(Math.log10(localRange)); fraction = localRange / Math.pow(10, exponent); if (round) { if (fraction < 1.5) niceFraction = 1; else if (fraction < 3) niceFraction = 2; else if (fraction < 7) niceFraction = 5; else niceFraction = 10; } else { if (fraction <= 1) niceFraction = 1; else if (fraction <= 2) niceFraction = 2; else if (fraction <= 5) niceFraction = 5; else niceFraction = 10; } return niceFraction * Math.pow(10, exponent); } /** * Sets the minimum and maximum data points for the axis. * * minPoint the minimum data point on the axis * maxPoint the maximum data point on the axis */ function setMinMaxPoints( localMinPoint, localMaxPoint) { minPoint = localMinPoint; maxPoint = localMaxoint; calculate(); } /** * Sets maximum number of tick marks we're comfortable with * * maxTicks the maximum number of tick marks for the axis */ function setMaxTicks(localMaxTicks) { maxTicks = localMaxTicks; calculate(); } 

请享用!

由于每个人和他的狗都在发布其他流行语言的翻译,这里是我的Nimrod编程语言版本。 我还添加了滴答数小于2的情况的处理:

 import math, strutils const defaultMaxTicks = 10 type NiceScale = object minPoint: float maxPoint: float maxTicks: int tickSpacing: float niceMin: float niceMax: float proc ff(x: float): string = result = x.formatFloat(ffDecimal, 3) proc `$`*(x: NiceScale): string = result = "Input minPoint: " & x.minPoint.ff & "\nInput maxPoint: " & x.maxPoint.ff & "\nInput maxTicks: " & $x.maxTicks & "\nOutput niceMin: " & x.niceMin.ff & "\nOutput niceMax: " & x.niceMax.ff & "\nOutput tickSpacing: " & x.tickSpacing.ff & "\n" proc calculate*(x: var NiceScale) proc init*(x: var NiceScale; minPoint, maxPoint: float; maxTicks = defaultMaxTicks) = x.minPoint = minPoint x.maxPoint = maxPoint x.maxTicks = maxTicks x.calculate proc initScale*(minPoint, maxPoint: float; maxTicks = defaultMaxTicks): NiceScale = result.init(minPoint, maxPoint, maxTicks) proc niceNum(scaleRange: float; doRound: bool): float = var exponent: float ## Exponent of scaleRange. fraction: float ## Fractional part of scaleRange. niceFraction: float ## Nice, rounded fraction. exponent = floor(log10(scaleRange)); fraction = scaleRange / pow(10, exponent); if doRound: if fraction < 1.5: niceFraction = 1 elif fraction < 3: niceFraction = 2 elif fraction < 7: niceFraction = 5 else: niceFraction = 10 else: if fraction <= 1: niceFraction = 1 elif fraction <= 2: niceFraction = 2 elif fraction <= 5: niceFraction = 5 else: niceFraction = 10 return niceFraction * pow(10, exponent) proc calculate*(x: var NiceScale) = assert x.maxPoint > x.minPoint, "Wrong input range!" assert x.maxTicks >= 0, "Sorry, can't have imaginary ticks!" let scaleRange = niceNum(x.maxPoint - x.minPoint, false) if x.maxTicks < 2: x.niceMin = floor(x.minPoint) x.niceMax = ceil(x.maxPoint) x.tickSpacing = (x.niceMax - x.niceMin) / (if x.maxTicks == 1: 2.0 else: 1.0) else: x.tickSpacing = niceNum(scaleRange / (float(x.maxTicks - 1)), true) x.niceMin = floor(x.minPoint / x.tickSpacing) * x.tickSpacing x.niceMax = ceil(x.maxPoint / x.tickSpacing) * x.tickSpacing when isMainModule: var s = initScale(57.2, 103.3) echo s 

这是评论剥离版本。 完整的一个可以在集成到我的项目中的GitHub上阅读。

这是Swift版本:

 class NiceScale { private var minPoint: Double private var maxPoint: Double private var maxTicks = 10 private(set) var tickSpacing: Double = 0 private(set) var range: Double = 0 private(set) var niceMin: Double = 0 private(set) var niceMax: Double = 0 init(min: Double, max: Double) { minPoint = min maxPoint = max calculate() } func setMinMaxPoints(min: Double, max: Double) { minPoint = min maxPoint = max calculate() } private func calculate() { range = niceNum(maxPoint - minPoint, round: false) tickSpacing = niceNum(range / Double((maxTicks - 1)), round: true) niceMin = floor(minPoint / tickSpacing) * tickSpacing niceMax = floor(maxPoint / tickSpacing) * tickSpacing } private func niceNum(range: Double, round: Bool) -> Double { let exponent = floor(log10(range)) let fraction = range / pow(10, exponent) let niceFraction: Double if round { if fraction <= 1.5 { niceFraction = 1 } else if fraction <= 3 { niceFraction = 2 } else if fraction <= 7 { niceFraction = 5 } else { niceFraction = 10 } } else { if fraction <= 1 { niceFraction = 1 } else if fraction <= 2 { niceFraction = 2 } else if fraction <= 5 { niceFraction = 5 } else { niceFraction = 10 } } return niceFraction * pow(10, exponent) } } 

这是C ++版本。 作为奖励,您将获得一个函数,该函数返回最小小数点数以在轴上显示刻度标签。

头文件:

 class NiceScale { public: float minPoint; float maxPoint; float maxTicks; float tickSpacing; float range; float niceMin; float niceMax; public: NiceScale() { maxTicks = 10; } /** * Instantiates a new instance of the NiceScale class. * * @param min the minimum data point on the axis * @param max the maximum data point on the axis */ NiceScale(float min, float max) { minPoint = min; maxPoint = max; calculate(); } /** * Calculate and update values for tick spacing and nice * minimum and maximum data points on the axis. */ void calculate() ; /** * Returns a "nice" number approximately equal to range Rounds * the number if round = true Takes the ceiling if round = false. * * @param range the data range * @param round whether to round the result * @return a "nice" number to be used for the data range */ float niceNum(float range, boolean round) ; /** * Sets the minimum and maximum data points for the axis. * * @param minPoint the minimum data point on the axis * @param maxPoint the maximum data point on the axis */ void setMinMaxPoints(float minPoint, float maxPoint) ; /** * Sets maximum number of tick marks we're comfortable with * * @param maxTicks the maximum number of tick marks for the axis */ void setMaxTicks(float maxTicks) ; int decimals(void); }; 

和CPP文件:

 /** * Calculate and update values for tick spacing and nice * minimum and maximum data points on the axis. */ void NiceScale::calculate() { range = niceNum(maxPoint - minPoint, false); tickSpacing = niceNum(range / (maxTicks - 1), true); niceMin = floor(minPoint / tickSpacing) * tickSpacing; niceMax = ceil(maxPoint / tickSpacing) * tickSpacing; } /** * Returns a "nice" number approximately equal to range Rounds the number if round = true Takes the ceiling if round = false. * * @param range the data range * @param round whether to round the result * @return a "nice" number to be used for the data range */ float NiceScale::niceNum(float range, boolean round) { float exponent; /** exponent of range */ float fraction; /** fractional part of range */ float niceFraction; /** nice, rounded fraction */ exponent = floor(log10(range)); fraction = range / pow(10.f, exponent); if (round) { if (fraction < 1.5) niceFraction = 1; else if (fraction < 3) niceFraction = 2; else if (fraction < 7) niceFraction = 5; else niceFraction = 10; } else { if (fraction <= 1) niceFraction = 1; else if (fraction <= 2) niceFraction = 2; else if (fraction <= 5) niceFraction = 5; else niceFraction = 10; } return niceFraction * pow(10, exponent); } /** * Sets the minimum and maximum data points for the axis. * * @param minPoint the minimum data point on the axis * @param maxPoint the maximum data point on the axis */ void NiceScale::setMinMaxPoints(float minPoint, float maxPoint) { this->minPoint = minPoint; this->maxPoint = maxPoint; calculate(); } /** * Sets maximum number of tick marks we're comfortable with * * @param maxTicks the maximum number of tick marks for the axis */ void NiceScale::setMaxTicks(float maxTicks) { this->maxTicks = maxTicks; calculate(); } // minimum number of decimals in tick labels // use in sprintf statement: // sprintf(buf, "%.*f", decimals(), tickValue); int NiceScale::decimals(void) { float logTickX = log10(tickSpacing); if(logTickX >= 0) return 0; return (int)(abs(floor(logTickX))); } 

这是VB.NET版本。

 Public Class NiceScale Private minPoint As Double Private maxPoint As Double Private maxTicks As Double = 10 Private tickSpacing Private range As Double Private niceMin As Double Private niceMax As Double Public Sub New(min As Double, max As Double) minPoint = min maxPoint = max calculate() End Sub Private Sub calculate() range = niceNum(maxPoint - minPoint, False) tickSpacing = niceNum(range / (maxTicks - 1), True) niceMin = Math.Floor(minPoint / tickSpacing) * tickSpacing niceMax = Math.Ceiling(maxPoint / tickSpacing) * tickSpacing End Sub Private Function niceNum(range As Double, round As Boolean) As Double Dim exponent As Double '/** exponent of range */ Dim fraction As Double '/** fractional part of range */ Dim niceFraction As Double '/** nice, rounded fraction */ exponent = Math.Floor(Math.Log10(range)) fraction = range / Math.Pow(10, exponent) If round Then If (fraction < 1.5) Then niceFraction = 1 ElseIf (fraction < 3) Then niceFraction = 2 ElseIf (fraction < 7) Then niceFraction = 5 Else niceFraction = 10 End If Else If (fraction <= 1) Then niceFraction = 1 ElseIf (fraction <= 2) Then niceFraction = 2 ElseIf (fraction <= 5) Then niceFraction = 5 Else niceFraction = 10 End If End If Return niceFraction * Math.Pow(10, exponent) End Function Public Sub setMinMaxPoints(minPoint As Double, maxPoint As Double) minPoint = minPoint maxPoint = maxPoint calculate() End Sub Public Sub setMaxTicks(maxTicks As Double) maxTicks = maxTicks calculate() End Sub Public Function getTickSpacing() As Double Return tickSpacing End Function Public Function getNiceMin() As Double Return niceMin End Function Public Function getNiceMax() As Double Return niceMax End Function End Class 

这是在TypeScript中!

 /** * Calculate and update values for tick spacing and nice * minimum and maximum data points on the axis. */ function calculateTicks(maxTicks: number, minPoint: number, maxPoint: number): [number, number, number] { let range = niceNum(maxPoint - minPoint, false); let tickSpacing = niceNum(range / (maxTicks - 1), true); let niceMin = Math.floor(minPoint / tickSpacing) * tickSpacing; let niceMax = Math.ceil(maxPoint / tickSpacing) * tickSpacing; let tickCount = range / tickSpacing; return [tickCount, niceMin, niceMax]; } /** * Returns a "nice" number approximately equal to range Rounds * the number if round = true Takes the ceiling if round = false. * * @param range the data range * @param round whether to round the result * @return a "nice" number to be used for the data range */ function niceNum(range: number, round: boolean): number { let exponent: number; /** exponent of range */ let fraction: number; /** fractional part of range */ let niceFraction: number; /** nice, rounded fraction */ exponent = Math.floor(Math.log10(range)); fraction = range / Math.pow(10, exponent); if (round) { if (fraction < 1.5) niceFraction = 1; else if (fraction < 3) niceFraction = 2; else if (fraction < 7) niceFraction = 5; else niceFraction = 10; } else { if (fraction <= 1) niceFraction = 1; else if (fraction <= 2) niceFraction = 2; else if (fraction <= 5) niceFraction = 5; else niceFraction = 10; } return niceFraction * Math.pow(10, exponent); } 

这是Kotlin版本!

 import java.lang.Math.* /** * Instantiates a new instance of the NiceScale class. * * @param min Double The minimum data point. * @param max Double The maximum data point. */ class NiceScale(private var minPoint: Double, private var maxPoint: Double) { private var maxTicks = 15.0 private var range: Double = 0.0 var niceMin: Double = 0.0 var niceMax: Double = 0.0 var tickSpacing: Double = 0.0 init { calculate() } /** * Calculate and update values for tick spacing and nice * minimum and maximum data points on the axis. */ private fun calculate() { range = niceNum(maxPoint - minPoint, false) tickSpacing = niceNum(range / (maxTicks - 1), true) niceMin = floor(minPoint / tickSpacing) * tickSpacing niceMax = ceil(maxPoint / tickSpacing) * tickSpacing } /** * Returns a "nice" number approximately equal to range. Rounds * the number if round = true. Takes the ceiling if round = false. * * @param range Double The data range. * @param round Boolean Whether to round the result. * @return Double A "nice" number to be used for the data range. */ private fun niceNum(range: Double, round: Boolean): Double { /** Exponent of range */ val exponent: Double = floor(log10(range)) /** Fractional part of range */ val fraction: Double /** Nice, rounded fraction */ val niceFraction: Double fraction = range / pow(10.0, exponent) niceFraction = if (round) { when { fraction < 1.5 -> 1.0 fraction < 3 -> 2.0 fraction < 7 -> 5.0 else -> 10.0 } } else { when { fraction <= 1 -> 1.0 fraction <= 2 -> 2.0 fraction <= 5 -> 5.0 else -> 10.0 } } return niceFraction * pow(10.0, exponent) } /** * Sets the minimum and maximum data points. * * @param minPoint Double The minimum data point. * @param maxPoint Double The maximum data point. */ fun setMinMaxPoints(minPoint: Double, maxPoint: Double) { this.minPoint = minPoint this.maxPoint = maxPoint calculate() } /** * Sets maximum number of tick marks we're comfortable with. * * @param maxTicks Double The maximum number of tick marks. */ fun setMaxTicks(maxTicks: Double) { this.maxTicks = maxTicks calculate() } }