2011-03-19 23 views
10

He estado buscando en la red desde hace un tiempo y todavía no he encontrado ninguna solución a mi problema. Quiero hacer que MS Chart cambie automáticamente el eje Y al desplazarse para asegurarse de que todos los puntos de datos estén visibles. El giro aquí es que necesito tener la capacidad de excluir ciertas series para que no se usen para la escala automática. Hasta ahora solo encontré soluciones que ofrecen iterar a través de toda la colección de puntos en el evento AxisViewChanged, que no funciona bien cuando tienes grandes colecciones de puntos y algunas series para iterar. Me preguntaba si había alguna manera de reducir la búsqueda obteniendo puntos de datos que están entre los valores min y max X actualmente visibles. Cualquier ayuda sería apreciada.Chart Control eje Y escala automática en el desplazamiento

Editar Aquí está la imagen. Como puede ver, las velas en el medio no son del todo visibles. enter image description here

+1

Mmh no está claro para mí ... ¿desea volver a escalar el eje Y mientras se desplaza el eje X, ¿verdad? De lo contrario, no tiene sentido para mí. Por cierto, ¿podrías dar un ejemplo visual de lo que necesitas? – digEmAll

+0

@digEmAll Sí, es correcto –

Respuesta

6

puede probar este código

 DateTime date = DateTime.Now; 
     chart1.ChartAreas[0].AxisX.Minimum = 0; 
     chart1.ChartAreas[0].AxisX.Maximum = 20; 
     Random r = new Random((int)date.Ticks); 

     chart1.Series[0].ChartType = SeriesChartType.Candlestick; 
     chart1.Series[0].Color = Color.Green; 
     chart1.Series[0].XValueType = ChartValueType.Time; 
     chart1.Series[0].IsXValueIndexed = true; 
     chart1.Series[0].YValuesPerPoint = 4; 
     chart1.Series[0].CustomProperties = "MaxPixelPointWidth=10"; 
     for (int i = 0; i < 100; i++) 
     { 
      DataPoint point = new DataPoint(date.AddHours(i).ToOADate(), new double[] { r.Next(10, 20), r.Next(30, 40), r.Next(20, 30), r.Next(20, 30) }); 
      chart1.Series[0].Points.Add(point); 
     } 

     int min = (int)chart1.ChartAreas[0].AxisX.Minimum; 
     int max = (int)chart1.ChartAreas[0].AxisX.Maximum; 

     if (max > chart1.Series[0].Points.Count) 
      max = chart1.Series[0].Points.Count; 

     var points = chart1.Series[0].Points.Skip(min).Take(max - min); 

     var minValue = points.Min(x => x.YValues[0]); 
     var maxValue = points.Max(x => x.YValues[1]); 

     chart1.ChartAreas[0].AxisY.Minimum = minValue; 
     chart1.ChartAreas[0].AxisY.Maximum = maxValue; 

enter image description here

+0

@Stecya. Tengo DateTime como el valor X que hace que el valor máximo sea mucho más bajo que el valor mínimo, por lo que los puntos resultan ser una colección vacía. –

+0

puede usar 'chart1.Series [0] .IsXValueIndexed = true;' luego el valor x será entero y las etiquetas seguirán siendo DateTime – Stecya

+0

@Stecya. Pero esto eliminaría todas las lagunas vacías en el eje X, ¿no? –

5

utilizar una consulta para averiguar qué serie que desea utilizar para encontrar ymin e ymax en el código.

private void chart1_AxisViewChanged(object sender, ViewEventArgs e) 
    { 
     if (e.Axis.AxisName == AxisName.X) 
     { 
      int start = (int)e.Axis.ScaleView.ViewMinimum; 
      int end = (int)e.Axis.ScaleView.ViewMaximum; 

      // Series ss = chart1.Series.FindByName("SeriesName"); 
      // use ss instead of chart1.Series[0] 

      double[] temp = chart1.Series[0].Points.Where((x, i) => i >= start && i <= end).Select(x => x.YValues[0]).ToArray(); 
      double ymin = temp.Min(); 
      double ymax = temp.Max(); 

      chart1.ChartAreas[0].AxisY.ScaleView.Position = ymin; 
      chart1.ChartAreas[0].AxisY.ScaleView.Size = ymax - ymin; 
     } 
    } 
3

Ésta es una pequeña mejora en la excelente presentación de Shivaram K R, para evitar la caída de abrir, cerrar y baja de la parte inferior de los puntos más bajos en los gráficos financieros con cuatro valores de Y: alto,, apertura y cierre bajo.

// The following line goes in your form constructor 
this.chart1.AxisViewChanged += new EventHandler<ViewEventArgs> (this.chart1_AxisViewChanged); 


private void chart1_AxisViewChanged(object sender, ViewEventArgs e) 
{ 
    if (e.Axis.AxisName == AxisName.X) 
    { 
     int start = (int)e.Axis.ScaleView.ViewMinimum; 
     int end = (int)e.Axis.ScaleView.ViewMaximum; 
     // Use two separate arrays, one for highs (same as temp was in Shavram's original) 
     // and a new one for lows which is used to set the Y axis min. 
     double[] tempHighs = chart1.Series[0].Points.Where((x, i) => i >= start && i <= end).Select(x => x.YValues[0]).ToArray(); 
     double[] tempLows = chart1.Series[0].Points.Where((x, i) => i >= start && i <= end).Select(x => x.YValues[1]).ToArray(); 
     double ymin = tempLows.Min(); 
     double ymax = tempHighs.Max(); 

     chart1.ChartAreas[0].AxisY.ScaleView.Position = ymin; 
     chart1.ChartAreas[0].AxisY.ScaleView.Size = ymax - ymin; 
    } 
} 
0

Sobre la base de las respuestas anteriores

private void chart1_AxisViewChanged(object sender, ViewEventArgs e) 
    { 
     if(e.Axis.AxisName == AxisName.X) 
     { 
      int start = (int)e.Axis.ScaleView.ViewMinimum; 
      int end = (int)e.Axis.ScaleView.ViewMaximum; 

      List<double> allNumbers = new List<double>(); 

      foreach(Series item in chart1.Series) 
       allNumbers.AddRange(item.Points.Where((x, i) => i >= start && i <= end).Select(x => x.YValues[0]).ToList()); 

      double ymin = allNumbers.Min(); 
      double ymax = allNumbers.Max(); 

      chart1.ChartAreas[0].AxisY.ScaleView.Position = ymin; 
      chart1.ChartAreas[0].AxisY.ScaleView.Size = ymax - ymin; 
     } 
    } 

Podría ser usted tiene más series en el ChartArea. En este caso, elige las series alta y baja de todas las áreas en lugar de solo una.

cordiales,

Matthijs

0

Por encima de las respuestas fueron muy útiles para mí. Sin embargo, tengo un gráfico con múltiples áreas de gráficos. He adaptado el código para ampliarlo a todas las áreas de gráfico:

foreach (ChartArea area in chart1.ChartAreas) 
    { 
     List<double> allNumbers = new List<double>(); 

     foreach (Series item in chart1.Series) 
     if (item.ChartArea == area.Name) 
      allNumbers.AddRange(item.Points.Where((x, i) => i >= start && i <= end).Select(x => x.YValues[0]).ToList()); 

     double ymin = allNumbers.Min(); 
     double ymax = allNumbers.Max(); 

     if (ymax > ymin) 
     { 
     double offset = 0.02 * (ymax - ymin); 
     area.AxisY.Maximum = ymax + offset; 
     area.AxisY.Minimum = ymin - offset; 
     } 
    } 
Cuestiones relacionadas