Pergunta

Eu preciso fazer um gráfico com um otimizado y eixo valor máximo.

O método atual que tenho de fazer gráficos simplesmente usa o valor máximo de todos os gráficos, em seguida, divide-o por dez, e usa como linhas de grade. Eu não escrevê-lo.

Atualização Nota: Estes gráficos foram alterados. Assim que fixa o código, meus gráficos dinâmicos começou a trabalhar, fazendo esta pergunta sem sentido (porque os exemplos já não tinha quaisquer erros neles). Eu atualizei estes com imagens estáticas, mas algumas das respostas refrence valores diferentes. Tenha isso em mente. Gráfico Antigo Havia entre 12003 e 14003 chamadas recebidas até agora em fevereiro. Informativo, mas feio.

Eu gostaria de evitar gráficos que olhar como um macaco veio com a y -axis números.

Usando o gráficos API Google ajuda um pouco, mas ainda não é bem o que eu quero. API do Google Chart Os números são limpos, mas a parte superior do valor de y é sempre o mesmo que o valor máximo no gráfico. Este gráfico escalas de 0 a 1357. Eu preciso ter calculado o valor adequado de 1400, problematicamente .


Eu estou jogando em rbobby 's defanition de um' bom 'número aqui porque explica muito bem.

  • Um número "agradável" é uma que tem 3 ou menos dígitos diferentes de zero (por ex. 1230000)
  • Um número "bom" tem as mesmas ou alguns dígitos diferentes de zero a zero dígitos (por exemplo, 1230 não é agradável, 1200 é bom)
  • Os números mais agradáveis ??são aqueles com múltiplos de 3 zeros (ex. "1000", "1000000")
  • O segundo números mais agradáveis ??são onces com multples de 3 zeros mais 2 zeros (por ex. "1500000", "1200")

Solução

Novo Gráfico

Eu encontrei a maneira de obter os resultados que eu quero usar uma versão modificada da idéia de Mark Ransom.

Punho, código de Mark Ransom determina o espaçamento ideal entre carrapatos, quando dado o número de carrapatos. Às vezes este número acaba sendo mais do que o dobro do que o valor mais alto no gráfico é, dependendo de quantas linhas de grade que quiser.

O que estou fazendo é que eu estou correndo de código de Mark com 5, 6, linhas 7, 8, 9 e 10 de grade (carrapatos) para descobrir qual delas é a mais baixa. Com um valor de 23, a altura do gráfico vai para 25, com uma linha de grelha a 5, 10, 15, 20, e 25. Com um valor de 26, altura do gráfico é 30, com linhas de grade, a 5, 10 , 15, 20, 25 e 30. Ele tem o mesmo espaçamento entre linhas de grade, mas há mais deles.

Então aqui está os passos para just-sobre cópia que Excel faz para fazer gráficos tudo fantasia.

  1. Temporariamente bata até maior valor do gráfico de cerca de 5% (de modo que há sempre algum espaço entre o ponto mais alto do gráfico ea parte superior da área do gráfico. Queremos 99,9 para arredondar para cima a 120)
  2. Encontre a colocação linha ideal grade para 5, 6, 7, 8, 9, e 10 grade linhas.
  3. Escolha o menor desses números. Lembre-se o número de linhas de grade que levou para obter esse valor.
  4. Agora você tem a altura ideal gráfico. O linhas / bar nunca vai intrometer-se contra o topo da tabela e você tem o número ideal de carrapatos.

PHP:

function roundUp($maxValue){
    $optiMax = $maxValue * 2;
    for ($i = 5; $i <= 10; $i++){
        $tmpMaxValue = bestTick($maxValue,$i);
        if (($optiMax > $tmpMaxValue) and ($tmpMaxValue > ($maxValue + $maxValue * 0.05))){
            $optiMax = $tmpMaxValue;
            $optiTicks = $i;
        }
    }
    return $optiMax;
}
function bestTick($maxValue, $mostTicks){
    $minimum = $maxValue / $mostTicks;
    $magnitude = pow(10,floor(log($minimum) / log(10)));
    $residual = $minimum / $magnitude;
    if ($residual > 5){
        $tick = 10 * $magnitude;
    } elseif ($residual > 2) {
        $tick = 5 * $magnitude;
    } elseif ($residual > 1){
        $tick = 2 * $magnitude;
    } else {
        $tick = $magnitude;
    }
    return ($tick * $mostTicks);
}

