2009-09-14 2 views
8

Мне нужна помощь, которая может программно отображать больше точек, чем может поместиться в одну серию Excel.C#/Excel: рабочий максимум Максимальный размер серии на диаграмме

В соответствии с http://office.microsoft.com/en-us/excel/HP100738491033.aspx максимальное количество точек, отображаемых на диаграмме Excel 2007, составляет 256000. Учитывая, что каждая серия закрывается на 32000 точек, для построения целых 256000 точек требуется 8 рядов. Мой клиент требует построения максимального количества точек на диаграмму из-за больших наборов данных, с которыми мы работаем.

У меня умеренный опыт взаимодействия с C#/Excel, поэтому я подумал, что было бы легко запрограммировать рабочий лист, а затем прокручивать каждый набор из 32000 точек и добавлять их к графику в виде серии, останавливаясь, когда данные будут полностью или 8-й серии. Если цвет правильно окрашен, серия 8 будет визуально неотличима от одной серии.

К сожалению, я здесь. Основной проблемой я сталкиваюсь является:

(full size) The maximum number of datapoints you can use in a data series for a 2-D chart is 32,000... http://img14.imageshack.us/img14/9630/errormessagen.png

Всплывающее, как ни странно, появляется, когда я исполняю строку:

chart.ChartType = chartType (where chartType is xlXYScatterLines) http://img2.imageshack.us/img2/2413/linean.png

и сопровождается:

Exception from HRESULT: 0x800AC472 http://img21.imageshack.us/img21/5153/exceptionb.png

Я не понимаю, как я мог бы генерировать такое всплывающее окно/предупреждение/исключение, прежде чем я даже укажу данные, которые нужно графипировать. Здесь Excel пытается быть умным?

Как временное обходное решение, я поместил инструкцию chart.ChartType = chartType в блок try-catch, чтобы я мог продолжать работу.

Как показано ниже, мой код «chunking» работает по назначению, но я все еще сталкиваюсь с той же проблемой при попытке добавить данные на график. Excel говорит, что я пытаюсь нарисовать слишком много баллов, когда я не уверен.

(full size image) code block with watch window http://img12.imageshack.us/img12/5360/snippet.png

Я понимаю, что не может иметь значения X правильно, связанные с каждой серией, но я пытаюсь получить эту работу, прежде чем пойти дальше.

Любая помощь была бы принята с благодарностью.

Вот полный код:

