2009-09-14 3 views
8

하나의 Excel 시리즈보다 많은 점수를 프로그램 적으로 그래프로 작성하는 데 도움이 필요합니다.C#/Excel : 차트의 최대 시리즈 크기 작업

http://office.microsoft.com/en-us/excel/HP100738491033.aspx에 따르면 Excel 2007 차트에 표시 할 수있는 최대 포인트 수는 256000입니다. 각 시리즈의 32000 포인트가 모자라는 경우 전체 256000 포인트를 플롯해야합니다. 고객은 우리가 작업하는 많은 데이터 세트로 인해 차트 당 최대 포인트를 계획해야합니다.

저는 C#/Excel interop에 대한 경험이 적으므로 프로그래밍 방식으로 워크 시트를 만든 다음 각 32000 점 세트를 반복하고 그래프로 시리즈에 추가하여 데이터가 완전히 끝났을 때 중단하는 것이 좋을 것이라고 생각했습니다. 플롯 또는 8 시리즈가 플로팅되었습니다. 제대로 색칠하면 8 시리즈는 단일 시리즈와 시각적으로 구별되지 않습니다.

불행히도 여기 있습니다. 내가 만나는 주요 문제는 다음과 같습니다

:

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

과이 동반 : 나는 줄을 실행할 때

(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

이 팝업, 이상하게 나타납니다

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

그래프로 표시 할 데이터를 지정하기 전에 이러한 팝업/경고/예외를 생성하는 방법을 이해하지 못합니다. Excel이 여기 영리 해 지려고합니까?

임시 해결 방법으로 chart.ChartType = chartType 문을 try-catch 블록에 넣고 계속 진행할 수 있도록했습니다.

다음과 같이 "청크"코드가 의도 한대로 작동하지만 그래프에 데이터를 추가 할 때도 여전히 동일한 문제가 발생합니다. 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에서 그래프를 볼 필요가없는 경우 데이터 포인트를 전달하고 그래프 응용 프로그램이나 웹 브라우저에서 이미지를 볼 수 있습니다.

엑셀로 그래프를보아야하는 경우 외부 그래프 응용 프로그램을 호출하여 데이터 포인트 모음을 전달할 수 있습니다. 이미지가 반환되면 vba로 Excel에 삽입하면됩니다.

필요한 경우 두 가지 방법에 대한 정보를 더 제공 할 수 있습니다.

또한 다른 고려 사항에는 그래프에서 드릴 다운 기능이 필요한지 여부가 포함될 수 있습니다. 이 많은 데이터 포인트로, 나는 당신이 상상할 수 없다.


다음 질문에 답할 수 있으면 사람들이 더 나은 답변을 작성하는 데 도움이 될 수 있습니다.

  1. 어떤 종류의 사용자 인터페이스가 이들 항목의 출력을 제공합니까? (예 : Excel, ASP.NET 웹 응용 프로그램, Windows Forms, WPF, Silverlight 등)

  2. 그래프는 사용자의 요청에 따라 실시간으로 생성되거나 생성되고 저장됩니까? 요청에 따라 생성되는 경우 사용자가 기다릴 수있는 최대 시간은 얼마입니까?

  3. 실제로 Excel을 얼마나 중요하게 사용합니까? 디스플레이에 대한 요구 사항이거나 사용하기 쉬운 것이기 때문에 사용하고 있습니까?

  4. 그래프를 표시하는 데 "와우 요소"가 얼마나 중요합니까? 단순히 그래프를 가지고있는 것입니까, 아니면 매우 아름답게해야합니까?

  5. 사용자는 그래프로 드릴 다운 할 수있는 기능이 필요하거나 단순히 이미지를 충분히 볼 수 있습니까?

+0

감사합니다. Jon이 조언을하기 전에 다른 대안을 고려할 시점에 가까워지고있었습니다. 참고로, 저는 Excel과 함께 작업하기 시작했습니다. 왜냐하면 1) 내 "벽으로 둘러싸인 정원"사용자가 쉽게 이용할 수 있기 때문입니다. 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"); 
    }