我想创建一个折线图,但数字的范围是不同的,有时它像:如何确定的数字范围的正确的域用于绘制线图?
1,2,5,8,10
,有时它像:
-5, - 1,4,5,15,第8,20,...
通过研究的Excel和OpenOffice我理解,他们可以指明的范围是这样的:
minNumber - k到MAXNUMBER + K
和它们划分Y轴成相等的区域。
有没有做这些事情的具体公式?
我想创建一个折线图,但数字的范围是不同的,有时它像:如何确定的数字范围的正确的域用于绘制线图?
1,2,5,8,10
,有时它像:
-5, - 1,4,5,15,第8,20,...
通过研究的Excel和OpenOffice我理解,他们可以指明的范围是这样的:
minNumber - k到MAXNUMBER + K
和它们划分Y轴成相等的区域。
有没有做这些事情的具体公式?
当我看到这个问题时,我发现商业产品在扩展范围方面做得非常好,足以实现令人满意的圆形数字作为刻度。如果这是你有兴趣,就来看看这个C#代码,我写了尝试不同的算法:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TickPicker
{
class TickPicker
{
double tickLow;
double tickHigh;
double tickUnit;
double tickCount;
//static double[] targetUnits = { 1, 2, 5, 10 };
static double[] targetUnits = { 1, 2, 2.5, 5, 10 };
static int[] roundFactors = { 1, 5, 4, 2, 1 };
//static double[] targetUnits = { 1, 1.5, 2.5, 5, 10 };
//static double[] targetUnits = { 1, 1.25, 2, 2.5, 5, 10 };
//static double[] targetUnits = { 1, 1.25, 1.5, 2, 2.5, 5, 10 };
//static double[] targetUnits = { 1, 1.25, 2, 5, 10 };
//static double[] targetUnits = { 1, 1.25, 1.5, 2, 5, 10 };
static double[] targetLogs = arrayLog(targetUnits);
TickPicker(double low, double high, int tickCountGoal)
{
double range = high - low;
double divGoal = range/(tickCountGoal - 2);
double logGoal = Math.Log10(divGoal);
double powerFactor = Math.Floor(logGoal);
logGoal = logGoal - powerFactor;
int closestIndex = findClosest(targetLogs, logGoal);
tickUnit = targetUnits[closestIndex] * (Math.Pow(10, powerFactor));
// Ensure the actual range encompasses the intended range
// The roundFactor discourages the .5 on the low and high range
int roundFactor = roundFactors[closestIndex];
tickLow = Math.Floor(low/tickUnit/roundFactor) * tickUnit * roundFactor;
tickHigh = Math.Ceiling(high/tickUnit/roundFactor) * tickUnit * roundFactor;
tickCount = (tickHigh - tickLow)/tickUnit;
}
static double[] arrayLog(double[] inputs)
{
double[] retVal = new double[inputs.Length];
int x = 0;
foreach (double input in inputs)
{
retVal[x] = Math.Log10(inputs[x]);
x++;
}
return retVal;
}
static int findClosest(double[] candidates, double input)
{
int low = 0;
for(int i = 1; i < candidates.Length && input > candidates[i]; i++)
{
low = i;
}
int high = low + 1;
return candidates[high] - input < input - candidates[low] ? high : low;
}
static void testPicker(double low, double high, int tickCountGoal)
{
TickPicker picker = new TickPicker(low, high, tickCountGoal);
System.Console.WriteLine("[{0}:{1}]/{2} gives [{3}:{4}] with {5} ticks of {6} units each.", low, high, tickCountGoal, picker.tickLow, picker.tickHigh, picker.tickCount, picker.tickUnit);
}
static void Main(string[] args)
{
testPicker(4.7, 39.2, 13);
testPicker(4.7, 39.2, 16);
testPicker(4.7, 39.2, 19);
testPicker(4.7, 39.2, 21);
testPicker(4.7, 39.2, 24);
testPicker(1967, 2011, 20);
testPicker(1967, 2011, 10);
testPicker(2.71, 3.14, 5);
testPicker(.0568, 13, 20);
}
}
}
我认为你的意思是minNumber而不是意味着数字。
的公式是接近你说什么。你的范围是maxNumber - minNumber。如果你想在任何一方添加2k空间,其中k是任何一方的空间。你知道你的图是Y像素宽。 Y /范围是图形每单位有多少个像素。
您在绘制图形时主要应用此调整。根据你的最小值,然后根据你的像素/单位应用一个移位。
所以绘制点X意味着您实际上以((X - min)/像素/单位)绘图。
我并不是100%确信这是一个编程问题(尽管可以使用一小部分图形库),但总体思路是这样的。
你有这些点进来,让我们说-5。这是我们收到的第0个值,因此对于0的x值,我们把-5在y轴。我们重复了-1,4等
所以,你会得到一个列表看起来像这样(比喻):
X | Y
0 | -5
1 | -1
2 | 4
3 | 5
4 | 15
结果是散点图(不是线),但有是Excel中的工具,可以帮助你。
[编辑]为了得到它作为实际的功能,可以使用以下形式:
的y Y_1 = M(X-X_1)
,其中M =(Y_2-Y_1)/( X_2-X_1),Y_2是你的最高y值,Y_1是你最低的,X_2是您最高的x值,和X_1是你最低的。
假设我们有很多的数字说,像1000,然后显示在X这些多号轴是不正确的,并且在Y轴上显示每个精确值也不好,这就是为什么我们需要有一个范围。我知道有很多libs,但我正在寻找的算法! – 2011-12-21 20:12:57
我不是100%确定我理解你的问题。你是说你正在寻找一个算法来绘制1,000或更多的数字,或者只是极端点?上面的公式[(线性方程式)](http://en.wikipedia.org/wiki/Linear_equation)会给你这条线,如果你只是采取数据集中的两个极端点。 – Makoto 2011-12-21 21:08:43
coooooooooool这就是我所能说的。 – 2011-12-23 17:16:16
想知道你是怎么结束这个算法的?实际上热衷于更多地了解这些问题以及如何解决这些问题。感谢您是否可以给我建议。 – 2011-12-24 02:04:17
我没有一个正式的算法,尽管可能有它的名字,我只是无知。我只知道它必须是对数的,并且在这个时候摆弄它。 – 2011-12-24 03:54:25