I need help programatically graphing more points than can fit in a single Excel series.
According to http://office.microsoft.com/en-us/excel/HP100738491033.aspx the
Does your graph actually have to be in Excel? With that many data points the performance would be horrible.
One suggestion might be to use a third party component to generate the graph. The specific technique for how to accomplish this depends on whether you have to be able to view the data in excel or whether the output graph simply needs to be available elsewhere.
If the graph does not need to be visible within Excel, then just pass the data points and view the image in the graphing application or a web browser.
If you do need to view the graph with excel, you could make a call to the external graphing application and pass it a collection of data points. When it returns the image just insert it in excel with vba.
I can give you more info on both approaches if you need.
Also, other considerations might include whether you need to have drill down capability on the graph. With this many data points, I can not imagine that you would.
If you can answer the following questions, it might help folks formulate better answers.
What sort of user interface will be presenting the output of these items? (e.g. Excel, ASP.NET Web Application, Windows Forms, WPF, Silverlight, other.)
Are these graphs supposed to be generated in real time at a user's request or are they generated and stored? If they are generated on demand, what is the maximum amount of time your users would consider acceptable to wait?
How important is it that you actually use Excel? Are you using it because it is a requirement for display, or is that just what is handy?
How important is the "Wow factor" for the display of the graphs? Is simply having the graphs, or do they have to be extremely beautiful?
Do users require any ability to drill down into the graph, or is simply being able to view the image sufficient?
To help anyone who comes across this in the future, here's the complete function with Jon's fix:
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");
}
If the active cell is in a block of data, Excel may assume you want to plot the range.
Select a blank cell which is not next to the data, then insert the chart. It will be blank, rather than prepopulated.