Python:

import math

def BestTick(largest, mostticks):
    minimum = largest / mostticks
    magnitude = 10 ** math.floor(math.log(minimum) / math.log(10))
    residual = minimum / magnitude
    if residual > 5:
        tick = 10 * magnitude
    elif residual > 2:
        tick = 5 * magnitude
    elif residual > 1:
        tick = 2 * magnitude
    else:
        tick = magnitude
    return tick

value = int(input(""))
optMax = value * 2
for i in range(5,11):
    maxValue = BestTick(value,i) * i
    print maxValue
    if (optMax > maxValue) and (maxValue > value  + (value*.05)):
        optMax = maxValue
        optTicks = i
print "\nTest Value: " + str(value + (value * .05)) + "\n\nChart Height: " + str(optMax) + " Ticks: " + str(optTicks)
Foi útil?

Solução

Esta é a partir de uma pergunta semelhante anterior:

Algoritmo para intervalos de linha de grade "nice" em um gráfico

Eu fiz isso com uma espécie de brute método de força. Em primeiro lugar, descobrir a número máximo de marcas de escala que você pode caber no espaço. Dividir o total a faixa de valores ao número de carrapatos; Isso é o mínimo espaçamento da carraça. agora calcule o chão do logaritmo de base 10 a obter a magnitude do carrapato, e dividir por este valor. Você deve acabar -se com algo na faixa de 1 a 10. Basta escolher o número maior rodada ou igual ao valor e multiplicá-lo pelo logaritmo calculado anteriormente. Isto é seu espaçamento carrapato final.

Exemplo em Python:

import math

def BestTick(largest, mostticks):
    minimum = largest / mostticks
    magnitude = 10 ** math.floor(math.log(minimum) / math.log(10))
    residual = minimum / magnitude
    if residual > 5:
        tick = 10 * magnitude
    elif residual > 2:
        tick = 5 * magnitude
    elif residual > 1:
        tick = 2 * magnitude
    else:
        tick = magnitude
    return tick

Outras dicas

No passado, eu fiz isso em um bruto tipo força-ish do caminho. Aqui está um pedaço de código C ++ que funciona bem ... mas por limites hardcoded inferiores e superiores (0 e 5000):

int PickYUnits()
{
    int MinSize[8] = {20, 20, 20, 20, 20, 20, 20, 20};
    int ItemsPerUnit[8] = {5, 10, 20, 25, 50, 100, 250, 500};
    int ItemLimits[8] = {20, 50, 100, 250, 500, 1000, 2500, 5000};
    int MaxNumUnits = 8;
    double PixelsPerY;
    int PixelsPerAxis;
    int Units;

    //
    // Figure out the max from the dataset
    //  - Min is always 0 for a bar chart
    //
    m_MinY = 0;
    m_MaxY = -9999999;
    m_TotalY = 0;
    for (int j = 0; j < m_DataPoints.GetSize(); j++) {
        if (m_DataPoints[j].m_y > m_MaxY) {
            m_MaxY = m_DataPoints[j].m_y;
        }

        m_TotalY += m_DataPoints[j].m_y;
    }

    //
    // Give some space at the top
    //
    m_MaxY = m_MaxY + 1;


    //
    // Figure out the size of the range
    //
    double yRange = (m_MaxY - m_MinY);

    //
    // Pick the initial size
    //
    Units = MaxNumUnits;
    for (int k = 0; k < MaxNumUnits; k++)
    {
        if (yRange < ItemLimits[k])
        {
            Units = k;
            break;
        }
    }

    //
    // Adjust it upwards based on the space available
    //
    PixelsPerY = m_rcGraph.Height() / yRange;
    PixelsPerAxis = (int)(PixelsPerY * ItemsPerUnit[Units]);

    while (PixelsPerAxis < MinSize[Units]){
        Units += 1;
        PixelsPerAxis = (int)(PixelsPerY * ItemsPerUnit[Units]);
        if (Units == 5)
            break;
    }


    return ItemsPerUnit[Units];
}

