如何为绘制线图的一系列数字确定正确的域?

时间:2011-12-21 20:00:01

标签: java graphics graph

我想创建一个折线图,但数字的范围有时会有所不同:

1,2,5,8,10

有时候就像:

-5,-1,4,5,15,8,20,......

通过研究excel和openoffice我明白他们可以指出一个类似的范围:

minNumber - k到maxNumber + k

他们将Y轴分成相等的区域。

有没有具体的公式来做这些事情?

3 个答案:

答案 0 :(得分:1)

我认为你的意思是minNumber而不是meanNumber。

这个公式接近你所说的。你的范围是maxNumber - minNumber。如果你想在任何一侧增加2k的空间,其中k是任何一方的空间。您知道您的图表是Y像素宽。 Y /范围是图表每单位有多少像素。

您在绘制图形时基本上应用此调整。根据你的min应用一个移位,然后根据你的像素/单位应用一个strech。

因此绘制点X意味着您实际绘制的是((X - min)/每单位像素数。)

答案 1 :(得分:1)

我不是100%确信这是一个编程问题(虽然有一些可以使用的图形库很少),但总体思路是这样的。

你有这些要点,比方说-5。这是我们收到的第0个值,因此对于x值为0,我们在y轴上放置-5。我们重复-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是你的最低值。

答案 2 :(得分:1)

当我看到这个问题时,我发现商业产品在扩展范围方面做得很好,足以为他们的刻度线获得令人愉悦的圆形数字。如果这是您感兴趣的内容,请查看我编写的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);
        }
    }
}