Algoritmo Gráfico (Gráfico)
Pergunta
Alguém tem um algoritmo decente para calcular mínimos e máximos dos eixos?
Ao criar um gráfico para um determinado conjunto de itens de dados, gostaria de poder fornecer o algoritmo:
- o valor máximo (y) no conjunto
- o valor mínimo (y) no conjunto
- o número de marcas de escala que aparecerão no eixo
- um valor opcional que deve aparecer como uma marca (por ex.zero ao mostrar valores +ve e -ve)
O algoritmo deve retornar
- o maior valor do eixo
- o menor valor do eixo (embora isso possa ser inferido do maior, o tamanho do intervalo e o número de ticks)
- o tamanho do intervalo
Os ticks devem estar em intervalos regulares e devem ser de tamanho "razoável" (por exemplo,1, 3, 5, possivelmente até 2,5, mas não há mais figos sig).
A presença do valor opcional distorcerá isso, mas sem esse valor o item maior deverá aparecer entre as duas marcas superiores, e o valor mais baixo entre as duas inferiores.
Esta é uma questão independente de linguagem, mas se houver uma biblioteca C#/.NET por aí, isso seria incrível;)
Solução
Eu tenho usado o jQuery flutuar biblioteca de gráficos.É de código aberto e gera muito bem eixos/tiques.Eu sugiro olhar seu código e extrair algumas idéias dele.
Outras dicas
OK, aqui está o que eu criei para um de nossos aplicativos.Observe que ele não trata do cenário de "valor opcional" que você mencionou, já que nosso valor opcional é sempre 0, mas não deve ser difícil modificá-lo.
Os dados são continuamente adicionados à série, portanto, apenas mantemos o intervalo de valores de y atualizado, inspecionando cada ponto de dados à medida que é adicionado;isso é muito barato e fácil de controlar.Valores mínimos e máximos iguais são casos especiais:um espaçamento 0 indica que nenhum marcador deve ser desenhado.
Esta solução não é diferente da sugestão de Andrew acima, exceto que ela lida, de uma forma um pouco confusa, com algumas frações arbitrárias do multiplicador de expoentes.
Por último, este exemplo está em C#.Espero que ajude.
private float GetYMarkerSpacing()
{
YValueRange range = m_ScrollableCanvas.
TimelineCanvas.DataModel.CurrentYRange;
if ( range.RealMinimum == range.RealMaximum )
{
return 0;
}
float absolute = Math.Max(
Math.Abs( range.RealMinimum ),
Math.Abs( range.RealMaximum ) ),
spacing = 0;
for ( int power = 0; power < 39; ++power )
{
float temp = ( float ) Math.Pow( 10, power );
if ( temp <= absolute )
{
spacing = temp;
}
else if ( temp / 2 <= absolute )
{
spacing = temp / 2;
break;
}
else if ( temp / 2.5 <= absolute )
{
spacing = temp / 2.5F;
break;
}
else if ( temp / 4 <= absolute )
{
spacing = temp / 4;
break;
}
else if ( temp / 5 <= absolute )
{
spacing = temp / 5;
break;
}
else
{
break;
}
}
return spacing;
}
Posso recomendar o seguinte:
- Defina um número mínimo visualmente atraente de linhas principais.Isso dependerá da natureza dos dados que você está apresentando e do tamanho do gráfico que você está fazendo, mas 7 é um número muito bom
- Escolha o expoente e o multiplicador com base em uma progressão de 1, 2, 5, 10, etc.isso lhe dará pelo menos o número mínimo de linhas principais.(ou seja.(max-min)/(escala x 10 ^ expoente) >= mínimo_tick_marks)
- Encontre o múltiplo inteiro mínimo do seu expoente e multiplicador que se ajusta ao seu intervalo.Este será o primeiro grande tick.O resto dos ticks são derivados disso.
Isso foi usado para um aplicativo que permitia o dimensionamento arbitrário de dados e parecia funcionar bem.