【问题标题】:how to determine a correct domain for a range of numbers for drawing a line-graph?如何确定用于绘制折线图的一系列数字的正确域?
【发布时间】:2011-12-21 20:00:00
【问题描述】:

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

1,2,5,8,10

有时像这样:

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

通过研究 excel 和 openoffice,我了解到它们可以指示一个范围,例如:

minNumber - k 到 maxNumber + k

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

有什么具体的公式可以做这些事情吗?

【问题讨论】:

    标签: java graphics graph


    【解决方案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);
            }
        }
    }
    

    【讨论】:

    • coooooooooool 我只能说。
    • 想知道你是怎么得到这个算法的?实际上热衷于更多地了解这些问题以及如何解决它们。如果您能给我建议,不胜感激。
    • 我没有一个正式的算法开始,虽然它可能有一个名字而且我只是不知道它。我只知道它必须是对数的,并且一直在摆弄它。
    【解决方案2】:

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

    公式和你说的很接近。您的范围是 maxNumber - minNumber。如果你想要两边的空间加 2k,k 是两边的空间。你知道你的图表是 Y 像素宽。 Y/范围是您的图表每单位有多少像素。

    您基本上是在绘制图形时应用此调整。根据您的最小值应用移位,然后根据您的像素/单位应用拉伸。

    所以绘制点 X 意味着您实际上是在 ((X - min) / 像素/单位) 绘制。

    【讨论】:

      【解决方案3】:

      我不是 100% 相信这是一个编程问题(尽管可以使用的图形库屈指可数),但总体思路是这样的。

      你有这些分数,比如说-5。这是我们收到的第 0 个值,所以对于 0 的 x 值,我们将 -5 放在 y 轴上。我们重复 -1、4 等。

      所以,你会得到一个看起来像这样的列表(形象地):

      X   |    Y
      0   |   -5
      1   |   -1
      2   |   4
      3   |   5
      4   |   15
      

      结果是一个散点图(不是一条线),但 Excel 中有工具可以为您获取。

      [EDIT] 要将其作为一个实际函数,您可以使用以下形式:

      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 轴上显示每个准确的值也不好,这也是我们需要有的原因一个范围。我知道那里有很多库,但我正在寻找的是算法!
      • 那么,我不能 100% 确定我理解你的问题。你是说你正在寻找一种算法来绘制 1,000 个或更多数字,或者只是极值点?如果你只取数据集中的两个极值点,上面的公式(Linear Equation) 会给你一条线。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-08-12
      • 1970-01-01
      • 2013-05-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多