standard algorithms algorithm math charts

algorithms - standard algorithm multiplication



Escalado razonable de gráficos optimizado (6)

En el pasado, he hecho esto en una especie de fuerza bruta. Aquí hay un fragmento de código C ++ que funciona bien ... pero para un límite inferior y superior codificado (0 y 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]; }

Sin embargo, algo en lo que me has dicho me ha modificado. Para elegir buenos números de ejes, una definición de "buen número" ayudaría:

  • Un número "agradable" es aquel que tiene 3 o menos dígitos distintos de cero (por ejemplo, 1230000)
  • Un número "bueno" tiene los mismos o pocos dígitos distintos de cero que cero dígitos (por ejemplo, 1230 no es agradable, 1200 es bueno)
  • Los números más bonitos son los que tienen múltiplos de 3 ceros (por ejemplo, "1,000", "1,000,000")
  • Los segundos números más bonitos son onces con múltiplos de 3 ceros más 2 ceros (p. Ej., "1,500,000", "1,200")

No estoy seguro de si la definición anterior es "correcta" o realmente útil (pero con la definición en mano, entonces se convierte en una tarea más sencilla idear un algoritmo).

Necesito hacer una tabla con un valor máximo optimizado del eje y .

El método actual que tengo para hacer gráficos simplemente usa el valor máximo de todos los gráficos, luego lo divide por diez y lo usa como líneas de cuadrícula. Yo no lo escribí

Nota de actualización: estos gráficos han sido cambiados. Tan pronto como arreglé el código, mis gráficos dinámicos comenzaron a funcionar, lo que hizo que esta pregunta no tuviera sentido (porque los ejemplos ya no tenían ningún error en ellos). Los actualicé con imágenes estáticas, pero algunas de las respuestas refirieron diferentes valores. Mantenlo en mente. alt text http://i42.tinypic.com/nwzr5s.jpg Hubo entre 12003 y 14003 llamadas entrantes en lo que va de febrero. Informativo, pero feo

Me gustaría evitar los gráficos que parecen un mono que tiene los números del eje y .

Usar el API de gráficos de Google ayuda un poco, pero todavía no es lo que quiero. Los números están limpios, pero la parte superior del valor y es siempre la misma que el valor máximo en el gráfico. Esta tabla escala de 0 a 1357. Necesito haber calculado el valor correcto de 1400, de forma problemática .

Estoy lanzando la definición de rbobby de un número "bueno" aquí porque lo explica muy bien.

  • Un número "agradable" es aquel que tiene 3 o menos dígitos distintos de cero (por ejemplo, 1230000)
  • Un número "bueno" tiene los mismos o pocos dígitos distintos de cero que cero dígitos (por ejemplo, 1230 no es agradable, 1200 es bueno)
  • Los números más bonitos son los que tienen múltiplos de 3 ceros (por ejemplo, "1,000", "1,000,000")
  • Los segundos números más bonitos son onces con múltiplos de 3 ceros más 2 ceros (p. Ej., "1,500,000", "1,200")

Solución

alt text http://i43.tinypic.com/21jc0no.png Encontré la manera de obtener los resultados que quiero usando una versión modificada de la idea de Mark Ransom.

En primer lugar, el código de Mark Ransom determina el espaciado óptimo entre los tics, cuando se le da el número de tics. A veces, este número termina siendo más del doble del valor más alto en el gráfico, dependiendo de la cantidad de líneas de cuadrícula que desee.

Lo que estoy haciendo es ejecutar el código de Mark con 5, 6, 7, 8, 9 y 10 líneas de cuadrícula (marcas) para encontrar cuál de ellas es la más baja. Con un valor de 23, la altura del gráfico va a 25, con una línea de cuadrícula en 5, 10, 15, 20 y 25. Con un valor de 26, la altura del gráfico es 30, con líneas de cuadrícula en 5, 10 , 15, 20, 25 y 30. Tiene el mismo espacio entre las líneas de cuadrícula, pero hay más de ellos.

Así que aquí están los pasos para simplemente copiar lo que Excel hace para hacer que los gráficos sean elegantes.

  1. Aumente temporalmente el valor más alto del gráfico en aproximadamente un 5% (de modo que siempre haya algo de espacio entre el punto más alto del gráfico y la parte superior del área del gráfico. Queremos que 99.9 redondee hasta 120)
  2. Encuentre la ubicación óptima de la línea de cuadrícula para 5, 6, 7, 8, 9 y 10 líneas de cuadrícula.
  3. Elija el más bajo de esos números. Recuerde la cantidad de líneas de cuadrícula que tomó para obtener ese valor.
  4. Ahora tiene la altura óptima del gráfico. Las líneas / barra nunca chocarán contra la parte superior del gráfico y usted tendrá la cantidad óptima de tics.

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

Pitón:

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)


Esto es de una pregunta similar anterior:

Algoritmo de intervalos de línea de cuadrícula "agradables" en un gráfico

He hecho esto con un método de fuerza bruta. Primero, determine la cantidad máxima de marcas que puede caber en el espacio. Divida el rango total de valores por el número de tics; este es el espaciamiento mínimo de la marca. Ahora calcule el piso de la base del logaritmo 10 para obtener la magnitud de la marca, y divida por este valor. Debería terminar con algo en el rango de 1 a 10. Simplemente elija el número de ronda mayor o igual que el valor y multiplíquelo por el logaritmo calculado anteriormente. Este es tu espacio de tilde final.

Ejemplo en 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


Podrías usar div y mod. Por ejemplo.

Digamos que desea que su tabla se redondee en incrementos de 20 (solo para hacerlo más un número más arbitrario que su valor típico de "10").

Así que supondría que 1, 11, 18 redondearían hasta 20. Pero 21, 33, 38 redondearían a 40.

Para obtener el valor correcto haga lo siguiente:

Where divisor = your rounding increment. divisor = 20 multiple = maxValue / divisor; // Do an integer divide here. if (maxValue modulus divisor > 0) multiple++; graphMax = multiple * maxValue;

Así que ahora vamos a agregar números reales:

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;


Puedes redondear hasta dos figuras significativas. El siguiente pseudocódigo debería funcionar:

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

Por ejemplo, si maxValue es 1357, entonces la magnitud es 3 y la base es 100. Dividir por 100, redondear y multiplicar por 100 tiene el resultado de redondear al siguiente múltiplo de 100, es decir, redondear hasta dos cifras significativas. En este caso, el resultado es 1400 (1357 ⇒ 13.57 ⇒ 14 ⇒ 1400).


Si quiere 1400 en la parte superior, ¿qué le parece si ajusta los últimos dos parámetros a 1400 en lugar de 1357?


Un ligero refinamiento y probado ... (funciona para fracciones de unidades y no solo enteros)

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