public void DrawScatterGraph(string xColumnLetter, string yColumnLetterStart, string yColumnLetterStop, string xAxisLabel, string yAxisLabel, string chartTitle, Microsoft.Office.Interop.Excel.XlChartType chartType, bool includeTrendline, bool includeLegend) 
    { 
     int totalRows = dataSheet.UsedRange.Rows.Count; //dataSheet is a private class variable that 
                 //is already properly set to the worksheet 
                 //we want to graph from 

     if (totalRows < 2) throw new Exception("Not generating graph for " + chartTitle.Replace('\n', ' ') 
              + " because not enough data was present"); 

     ChartObjects charts = (ChartObjects)dataSheet.ChartObjects(Type.Missing); 
     ChartObject chartObj = charts.Add(100, 300, 500, 300); 
     Chart chart = chartObj.Chart; 

     try { chart.ChartType = chartType; } 
     catch { } //i don't know why this is throwing an exception, but i'm 
        //going to bulldoze through this problem temporarily 

     if (totalRows < SizeOfSeries) //we can graph the data in a single series - yay! 
     { 
      Range xValues = dataSheet.get_Range(xColumnLetter + "2", xColumnLetter + totalRows.ToString()); 
      Range yValues = dataSheet.get_Range(yColumnLetterStart + "1", yColumnLetterStop + totalRows.ToString()); 
      chart.SetSourceData(yValues, XlRowCol.xlColumns); 
      SeriesCollection seriesCollection = (SeriesCollection)chart.SeriesCollection(Type.Missing); 
      foreach (Series s in seriesCollection) 
      { 
       s.XValues = xValues; 
      } 
     } 
     else // we need to split the data across multiple series -- this doesn't work yet 
     { 
      int startRow = 1; 
      while (startRow < totalRows) 
      { 
       int stopRow = (startRow + SizeOfSeries)-1; 
       if (stopRow > totalRows) stopRow = totalRows; 
       Range curRange = dataSheet.get_Range(yColumnLetterStart + startRow.ToString(), yColumnLetterStop + stopRow.ToString()); 
       try 
       { 
        ((SeriesCollection)chart.SeriesCollection(Type.Missing)).Add(curRange, XlRowCol.xlColumns, 
                      Type.Missing, Type.Missing, Type.Missing); 
       } 
       catch (Exception exc) 
       { 
        throw new Exception(yColumnLetterStart + startRow.ToString() + "!" + yColumnLetterStop + stopRow.ToString() + "!" + exc.Message); 
       } 
       startRow = stopRow+1; 
      } 
     } 

     chart.HasLegend = includeLegend; 
     chart.HasTitle = true; 
     chart.ChartTitle.Text = chartTitle; 

     Axis axis; 
     axis = (Axis)chart.Axes(XlAxisType.xlCategory, XlAxisGroup.xlPrimary); 
     axis.HasTitle = true; 
     axis.AxisTitle.Text = xAxisLabel; 
     axis.HasMajorGridlines = false; 
     axis.HasMinorGridlines = false; 

     axis = (Axis)chart.Axes(XlAxisType.xlValue, XlAxisGroup.xlPrimary); 
     axis.HasTitle = true; 
     axis.AxisTitle.Text = yAxisLabel; 
     axis.HasMajorGridlines = true; 
     axis.HasMinorGridlines = false; 

     if (includeTrendline) 
     { 
      Trendlines t = (Trendlines)((Series)chart.SeriesCollection(1)).Trendlines(Type.Missing); 
      t.Add(XlTrendlineType.xlLinear, Type.Missing, Type.Missing, 0, 0, Type.Missing, false, false, "AutoTrendlineByChameleon"); 
     } 

     chart.Location(XlChartLocation.xlLocationAsNewSheet, "Graph"); 
    } 

ответ

2

Если активная ячейка находится в блоке данных, Excel может предположить, что вы хотите построить диапазон.

Выберите пустую ячейку, которая не находится рядом с данными, затем вставьте диаграмму. Он будет пустым, а не предварительным.

+0

Спасибо, Джон! Я добавил следующее в верхней части моей функции: Диапазон tempRange = dataSheet.get_Range ("E1", "E2"); tempRange.Select(); Если столбец E пуст (мои данные указаны только в столбцах A - C). С этим изменением на месте все работало правильно. Еще раз спасибо! – Vincent

2

ли ваш график на самом деле должны быть в Excel? С таким количеством точек данных производительность будет ужасной.

Одно из предложений может заключаться в использовании стороннего компонента для генерации графика. Конкретный метод выполнения этого зависит от того, нужно ли вам просматривать данные в excel или должен ли доступ к выходному графику просто быть доступен в другом месте.

Если граф не нужно видеть в Excel, просто передайте точки данных и просмотрите изображение в графическом приложении или в веб-браузере.

Если вам нужно просмотреть график с помощью excel, вы можете сделать вызов внешнему графическому приложению и передать ему набор точек данных. Когда он возвращает изображение, просто вставьте его в excel с помощью vba.

Я могу дать вам больше информации об обоих подходах, если вам нужно.

Кроме того, другие соображения могут включать в себя необходимость иметь возможность сверления на графике. С этим множеством точек данных я не могу себе представить, что бы вы сделали.


Если вы можете ответить на следующие вопросы, это может помочь людям сформулировать лучшие ответы.

  1. Какой пользовательский интерфейс будет представлять выход этих элементов? (например, Excel, веб-приложение ASP.NET, Windows Forms, WPF, Silverlight и т. д.)

  2. Эти графики должны генерироваться в реальном времени по запросу пользователя или они сгенерированы и сохранены? Если они генерируются по требованию, каков максимальный период времени, который ваши пользователи считают приемлемым ждать?

  3. Насколько важно, чтобы вы действительно использовали Excel? Вы используете его, потому что это требование для отображения, или это просто то, что удобно?

  4. Насколько важен «коэффициент вау» для отображения графиков? Просто есть графики, или они должны быть чрезвычайно красивыми?

  5. Нужны ли пользователям какие-либо способности просверливаться на графике или просто достаточно для просмотра изображения?

