8
votes

C # / Excel: Travailler autour de la taille de la série maximale sur le graphique

J'ai besoin d'aide pour graphiser de manière programmée de manière programmée que possible dans une seule série Excel.

Selon http://office.microsoft.com/en-us/excel/hp10073849103.cèse Le nombre maximum de points affichés sur un graphique Excel 2007 est de 256 000. Étant donné que chaque série change à 32000 points, 8 séries sont nécessaires pour tracer 256 000 points. Mon client nécessite un tracé de montant maximum de points par graphique en raison des grands ensembles de données que nous travaillons. P>

J'ai une expérience modérée avec C # / Excel Interop, donc je pensais qu'il serait facile de créer de manière programmative une feuille de calcul et Ensuite, bouclez à travers chaque ensemble de 32 000 points et ajoutez-les au graphique en tant que série, arrêtez-vous lorsque les données ont été complètement tracées ou 8 séries ont été tracées. Si coloré correctement, la série 8 serait visuellement indiscernable d'une seule série. P>

Malheureusement, je suis ici. Le problème principal que je rencontre est: p>

(Taille complète) a> Le nombre maximum de données que vous pouvez utiliser dans une série de données pour un graphique 2D est de 32 000 ... http://img14.imageshack.us/img14/9630/ErormSagen.png p>

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

 graphique.chartype = graphtype (où THYTTYPE est XLXYSCatterLines) p>

et est accompagné de: p>

Exception de hresult: 0x800ac472 http://img21.imageshack.us/img21/5153/exceptionb.png p>

Je ne comprends pas comment je pourrais générer une telle popup / avertissement / exception avant i ont même spécifié les données à graphiser. Excel essaie d'être intelligent ici? P>

En tant que solution de contournement temporaire, j'ai mis le graphique.ChatType = instruction graphique dans un bloc de try-catch afin que je puisse continuer. P>

Comme indiqué ci-après, mon code "chunking" fonctionne comme prévu, mais je rencontre toujours le même problème lorsque vous essayez d'ajouter des données au graphique. Excel dit que j'essaie de graphiquement de trop de points quand je ne suis clairement pas. P>

( Image complète ) bloc de code avec fenêtre de montre http://img12.imageshack.us/img12/5360/snippet .png p>

Je comprends que je n'ai peut-être pas encore les valeurs X correctement associées à chaque série, mais j'essaie d'obtenir cela pour que cela fonctionne avant d'aller plus loin. p>

Toute aide serait grandement appréciée. P>

Voici le code complet: p>

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


0 commentaires

3 Réponses :


2
votes

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

Une suggestion peut être d'utiliser un composant tiers pour générer le graphique. La technique spécifique pour savoir comment accomplir cela dépend de la possibilité de 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, passez simplement les points de données et affichez l'image dans l'application graphique ou sur un navigateur Web.

Si vous devez afficher le graphique avec Excel, vous pouvez appeler à l'application de graphique externe et transmettre une collection de points de données. Quand il renvoie l'image, insérez-le dans Excel avec VBA.

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

En outre, d'autres considérations peuvent inclure si vous devez avoir une capacité d'exploration sur le graphique. Avec ces nombreux 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 personnes à formuler de meilleures réponses.

  1. Quel type d'interface utilisateur présentera la sortie de ces éléments? (E.G. Excel, application Web ASP.NET, Formulaires Windows, WPF, Silverlight, Autre.)

  2. Ces graphiques sont-ils censés être générés en temps réel à la demande d'un utilisateur ou sont-ils générés et stockés? S'ils sont générés sur demande, quel est le maximum de temps que vos utilisateurs envisageraient acceptables d'attendre?

  3. Quelle est l'importance que vous utilisez réellement Excel? Utilisez-vous-tu parce que c'est une exigence d'affichage, ou est-ce juste ce qui est pratique?

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

  5. Les utilisateurs ont besoin de la possibilité de réduire dans le graphique ou de pouvoir simplement afficher l'image suffisante?


1 commentaires

Merci pour l'entrée, Anthony. Je me faisais près du point d'envisager d'autres solutions de remplacement avant que Jon ne donne son avis. FYI, j'ai commencé à travailler avec Excel car 1) Il est facilement accessible à ma base d'utilisateurs "muré-jardin" et 2) parfois, les graphiques doivent parfois être modifiés à la main après la génération automatique et les utilisateurs sont tous formés à Excel.



3
votes

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

Sélectionnez une cellule vierge qui n'est pas à côté des données, puis insérez le graphique. Il sera vide, plutôt que prépopulé.


1 commentaires

Merci Jon! J'ai ajouté ce qui suit près du sommet de ma fonction: gamme Temprange = datasheet.get_range ("E1", "E2"); temprange.select (); Où la colonne E est vide (mes données sont uniquement dans les colonnes A - C). Avec ce changement de place, tout a fonctionné correctement. Merci encore!



1
votes

Aider toute personne qui appartient à 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");
    }


0 commentaires