我需要制作一个具有优化的 y 轴最大值的图表。
我制作图表的当前方法只是使用所有图形的最大值,然后将其除以10,并将其用作网格线。我没有写。
更新注意:这些图表已更改。一旦我修复了代码,我的动态图就开始工作了,这个问题没有意义(因为这些例子不再有任何错误)。我用静态图像更新了这些,但是一些答案引用了不同的值。记在脑子里。 到目前为止,2月份有12003到14003个入境电话。信息性,但丑陋。
我想避免看起来像猴子的图表提出 y -axis数字。
使用谷歌图表API有点帮助,但它仍然不是我想要的。 数字很干净,但y值的顶部始终与图表上的最大值相同。此图表从0到1357缩放。我需要计算1400的正确值,有问题。
我在rbobby中摒弃了一个“好”的数字,因为它解释得很好。
我找到了使用Mark Ransom想法的修改版本来获得我想要的结果的方法。
Fist,Mark Ransom的代码确定了刻度线之间的最佳间距,给出了刻度数。有时这个数字最终会超过图表中最高值的两倍,具体取决于您想要的网格线数量。
我正在做的是我用5,6,7,8,9和10个网格线(刻度线)运行Mark的代码,以找出哪些是最低的。值为23时,图表的高度为25,网格线为5,10,15,20和25.值为26时,图表的高度为30,网格线为5,10 ,15,20,25和30.网格线之间的间距相同,但它们有更多。
所以这里只是简单地复制Excel所做的一些步骤,以使图表更加流行。
PHP:
function roundUp($maxValue){
$optiMax = $maxValue * 2;
for ($i = 5; $i <= 10; $i++){
$tmpMaxValue = bestTick($maxValue,$i);
if (($optiMax > $tmpMaxValue) and ($tmpMaxValue > ($maxValue + $maxValue * 0.05))){
$optiMax = $tmpMaxValue;
$optiTicks = $i;
}
}
return $optiMax;
}
function bestTick($maxValue, $mostTicks){
$minimum = $maxValue / $mostTicks;
$magnitude = pow(10,floor(log($minimum) / log(10)));
$residual = $minimum / $magnitude;
if ($residual > 5){
$tick = 10 * $magnitude;
} elseif ($residual > 2) {
$tick = 5 * $magnitude;
} elseif ($residual > 1){
$tick = 2 * $magnitude;
} else {
$tick = $magnitude;
}
return ($tick * $mostTicks);
}
的Python:
import math
def BestTick(largest, mostticks):
minimum = largest / mostticks
magnitude = 10 ** math.floor(math.log(minimum) / math.log(10))
residual = minimum / magnitude
if residual > 5:
tick = 10 * magnitude
elif residual > 2:
tick = 5 * magnitude
elif residual > 1:
tick = 2 * magnitude
else:
tick = magnitude
return tick
value = int(input(""))
optMax = value * 2
for i in range(5,11):
maxValue = BestTick(value,i) * i
print maxValue
if (optMax > maxValue) and (maxValue > value + (value*.05)):
optMax = maxValue
optTicks = i
print "\nTest Value: " + str(value + (value * .05)) + "\n\nChart Height: " + str(optMax) + " Ticks: " + str(optTicks)
答案 0 :(得分:5)
这是来自之前的类似问题:
Algorithm for "nice" grid line intervals on a graph
我用粗野的方式做到了这一点 力法。首先,搞清楚 你能得到的最大刻度数 适合空间。除以总数 数值范围的数量 蜱;这是最低 蜱的间距。现在计算 对数基数为10的地板 得到刻度的大小,和 除以这个值。你应该结束 在1到1的范围内 10.只需选择大于或等于值的圆数 乘以对数 早先算过。这是你的 最后的刻度线间距。
Python中的示例:
import math
def BestTick(largest, mostticks):
minimum = largest / mostticks
magnitude = 10 ** math.floor(math.log(minimum) / math.log(10))
residual = minimum / magnitude
if residual > 5:
tick = 10 * magnitude
elif residual > 2:
tick = 5 * magnitude
elif residual > 1:
tick = 2 * magnitude
else:
tick = magnitude
return tick
答案 1 :(得分:3)
过去我用蛮力的方式做到了这一点。这里有一大块C ++代码可以很好地工作......但对于硬编码的下限和上限(0和5000):
int PickYUnits()
{
int MinSize[8] = {20, 20, 20, 20, 20, 20, 20, 20};
int ItemsPerUnit[8] = {5, 10, 20, 25, 50, 100, 250, 500};
int ItemLimits[8] = {20, 50, 100, 250, 500, 1000, 2500, 5000};
int MaxNumUnits = 8;
double PixelsPerY;
int PixelsPerAxis;
int Units;
//
// Figure out the max from the dataset
// - Min is always 0 for a bar chart
//
m_MinY = 0;
m_MaxY = -9999999;
m_TotalY = 0;
for (int j = 0; j < m_DataPoints.GetSize(); j++) {
if (m_DataPoints[j].m_y > m_MaxY) {
m_MaxY = m_DataPoints[j].m_y;
}
m_TotalY += m_DataPoints[j].m_y;
}
//
// Give some space at the top
//
m_MaxY = m_MaxY + 1;
//
// Figure out the size of the range
//
double yRange = (m_MaxY - m_MinY);
//
// Pick the initial size
//
Units = MaxNumUnits;
for (int k = 0; k < MaxNumUnits; k++)
{
if (yRange < ItemLimits[k])
{
Units = k;
break;
}
}
//
// Adjust it upwards based on the space available
//
PixelsPerY = m_rcGraph.Height() / yRange;
PixelsPerAxis = (int)(PixelsPerY * ItemsPerUnit[Units]);
while (PixelsPerAxis < MinSize[Units]){
Units += 1;
PixelsPerAxis = (int)(PixelsPerY * ItemsPerUnit[Units]);
if (Units == 5)
break;
}
return ItemsPerUnit[Units];
}
然而,你所说的内容调整了我。要选择漂亮的轴编号,“漂亮编号”的定义会有所帮助:
不确定上述定义是否“正确”或实际上是否有用(但如果手头有定义,那么设计算法就变得更简单了。)
答案 2 :(得分:3)
你最多可以得到两个有效数字。以下伪代码应该有效:
// maxValue is the largest value in your chart
magnitude = floor(log10(maxValue))
base = 10^(magnitude - 1)
chartHeight = ceiling(maxValue / base) * base
例如,如果maxValue
为1357,则幅度为3,基数为100.除以100,向上舍入,再乘以100,得到舍入到下一个100的倍数的结果,即舍入最多两个重要数字。在这种情况下,结果如果1400(1357⇒13.57⇒14⇒1400)。
答案 3 :(得分:3)
稍微改进并测试......(适用于单位的分数而不仅仅是整数)
public void testNumbers() {
double test = 0.20000;
double multiple = 1;
int scale = 0;
String[] prefix = new String[]{"", "m", "u", "n"};
while (Math.log10(test) < 0) {
multiple = multiple * 1000;
test = test * 1000;
scale++;
}
double tick;
double minimum = test / 10;
double magnitude = 100000000;
while (minimum <= magnitude){
magnitude = magnitude / 10;
}
double residual = test / (magnitude * 10);
if (residual > 5) {
tick = 10 * magnitude;
} else if (residual > 2) {
tick = 5 * magnitude;
} else if (residual > 1) {
tick = 2 * magnitude;
} else {
tick = magnitude;
}
double curAmt = 0;
int ticks = (int) Math.ceil(test / tick);
for (int ix = 0; ix < ticks; ix++) {
curAmt += tick;
BigDecimal bigDecimal = new BigDecimal(curAmt);
bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP);
System.out.println(bigDecimal.stripTrailingZeros().toPlainString() + prefix[scale] + "s");
}
System.out.println("Value = " + test + prefix[scale] + "s");
System.out.println("Tick = " + tick + prefix[scale] + "s");
System.out.println("Ticks = " + ticks);
System.out.println("Scale = " + multiple + " : " + scale);
}
答案 4 :(得分:1)
如果你想要1400在顶部,如何将最后两个参数调整为1400而不是1357:
答案 5 :(得分:0)
你可以使用div和mod。例如。
假设你希望你的图表以20的增量向上舍入(只是为了使它更像是一个比典型的“10”值更多的数字)。
所以我认为1,11,18全部可以达到20个。但是21,33,38会变成40个。
要想出正确的值,请执行以下操作:
Where divisor = your rounding increment.
divisor = 20
multiple = maxValue / divisor; // Do an integer divide here.
if (maxValue modulus divisor > 0)
multiple++;
graphMax = multiple * maxValue;
现在让我们插入实数:
divisor = 20; multiple = 33 / 20; (integer divide) so multiple = 1 if (33 modulus 20 > 0) (it is.. it equals 13) multiple++; so multiple = 2; graphMax = multiple (2) * maxValue (20); graphMax = 40;