+0

Спасибо за вход, Энтони. Я почти подошел к рассмотрению других альтернатив, прежде чем Джон дал ему совет. FYI, я начал работать с Excel, потому что 1) он легко доступен для моей пользовательской базы «walled-garden» и 2) Иногда графики нужно настраивать вручную после автогенерации, и все пользователи обучаются в Excel. – Vincent

1

Чтобы помочь всем, кто попадается это в будущем, вот полная функция с исправлением Джона:

public void DrawScatterGraph(string xColumnLetter, string yColumnLetterStart, string yColumnLetterStop, string xAxisLabel, string yAxisLabel, string chartTitle, Microsoft.Office.Interop.Excel.XlChartType chartType, bool includeTrendline, bool includeLegend) 
    { 
     int totalRows = dataSheet.UsedRange.Rows.Count; //dataSheet is a private class variable that 
                 //is already properly set to the worksheet 
                 //we want to graph from 

     if (totalRows < 2) throw new Exception("Not generating graph for " + chartTitle.Replace('\n', ' ') 
               + " because not enough data was present"); 

     dataSheet.get_Range("Z1", "Z2").Select(); //we need to select some empty space 
                //so Excel doesn't try to jam the 
                //potentially large data set into the 
                //chart automatically 

     ChartObjects charts = (ChartObjects)dataSheet.ChartObjects(Type.Missing); 
     ChartObject chartObj = charts.Add(100, 300, 500, 300); 
     Chart chart = chartObj.Chart; 
     chart.ChartType = chartType; 
     SeriesCollection seriesCollection = (SeriesCollection)chart.SeriesCollection(Type.Missing); 

     if (totalRows < SizeOfSeries) //we can graph the data in a single series - yay! 
     { 
      Range xValues = dataSheet.get_Range(xColumnLetter + "2", xColumnLetter + totalRows.ToString()); 
      Range yValues = dataSheet.get_Range(yColumnLetterStart + "1", yColumnLetterStop + totalRows.ToString()); 
      chart.SetSourceData(yValues, XlRowCol.xlColumns); 

      foreach (Series s in seriesCollection) 
      { 
       s.XValues = xValues; 
      } 
     } 
     else // we need to split the data across multiple series 
     { 
      int startRow = 2; 

      while (startRow < totalRows) 
      { 
       int stopRow = (startRow + SizeOfSeries)-1; 
       if (stopRow > totalRows) stopRow = totalRows; 

       Series s = seriesCollection.NewSeries(); 
       s.Name = "ChunkStartingAt" + startRow.ToString(); 
       s.XValues = dataSheet.get_Range(xColumnLetter + startRow.ToString(), xColumnLetter + stopRow.ToString()); 
       s.Values = dataSheet.get_Range(yColumnLetterStart + startRow.ToString(), yColumnLetterStop + stopRow.ToString()); 

       startRow = stopRow+1; 
      } 
     } 

     chart.HasLegend = includeLegend; 
     chart.HasTitle = true; 
     chart.ChartTitle.Text = chartTitle; 

     Axis axis; 
     axis = (Axis)chart.Axes(XlAxisType.xlCategory, XlAxisGroup.xlPrimary); 
     axis.HasTitle = true; 
     axis.AxisTitle.Text = xAxisLabel; 
     axis.HasMajorGridlines = false; 
     axis.HasMinorGridlines = false; 

     axis = (Axis)chart.Axes(XlAxisType.xlValue, XlAxisGroup.xlPrimary); 
     axis.HasTitle = true; 
     axis.AxisTitle.Text = yAxisLabel; 
     axis.HasMajorGridlines = true; 
     axis.HasMinorGridlines = false; 

     if (includeTrendline) 
     { 
      Trendlines t = (Trendlines)((Series)chart.SeriesCollection(1)).Trendlines(Type.Missing); 
      t.Add(XlTrendlineType.xlLinear, Type.Missing, Type.Missing, 0, 0, Type.Missing, false, false, "AutoTrendlineByChameleon"); 
     } 

     chart.Location(XlChartLocation.xlLocationAsNewSheet, "Graph"); 
    } 
Смежные вопросы