Pergunta

Preciso de ajuda através de programação de gráficos mais pontos do que pode caber em uma única série Excel.

De acordo com a http://office.microsoft.com/en-us /excel/HP100738491033.aspx o número máximo de pontos que podem ser visualizados em um gráfico do Excel 2007 é 256000. Dado que cada tampas de série para fora em 32000 pontos, 8 séries são obrigados a traçar os completos 256000 pontos. Meu cliente requer plotagem da quantidade máxima de pontos por gráfico devido aos grandes conjuntos de dados com que trabalhamos.

Eu tenho experiência moderada com C # interoperabilidade / Excel, então eu pensei que seria fácil para programaticamente criar uma planilha e, em seguida, percorrer cada conjunto de 32000 pontos e adicioná-los ao gráfico como uma série, parando quando os dados foi totalmente plotado ou 8 série foram representados graficamente. Se colorido corretamente, os 8 série iria ser visualmente indistinguível de uma única série.

Infelizmente, aqui estou. O principal problema que eu encontro é:

(tamanho grande) O número máximo de pontos de dados pode ser usado em uma série de dados para um gráfico de 2-D é de 32.000 ... http://img14.imageshack.us/img14/9630/errormessagen.png

Este pop-up, curiosamente, aparece quando eu executar a linha:

chart.ChartType = chartType (onde chartType é xlXYScatterLines)

e é acompanhada por:

Exceção de HRESULT: 0x800AC472 http://img21.imageshack.us/img21/ 5153 / exceptionb.png

Eu não entendo como eu poderia estar gerando tal um pop-up / aviso / exceção antes de eu mesmo ter especificado os dados a serem desenhados. Excel está tentando ser inteligente aqui?

Como solução temporária, eu coloquei o chart.ChartType = declaração chartType em um bloco try-catch para que eu possa continuar.

Como mostra o seguinte, meu código "chunking" está funcionando conforme o esperado, mas eu ainda encontrar o mesmo problema ao tentar adicionar dados para o gráfico. Excel diz que eu estou tentando representar graficamente muitos pontos quando claramente não sou.

( a imagem no tamanho ) bloco de código com janela de observação http://img12.imageshack.us/img12/5360/snippet .png

Eu compreendo que eu não pode ter os valores x corretamente associado ainda cada série, mas eu estou tentando chegar a este trabalho antes de eu ir mais longe.

Qualquer ajuda seria muito apreciada.

Aqui está o código completo:

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");
    }
Foi útil?

Solução

Se a célula ativa está em um bloco de dados, o Excel pode assumir que você quer traçar o intervalo.

Selecionar uma célula em branco que não é o lado de dados, em seguida, inserir o gráfico. Ele ficará em branco, em vez de prepopulated.

Outras dicas

O seu gráfico realmente tem que estar em Excel? Com que muitos pontos de dados o desempenho seria horrível.

Uma sugestão seria usar um componente de terceiros para gerar o gráfico. A técnica específica para como fazer isso depende se você tem que ser capaz de visualizar os dados no Excel ou se o gráfico de saída simplesmente precisa estar disponível em outros lugares.

Se o gráfico não precisa ser visível dentro do Excel, em seguida, basta passar os pontos de dados e visualizar a imagem no aplicativo gráfico ou de um navegador web.

Se você precisa fazer para ver o gráfico com excel, você pode fazer uma chamada para a aplicação gráfica externa e passá-lo uma coleção de pontos de dados. Quando ele retorna a imagem basta inseri-lo no Excel com VBA.

Eu posso lhe dar mais informações sobre ambas as abordagens se você precisar.

Além disso, outras considerações podem incluir se você precisa ter detalhar capacidade no gráfico. Com isso muitos pontos de dados, eu não posso imaginar que você faria.


Se você puder responder às seguintes perguntas, pode ajudar a gente formular melhores respostas.

  1. Que tipo de interface com o usuário estará apresentando a saída de algum desses equipamentos? (Por exemplo, Excel, Aplicação Web ASP.NET, Windows Forms, WPF, Silverlight, outros.)

  2. São estes gráficos deveriam ser gerados em tempo real, a pedido de um usuário ou são gerados e armazenados? Se eles são gerados sob demanda, o que é a quantidade máxima de tempo que seus usuários consideraria aceitável esperar?

  3. Como é que é importante que você realmente usar o Excel? Você usá-lo porque é uma exigência para exibição, ou isso é apenas o que é útil?

  4. Qual a importância do "fator Wow" para a exibição de gráficos? É simplesmente ter os gráficos, ou eles tem que ser extremamente bonita?

  5. usuários

    exigem qualquer capacidade de detalhar o gráfico, ou é simplesmente ser capaz de ver a imagem suficiente?

Para ajudar a qualquer um que se depara com isso no futuro, aqui está a função completa com correção de 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");
    }
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top