2009-09-14 16 views
8

Excelのシリーズに収まるより多くのポイントをプログラム的にグラフ化するのに役立つ必要があります。C#/ Excel:グラフ上で最大シリーズサイズで作業する

http://office.microsoft.com/en-us/excel/HP100738491033.aspxによると、Excel 2007チャートで表示可能な最大ポイント数は256000です。32000ポイントで各シリーズをキャップアウトすると、全256000ポイントをプロットするには8シリーズが必要です。私の顧客は、私たちが扱っている大量のデータセットのためにチャートあたり最大のポイントをプロットする必要があります。

私は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 imagecode 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でグラフを表示する必要がない場合は、データポイントを渡してグラフアプリケーションまたはWebブラウザで画像を表示するだけです。

グラフをExcelで表示する必要がある場合は、外部グラフアプリケーションを呼び出してデータポイントのコレクションを渡すことができます。それが画像を返すときに、それをvbaでExcelに挿入するだけです。

私は、必要に応じて両方のアプローチについてさらに詳しい情報を提供できます。

また、グラフにドリルダウン機能を必要とするかどうかも考慮する必要があります。このように多くのデータポイントで、私はあなたが想像することはできません。


次の質問に答えることができれば、より良い回答を策定するのに役立つかもしれません。

  1. これらの項目の出力をどのようなユーザーインターフェイスで表示しますか? (Excel、ASP.NET Webアプリケーション、Windowsフォーム、WPF、Silverlightなど)

  2. これらのグラフは、ユーザーの要求によってリアルタイムで生成されるか、生成され保存されますか?それらが要求に応じて生成される場合、ユーザーが待ち受けると考えられる最大時間はどれくらいですか?

  3. Excelを実際に使用することの重要度はどれですか?あなたはそれがディスプレイのための要件であるか、それとも便利なのかという理由でそれを使用していますか?

  4. グラフの表示には「Wow factor」がどれくらい重要ですか?単にグラフを持っているのですか、それとも非常に美しくなければなりませんか?

  5. ユーザーはグラフをドリルダウンする必要がありますか、単にイメージを十分に表示できますか?

+0

感謝。ジョンが助言をする前に、私は他の選択肢を検討する段階に近づいていました。 Excelを使って作業を始めました。なぜなら、1)私の「壁の庭」ユーザーベースですぐに利用できること、2)自動生成後にグラフを手動で微調整する必要があり、ユーザーがすべてExcelで訓練されていることがあります。 – Vincent

1

は、ここではJonの修正で完全な機能です:入力、アンソニーのため

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"); 
    } 
関連する問題