繁体   English   中英

C#/ Excel:解决图表上的最大序列大小

[英]C#/Excel: Working Around Maximum Series Size On Chart

我需要以编程方式绘制比单个Excel系列中更多的点的帮助。

根据http://office.microsoft.com/zh-cn/excel/HP100738491033.aspx,Excel 2007图表上可显示的最大点数为256000。鉴于每个系列的上限为32000点,因此需要8个系列绘制全部256000点。 由于我们要处理大量数据,因此我的客户需要绘制每个图表的最大点数。

我对C#/ Excel互操作有一定的经验,因此我认为以编程方式创建工作表,然后遍历每组32000点并将它们作为一个序列添加到图形中会很容易,在完全绘制数据或8个序列时停止被绘制。 如果上色正确,则8系列与单个系列在视觉上无法区分。

不幸的是我在这里。 我遇到的主要问题是:

(完整大小) 您可以在一个数据系列中用于二维图表的最大数据点数是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");
    }

您的图形实际上必须在Excel中吗? 拥有如此多的数据点,性能将非常糟糕。

一个建议可能是使用第三方组件来生成图形。 如何完成此操作的具体技术取决于您是否必须能够在excel中查看数据,或者输出图是否仅需要在其他地方使用。

如果在Excel中不需要显示图形,则只需传递数据点并在图形应用程序或Web浏览器中查看图像即可。

如果确实需要使用excel查看图形,则可以调用外部图形应用程序并将其传递给数据点的集合。 当它返回图像时,只需使用vba将其插入excel。

如果需要,我可以为您提供有关这两种方法的更多信息。

另外,其他注意事项可能包括是否需要在图形上具有向下钻取功能。 有了这么多数据点,我无法想象您会那样。


如果您可以回答以下问题,则可能会帮助人们制定更好的答案。

  1. 什么样的用户界面将显示这些项目的输出? (例如,Excel,ASP.NET Web应用程序,Windows窗体,WPF,Silverlight等)。

  2. 这些图是应该根据用户的要求实时生成还是要生成和存储? 如果它们是按需生成的,那么您的用户认为可以等待的最长时间是多少?

  3. 实际使用Excel有多重要? 您使用它是因为它是显示的必要条件,还是方便使用?

  4. “哇系数”对于图形显示有多重要? 只是拥有图形,还是必须非常漂亮?

  5. 用户是否需要任何能力来深入研究图形,或者仅仅是能够查看图像就足够了?

如果活动单元格在数据块中,Excel可能会假定您要绘制范围。

选择一个不在数据旁边的空白单元格,然后插入图表。 它将为空白,而不是预先填充。

为了帮助将来遇到此问题的任何人,这是乔恩修复程序的完整功能:

    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");
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM