Как определить правильный домен для диапазона чисел для рисования линейного графика? - PullRequest
1 голос
/ 22 декабря 2011

Я хочу создать линейный график, но диапазон чисел различается, иногда он выглядит так:

1,2,5,8,10

, а иногда - как:

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

, изучая Excel и OpenOffice. Я понимаю, что они могут указывать диапазон что-то вроде:

minNumber - от k до maxNumber + k

, и они делят ось Y на равные области.

Существует ли какая-либо конкретная формула для этих действий?

Ответы [ 3 ]

1 голос
/ 22 декабря 2011

Я не на 100% убежден, что это вопрос программирования (хотя есть несколько приличных графических библиотек, которые можно использовать), но общая идея была бы такова.

У вас есть эти вопросыв, скажем, -5.Это 0-е значение, которое мы получили, поэтому для значения x, равного 0, мы помещаем -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 - вашенизкий.

1 голос
/ 22 декабря 2011

Когда я посмотрел на эту проблему, я обнаружил, что коммерческие продукты отлично справляются с расширением ассортимента настолько, что достигают приятных круглых чисел для своих отметок. Если это то, что вас интересует, посмотрите на этот код 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);
        }
    }
}
1 голос
/ 22 декабря 2011

Я думаю, что вы имеете в виду minNumber, а не meanNumber.

Формула близка к тому, что вы говорите.Ваш диапазон maxNumber - minNumber.Если вам нужно немного места с обеих сторон, добавьте 2k, где k - это пространство с любой стороны.Вы знаете, что ваш график имеет ширину Y пикселей.Y / диапазон - это количество пикселей на единицу для вашего графика.

Вы в основном применяете эту настройку при рисовании графика.Примените смещение на основе вашего минимума, а затем растяжение на основе вашего пикселя / единицы.

Таким образом, точка рисования X означает, что вы фактически рисуете с ((X - мин) / пикселей на единицу).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...