No entanto algo em que você disse me mexido. Para escolher números eixo agradáveis ??uma definição de "bom número" ajudaria:

  • Um número "agradável" é uma que tem 3 ou menos dígitos diferentes de zero (por ex. 1230000)
  • Um número "bom" tem as mesmas ou alguns dígitos diferentes de zero a zero dígitos (por exemplo, 1230 não é agradável, 1200 é bom)
  • Os números mais agradáveis ??são aqueles com múltiplos de 3 zeros (ex. "1000", "1000000")
  • O segundo números mais agradáveis ??são onces com multples de 3 zeros mais 2 zeros (por ex. "1500000", "1200")

Não tenho certeza se a definição acima é "certo" ou realmente útil (mas com a definição na mão torna-se então uma tarefa mais simples para elaborar um algoritmo).

Você poderia arredondar para dois algarismos significativos. O seguinte pseudocódigo deve funcionar:

// maxValue is the largest value in your chart
magnitude = floor(log10(maxValue))
base = 10^(magnitude - 1)
chartHeight = ceiling(maxValue / base) * base

Por exemplo, se é maxValue 1357, então magnitude é 3 e a base é 100. Dividindo por 100, o arredondamento para cima, e multiplicando por 100 tem o resultado do arredondamento para cima para o próximo múltiplo de 100, ou seja, o arredondamento para cima para duas significativa figuras. Neste caso, o resultado se 1400 (1357 ? 13,57 ? 14 ? 1400).

Um ligeiro refinamento e testado ... (obras por frações de unidades e não apenas números inteiros)

public void testNumbers() {
        double test = 0.20000;

        double multiple = 1;
        int scale = 0;
        String[] prefix = new String[]{"", "m", "u", "n"};
        while (Math.log10(test) < 0) {
            multiple = multiple * 1000;
            test = test * 1000;
            scale++;
        }

        double tick;
        double minimum = test / 10;
        double magnitude = 100000000;
        while (minimum <= magnitude){
            magnitude = magnitude / 10;
        }

        double residual = test / (magnitude * 10);
        if (residual > 5) {
            tick = 10 * magnitude;
        } else if (residual > 2) {
            tick = 5 * magnitude;
        } else if (residual > 1) {
            tick = 2 * magnitude;
        } else {
            tick = magnitude;
        }

        double curAmt = 0;

        int ticks = (int) Math.ceil(test / tick);

        for (int ix = 0; ix < ticks; ix++) {
            curAmt += tick;
            BigDecimal bigDecimal = new BigDecimal(curAmt);
            bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP);
            System.out.println(bigDecimal.stripTrailingZeros().toPlainString() + prefix[scale] + "s");
        }

        System.out.println("Value = " + test + prefix[scale] + "s");
        System.out.println("Tick = " + tick + prefix[scale] + "s");
        System.out.println("Ticks = " + ticks);
        System.out.println("Scale = " +  multiple + " : " + scale);


    }

Se você quiser 1400 no topo, como sobre como ajustar os dois últimos parâmetros a 1400 em vez de 1357:

text alt

Você pode usar div e mod. Por exemplo.

Vamos dizer que você quer que seu gráfico para cima rodada em incrementos de 20 (apenas para torná-lo mais um número mais arbitrário do que o seu "10" valor típico).

Então, eu diria que 1, 11, 18 faria todo até 20. Mas 21, 33, 38 seria rodada a 40.

Para chegar com o valor correto faça o seguinte:

Where divisor = your rounding increment.

divisor = 20
multiple = maxValue / divisor;  // Do an integer divide here. 
if (maxValue modulus divisor > 0)
   multiple++;

graphMax = multiple * maxValue;

Então agora vamos plugin de números reais:

divisor = 20;
multiple = 33 / 20; (integer divide)
so multiple = 1
if (33 modulus 20 > 0)  (it is.. it equals 13) 
   multiple++;

so multiple = 2;
graphMax = multiple (2) * maxValue (20);
graphMax = 40;
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top