2009-09-14 38 views
8

Tôi cần trợ giúp lập biểu đồ nhiều điểm hơn có thể phù hợp trong một chuỗi Excel.C#/Excel: Làm việc Xung quanh Kích thước Dòng Tối đa Trên Biểu đồ

Theo số http://office.microsoft.com/en-us/excel/HP100738491033.aspx số điểm tối đa có thể hiển thị trên biểu đồ Excel 2007 là 256000. Do mỗi chuỗi giới hạn ở 32000 điểm, 8 chuỗi được yêu cầu để vẽ toàn bộ 256000 điểm. Khách hàng của tôi yêu cầu vẽ số lượng điểm tối đa trên mỗi biểu đồ do các tập dữ liệu lớn mà chúng tôi làm việc.

Tôi có kinh nghiệm vừa phải với C#/Excel interop nên tôi nghĩ sẽ dễ dàng tạo lập một bảng tính và sau đó lặp qua từng bộ 32000 điểm và thêm chúng vào biểu đồ dưới dạng chuỗi, dừng khi dữ liệu hoàn toàn vẽ hoặc 8 loạt được vẽ. Nếu được tô màu đúng cách, chuỗi 8 sẽ không thể phân biệt bằng một chuỗi đơn.

Thật không may ở đây tôi. Vấn đề chính tôi gặp phải là:

(full size) The maximum number of datapoints you can use in a data series for a 2-D chart is 32,000... http://img14.imageshack.us/img14/9630/errormessagen.png

này pop-up, lạ đủ, xuất hiện khi tôi thực hiện các dòng:

chart.ChartType = chartType (where chartType is xlXYScatterLines) http://img2.imageshack.us/img2/2413/linean.png

và được đi kèm:

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

Tôi không hiểu làm thế nào tôi có thể tạo ra một popup/cảnh báo/ngoại lệ trước khi tôi thậm chí đã chỉ định dữ liệu được vẽ đồ thị. Excel có cố gắng thông minh ở đây không?

Là giải pháp tạm thời, tôi đã đặt biểu đồ.ChartType = chartType statement thành khối try-catch để tôi có thể tiếp tục.

Như sau đây cho thấy, mã "chunking" của tôi đang hoạt động như dự định, nhưng tôi vẫn gặp phải vấn đề tương tự khi cố gắng thêm dữ liệu vào biểu đồ. Excel nói rằng tôi đang cố gắng vẽ đồ thị quá nhiều điểm khi tôi không rõ ràng.

(full size image) code block with watch window http://img12.imageshack.us/img12/5360/snippet.png

Tôi hiểu rằng tôi không thể có giá trị X được liên kết một cách chính xác với từng loạt, nhưng tôi đang cố gắng để có được điều này để làm việc trước khi tôi đi xa hơn.

Mọi trợ giúp sẽ được đánh giá cao.

Dưới đây là đoạn code đầy đủ:

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

Trả lời

2

Nếu ô hiện hoạt nằm trong khối dữ liệu, Excel có thể giả sử bạn muốn vẽ phạm vi.

Chọn ô trống không nằm bên cạnh dữ liệu, sau đó chèn biểu đồ. Nó sẽ được để trống, thay vì được chuẩn bị sẵn.

+0

Cảm ơn bạn Jon! Tôi đã thêm phần sau gần đầu chức năng của mình: Phạm vi tempRange = dataSheet.get_Range ("E1", "E2"); tempRange.Select(); Trường hợp cột E trống (dữ liệu của tôi chỉ ở cột A - C). Với sự thay đổi này tại chỗ, mọi thứ hoạt động bình thường. Cảm ơn bạn một lần nữa! – Vincent

2

Liệu đồ thị của bạn thực sự có được trong Excel? Với nhiều điểm dữ liệu, hiệu suất sẽ là khủng khiếp.

Một đề xuất có thể là sử dụng thành phần của bên thứ ba để tạo biểu đồ. Kỹ thuật cụ thể về cách thực hiện điều này phụ thuộc vào việc bạn có thể xem dữ liệu trong excel hay liệu biểu đồ đầu ra có cần phải có sẵn ở nơi khác không.

Nếu biểu đồ không cần hiển thị trong Excel, thì chỉ cần chuyển các điểm dữ liệu và xem hình ảnh trong ứng dụng đồ họa hoặc trình duyệt web.

Nếu bạn cần xem biểu đồ với excel, bạn có thể thực hiện cuộc gọi đến ứng dụng vẽ đồ họa bên ngoài và chuyển nó tới tập hợp các điểm dữ liệu. Khi nó trả về hình ảnh chỉ cần chèn nó trong excel với vba.

Tôi có thể cung cấp cho bạn thêm thông tin về cả hai cách tiếp cận nếu bạn cần.

Ngoài ra, các cân nhắc khác có thể bao gồm việc bạn có cần có khả năng phân tích chi tiết trên biểu đồ hay không. Với nhiều điểm dữ liệu này, tôi không thể tưởng tượng được rằng bạn sẽ làm như vậy.


Nếu bạn có thể trả lời các câu hỏi sau, điều này có thể giúp mọi người xây dựng câu trả lời tốt hơn.

  1. Loại giao diện người dùng nào sẽ trình bày đầu ra của các mục này? (ví dụ: Excel, Ứng dụng Web ASP.NET, Windows Forms, WPF, Silverlight, khác.)

  2. Các đồ thị này được cho là được tạo trong thời gian thực theo yêu cầu của người dùng hay chúng được tạo và lưu trữ? Nếu chúng được tạo theo yêu cầu, thì lượng thời gian tối đa mà người dùng của bạn sẽ xem là chấp nhận được khi chờ đợi?

  3. Điều quan trọng là bạn thực sự sử dụng Excel? Bạn đang sử dụng nó bởi vì nó là một yêu cầu để hiển thị, hoặc là chỉ là những gì là tiện dụng?

  4. Yếu tố "Wow" quan trọng như thế nào đối với việc hiển thị biểu đồ? Đơn giản là có đồ thị, hay chúng phải cực kỳ xinh đẹp?

  5. Người dùng có yêu cầu bất kỳ khả năng nào đi sâu vào biểu đồ hoặc chỉ đơn giản là có thể xem đủ hình ảnh không?

+0

Cảm ơn cho đầu vào, Anthony. Tôi đã gần đến mức xem xét các lựa chọn thay thế khác trước khi Jon đưa ra lời khuyên. FYI, tôi bắt đầu làm việc với Excel vì 1) Nó sẵn sàng cho cơ sở người dùng "có tường bao quanh" và 2) Đôi khi các đồ thị cần được tinh chỉnh bằng tay sau khi tạo tự động và người dùng đều được đào tạo trong Excel. – Vincent

1

Để giúp bất cứ ai đi qua này trong tương lai, đây là chức năng hoàn chỉnh với sửa chữa 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"); 
    } 
Các vấn đề liên quan