如何确定绘制线图的一系列数字的正确域? [英] how to determine a correct domain for a range of numbers for drawing a line-graph?

查看:107
本文介绍了如何确定绘制线图的一系列数字的正确域?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建一个线图,但是数字的范围有时与它不一样:

<1,2,5,8,10



有时候也是这样:

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



通过学习excel和openoffice,我明白它们可以表示一个范围类似于:

minNumber - k to maxNumber + k

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

是否有任何特定的公式当我看到这个问题时,我发现商业产品在扩展范围方面做得不错,可以达到足够的效果令人愉快的圆形数字为他们的刻度。如果这是您感兴趣的内容,请查看我编写的这个C#代码以尝试不同的算法:

 使用系统; 
使用System.Collections.Generic;
使用System.Linq;
使用System.Text;

名称空间TickPicker
{
类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(双低,双高,int tickCountGoal)
{
双倍范围=高 - 低;
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));
//确保实际范围包含目标范围
// roundFactor不鼓励在低和高范围中的.5
int roundFactor = roundFactors [closestIndex];
tickLow = Math.Floor(低/ 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(输入中的双输入)
{
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;
返回候选人[高] - 输入<输入 - 候选人[低]?前高后低;
}

静态无效testPicker(双低,双高,nt tickCountGoal)
{
TickPicker picker = new TickPicker(low,high,tickCountGoal);
System.Console.WriteLine([{0}:{1}] / {2}给出{5}个{6}个单位的{[3}:{4}],低,高,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);
}
}
}


I want to create a line graph but the range of numbers are different sometimes its like :

1,2,5,8,10

and sometimes its like :

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

by studying excel and openoffice I understand that they can indicate a range something like :

minNumber - k to maxNumber + k

and they divide the Y axis into equal area.

is there any specific formula for doing these things ?

解决方案

When I looked at this problem I found that commercial products do a nice job of extending the range just enough to achieve pleasingly nice round numbers for their tick marks. If this is something you are interested in, take a look at this C# code that I wrote to try out different algorithms:

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);
        }
    }
}

这篇关于如何确定绘制线图的一系列数字的正确域?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