C # / Excel: работа вокруг максимального размера серии на графике

StackOverflow https://stackoverflow.com/questions/1422779

  •  07-07-2019
  •  | 
  •  

Вопрос

Мне нужна помощь для составления графиков большего количества точек, чем может поместиться в одной серии Excel.

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

У меня небольшой опыт взаимодействия с 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 или просто нужно, чтобы выходной график был доступен в другом месте.

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

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

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

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

<Ч>

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

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

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

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

  • Насколько важен " Wow factor " для отображения графиков? Просто иметь графики или они должны быть очень красивыми?

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

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

        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 с атрибуция
    Не связан с StackOverflow
    scroll top