Dom*_*ier 27 java algorithm math charts
我需要手动计算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.这里的值 - 当然 - 不是最优的,而且滴答非常难看.
有没有人知道问题的解决方案或有正式算法描述的提示?
小智 63
我是" 图表轴上的最佳缩放算法 "的作者.它曾经托管在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();
}
}
Run Code Online (Sandbox Code Playgroud)
然后我们可以像这样使用上面的代码:
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());
Run Code Online (Sandbox Code Playgroud)
然后,它将输出格式良好的数字,以便在您需要创建漂亮比例的任何应用程序中使用.= d
Tick Spacing: 0.05
Nice Minimum: -0.1
Nice Maximum: 0.2
Run Code Online (Sandbox Code Playgroud)
这是一个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();
}
Run Code Online (Sandbox Code Playgroud)
请享用!
小智 5
我已根据我的要求将上面的 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
Run Code Online (Sandbox Code Playgroud)
您应该能够通过较小的修正来使用 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
}
Run Code Online (Sandbox Code Playgroud)
免责声明:请注意,我尚未对此进行测试,因此您可能需要对其进行调整以使其看起来不错。我建议的解决方案在图表顶部添加额外的空间,以便始终为 5 个刻度腾出空间。在某些情况下这可能看起来很难看。
| 归档时间: |
|
| 查看次数: |
12788 次 |
| 最近记录: |