Question

J'ai besoin d'aide pour représenter graphiquement par programme plus de points que ne peut en contenir une seule série Excel.

Selon http://office.microsoft.com/en-us /excel/HP100738491033.aspx , le nombre maximal de points pouvant être affichés sur un graphique Excel 2007 est de 256 000. Étant donné que chaque série est limitée à 32 000 points, 8 séries sont nécessaires pour tracer les 256 000 points. En raison des grands ensembles de données avec lesquels nous travaillons, mon client a besoin de tracer le nombre maximum de points par graphique.

J'ai une expérience modérée de l'interopérabilité C # / Excel et j'ai donc pensé qu'il serait facile de créer par programme une feuille de calcul, puis de parcourir chaque ensemble de 32 000 points et de les ajouter au graphique sous forme de série, en m'arrêtant lorsque les données ont été entièrement tracées. ou 8 séries ont été tracées. Si elle était correctement colorée, il serait impossible de distinguer visuellement la série 8 d'une série unique.

Malheureusement, je suis là. Le principal problème que je rencontre est:

(taille réelle) Le nombre maximal de points de données pouvant être utilisés dans une série de données pour un graphique à deux dimensions est de 32 000. ... http://img14.imageshack.us/img14/9630/errormessagen.png

Ce pop-up, étrangement, apparaît lorsque j'exécute la ligne:

 chart.ChartType = chartType (où chartType est xlXYScatterLines)

et est accompagné de:

Exception de HRESULT: 0x800AC472 http://img21.imageshack.us/img21/ 5153 / exceptionb.png

Je ne comprends pas comment je pourrais générer un tel popup / avertissement / exception avant même d’avoir spécifié les données à représenter. Excel essaie-t-il d'être intelligent ici?

En guise de solution de contournement temporaire, j'ai placé l'instruction chart.ChartType = chartType dans un bloc try-catch afin que je puisse continuer.

Comme le montre l’illustration suivante, mon & ch; chunking " Le code fonctionne comme prévu, mais je rencontre toujours le même problème lorsque j'essaie d'ajouter des données au graphique. Excel dit que j'essaie de représenter trop de points alors que je ne le fais manifestement pas.

( image en taille réelle ) bloc de code avec la fenêtre de surveillance http://img12.imageshack.us/img12/5360/snippet .png

Je comprends que les valeurs X ne sont peut-être pas correctement associées à chaque série, mais j'essaie de faire en sorte que cela fonctionne avant d'aller plus loin.

Toute aide serait grandement appréciée.

Voici le code complet:

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");
    }
Était-ce utile?

La solution

Si la cellule active se trouve dans un bloc de données, Excel peut supposer que vous souhaitez tracer la plage.

Sélectionnez une cellule vide qui ne se trouve pas à côté des données, puis insérez le graphique. Ce sera vide, plutôt que pré-rempli.

Autres conseils

Votre graphique doit-il être réellement dans Excel? Avec autant de points de données, la performance serait horrible.

Une suggestion pourrait être d’utiliser un composant tiers pour générer le graphique. La technique spécifique pour y parvenir dépend de savoir si vous devez pouvoir afficher les données dans Excel ou si le graphique de sortie doit simplement être disponible ailleurs.

Si le graphique n'a pas besoin d'être visible dans Excel, transmettez simplement les points de données et affichez l'image dans l'application graphique ou dans un navigateur Web.

Si vous avez besoin d'afficher le graphique avec Excel, vous pouvez appeler l'application de graphique externe et lui transmettre une collection de points de données. Quand il retourne l'image, insérez-la dans Excel avec vba.

Je peux vous donner plus d'informations sur les deux approches si vous en avez besoin.

De même, d'autres considérations peuvent être prises en compte pour déterminer si vous devez avoir une capacité d’exploration sur le graphique. Avec autant de points de données, je ne peux pas imaginer que vous le feriez.

Si vous pouvez répondre aux questions suivantes, cela pourrait aider les gens à formuler de meilleures réponses.

  1. Quel type d'interface utilisateur présentera la sortie de ces éléments? (par exemple, Excel, application Web ASP.NET, Windows Forms, WPF, Silverlight, autre.)

  2. Ces graphiques sont-ils censés être générés en temps réel à la demande de l'utilisateur ou sont-ils générés et stockés? S'ils sont générés à la demande, quelle est la durée maximale que vos utilisateurs jugeraient acceptable d'attendre?

  3. Dans quelle mesure utilisez-vous réellement Excel? Est-ce que vous l'utilisez parce que c'est une exigence d'affichage, ou est-ce simplement ce qui est pratique?

  4. Quelle est l’importance du "facteur de Wow"? pour l'affichage des graphiques? Est-ce simplement avoir les graphiques, ou est-ce qu'ils doivent être extrêmement beaux?

  5. Les utilisateurs doivent-ils avoir la possibilité d’explorer le graphique ou sont-ils simplement en mesure de visualiser l’image?

Pour aider ceux qui rencontreront cela à l'avenir, voici la fonction complète avec le correctif 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");
    }
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top