8

単一のExcelシリーズに収まるよりも多くのポイントをプログラムでグラフ化するための支援が必要です。

http://office.microsoft.com/en-us/excel/HP100738491033.aspxによると、Excel 2007チャートに表示できるポイントの最大数は256000です。各シリーズの上限が32000ポイントであることを考えると、8つのシリーズが必要です。 256000ポイント全体をプロットします。私の顧客は、私たちが扱うデータセットが大きいため、チャートごとに最大量のポイントをプロットする必要があります。

私はC#/ Excelの相互運用性について中程度の経験があるので、プログラムでワークシートを作成し、32000ポイントの各セットをループしてグラフにシリーズとして追加し、データが完全にプロットされたとき、または8シリーズで停止するのは簡単だと思いました。プロットされました。適切に着色されている場合、8シリーズは1つのシリーズと視覚的に区別できません。

残念ながらここにいます。私が遭遇する主な問題は次のとおりです。

(フルサイズ) 2次元グラフのデータ系列で使用できるデータポイントの最大数は32,000です... http://img14.imageshack.us/img14/9630/errormessagen.png

このポップアップは、奇妙なことに、次の行を実行すると表示されます。

chart.ChartType = chartType(chartTypeはxlXYScatterLines)

それに伴うもの:

HRESULTからの例外:0x800AC472 http://img21.imageshack.us/img21/5153/exceptionb.png

グラフ化するデータを指定する前に、このようなポップアップ/警告/例外をどのように生成できるかわかりません。Excelはここで賢くしようとしていますか?

一時的な回避策として、chart.ChartType = chartTypeステートメントをtry-catchブロックに入れて、続行できるようにしました。

次のように、私の「チャンキング」コードは意図したとおりに機能していますが、グラフにデータを追加しようとすると、同じ問題が発生します。Excelは、明らかにそうではないのに、あまりにも多くのポイントをグラフ化しようとしていると言っています。

フルサイズの画像ウォッチウィンドウ付きのコードブロック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");
    }
4

3 に答える 3

3

アクティブ セルがデータ ブロック内にある場合、Excel は範囲をプロットする必要があると想定する場合があります。

データの横にない空白のセルを選択し、グラフを挿入します。事前入力ではなく、空白になります。

于 2009-09-15T10:57:15.057 に答える
2

グラフは実際にExcelである必要がありますか?その数のデータポイントがあると、パフォーマンスはひどいものになります。

1つの提案は、サードパーティのコンポーネントを使用してグラフを生成することです。これを実現するための具体的な手法は、Excelでデータを表示できる必要があるかどうか、または出力グラフを他の場所で利用できるようにする必要があるかどうかによって異なります。

グラフをExcel内で表示する必要がない場合は、データポイントを渡して、グラフ作成アプリケーションまたはWebブラウザで画像を表示するだけです。

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

必要に応じて、両方のアプローチについて詳しく説明します。

また、他の考慮事項には、グラフにドリルダウン機能が必要かどうかが含まれる場合があります。これだけ多くのデータポイントがあるので、あなたがそうすることは想像できません。


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

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

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

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

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

  5. ユーザーはグラフにドリルダウンする機能を必要としますか、それとも単に画像を十分に表示できる必要がありますか?

于 2009-09-15T00:51:24.240 に答える
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");
    }
于 2009-09-15T15:41:02.680 に答える