Domanda

Ho bisogno di aiuto per rappresentare graficamente più punti di quanti possano rientrare in una singola serie di Excel.

Secondo http://office.microsoft.com/en-us /excel/HP100738491033.aspx il numero massimo di punti visualizzabili su un grafico Excel 2007 è 256000. Dato che ogni serie supera 32000 punti, sono necessarie 8 serie per tracciare i 256000 punti completi. Il mio cliente richiede la stampa del numero massimo di punti per grafico a causa dei grandi set di dati con cui collaboriamo.

Ho una moderata esperienza con l'interoperabilità C # / Excel, quindi ho pensato che sarebbe stato facile creare in modo programmatico un foglio di lavoro e poi passare in rassegna ogni serie di 32000 punti e aggiungerli al grafico come una serie, fermandosi quando i dati sono stati completamente tracciati o 8 serie sono state tracciate. Se colorata correttamente, la serie 8 sarebbe visivamente indistinguibile da una singola serie.

Purtroppo eccomi qui. Il problema principale che incontro è:

(dimensione intera) Il numero massimo di punti dati che è possibile utilizzare in una serie di dati per un grafico 2D è 32.000 ... http://img14.imageshack.us/img14/9630/errormessagen.png

Questo pop-up, stranamente, appare quando eseguo la linea:

 chart.ChartType = chartType (dove chartType è xlXYScatterLines)

ed è accompagnato da:

Eccezione da HRESULT: 0x800AC472 http://img21.imageshack.us/img21/ 5153 / exceptionb.png

Non capisco come avrei potuto generare un tale popup / avviso / eccezione prima ancora di aver specificato i dati da rappresentare graficamente. Excel sta cercando di essere intelligente qui?

Come soluzione temporanea, ho inserito l'istruzione chart.ChartType = chartType in un blocco try-catch in modo da poter continuare.

Come mostra quanto segue, il mio "chunking" il codice funziona come previsto, ma riscontro ancora lo stesso problema quando provo ad aggiungere dati al grafico. Excel dice che sto cercando di rappresentare troppi punti quando chiaramente non lo sono.

( immagine a dimensione intera ) blocco di codice con finestra dell'orologio http://img12.imageshack.us/img12/5360/snippet .png

Capisco che potrei non avere ancora gli X Values ??correttamente associati ad ogni serie, ma sto cercando di farlo funzionare prima di andare oltre.

Qualsiasi aiuto sarebbe molto apprezzato.

Ecco il codice 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");
    }
È stato utile?

Soluzione

Se la cella attiva si trova in un blocco di dati, Excel potrebbe supporre che tu voglia tracciare l'intervallo.

Seleziona una cella vuota che non si trova accanto ai dati, quindi inserisci il grafico. Sarà vuoto, anziché prepopolato.

Altri suggerimenti

Il tuo grafico deve essere effettivamente in Excel? Con così tanti punti dati le prestazioni sarebbero orribili.

Un suggerimento potrebbe essere quello di utilizzare un componente di terze parti per generare il grafico. La tecnica specifica per ottenere questo risultato dipende dal fatto che devi essere in grado di visualizzare i dati in Excel o se il grafico di output deve essere semplicemente disponibile altrove.

Se non è necessario che il grafico sia visibile in Excel, è sufficiente passare i punti dati e visualizzare l'immagine nell'applicazione grafica o in un browser Web.

Se è necessario visualizzare il grafico con Excel, è possibile effettuare una chiamata all'applicazione grafica esterna e passargli una raccolta di punti dati. Quando restituisce l'immagine, inseriscila in Excel con VBA.

Posso darti maggiori informazioni su entrambi gli approcci, se necessario.

Inoltre, altre considerazioni potrebbero includere se è necessario disporre della funzionalità di drill-down sul grafico. Con così tanti punti dati, non riesco a immaginarlo.


Se puoi rispondere alle seguenti domande, potrebbe aiutare la gente a formulare risposte migliori.

  1. Quale tipo di interfaccia utente presenterà l'output di questi elementi? (ad esempio Excel, Applicazione Web ASP.NET, Windows Form, WPF, Silverlight, altro.)

  2. Questi grafici dovrebbero essere generati in tempo reale su richiesta di un utente o sono generati e memorizzati? Se vengono generati su richiesta, qual è il tempo massimo che i tuoi utenti considererebbero accettabile?

  3. Quanto è importante utilizzare effettivamente Excel? Lo stai usando perché è un requisito per la visualizzazione o è proprio ciò che è utile?

  4. Quanto è importante il fattore "wow" per la visualizzazione dei grafici? Avere semplicemente i grafici o devono essere estremamente belli?

  5. Gli utenti richiedono la possibilità di eseguire il drill-down nel grafico o è semplicemente in grado di visualizzare l'immagine sufficiente?

Per aiutare chiunque si imbatterà in questo in futuro, ecco la funzione completa con la correzione di 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");
    }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top