I’m using Bumblebee to read data into Rhino. My Excel files have about 500 000 rows each but I cannot get in more than ± 65 000 rows into Grasshopper at a time. In the old days, Excel had a limit of 65 000 rows but since 2007 one file can contain up to 1 048 576 rows.
Does anybody know if it’s possible (and how) to go beyond the 65K lines?
The Bumblebee gh userobject is as follows:
Option Strict Off
Option Explicit On
Imports Rhino
Imports Rhino.Geometry
Imports Rhino.DocObjects
Imports Rhino.Collections
Imports GH_IO
Imports GH_IO.Serialization
Imports Grasshopper
Imports Grasshopper.Kernel
Imports Grasshopper.Kernel.Data
Imports Grasshopper.Kernel.Types
Imports System
Imports System.IO
Imports System.Xml
Imports System.Xml.Linq
Imports System.Linq
Imports System.Data
Imports System.Drawing
Imports System.Reflection
Imports System.Collections
Imports System.Windows.Forms
Imports Microsoft.VisualBasic
Imports System.Collections.Generic
Imports System.Runtime.InteropServices
''' <summary>
''' This class will be instantiated on demand by the Script component.
''' </summary>
Public Class Script_Instance
Inherits GH_ScriptInstance
#Region "Utility functions"
''' <summary>Print a String to the [Out] Parameter of the Script component.</summary>
''' <param name="text">String to print.</param>
Private Sub Print(ByVal text As String)
__out.Add(text)
End Sub
''' <summary>Print a formatted String to the [Out] Parameter of the Script component.</summary>
''' <param name="format">String format.</param>
''' <param name="args">Formatting parameters.</param>
Private Sub Print(ByVal format As String, ByVal ParamArray args As Object())
__out.Add(String.Format(format, args))
End Sub
''' <summary>Print useful information about an object instance to the [Out] Parameter of the Script component. </summary>
''' <param name="obj">Object instance to parse.</param>
Private Sub Reflect(ByVal obj As Object)
__out.Add(GH_ScriptComponentUtilities.ReflectType_VB(obj))
End Sub
''' <summary>Print the signatures of all the overloads of a specific method to the [Out] Parameter of the Script component. </summary>
''' <param name="obj">Object instance to parse.</param>
Private Sub Reflect(ByVal obj As Object, ByVal method_name As String)
__out.Add(GH_ScriptComponentUtilities.ReflectType_VB(obj, method_name))
End Sub
#End Region
#Region "Members"
''' <summary>Gets the current Rhino document.</summary>
Private RhinoDocument As RhinoDoc
''' <summary>Gets the Grasshopper document that owns this script.</summary>
Private GrasshopperDocument as GH_Document
''' <summary>Gets the Grasshopper script component that owns this script.</summary>
Private Component As IGH_Component
''' <summary>
''' Gets the current iteration count. The first call to RunScript() is associated with Iteration=0.
''' Any subsequent call within the same solution will increment the Iteration count.
''' </summary>
Private Iteration As Integer
#End Region
''' <summary>
''' This procedure contains the user code. Input parameters are provided as ByVal arguments,
''' Output parameter are ByRef arguments. You don't have to assign output parameters,
''' they will have default values.
''' </summary>
Private Sub RunScript(ByVal XL_Path As List(Of Object), ByVal Origin As Point3d, ByVal Bound As Point3d, ByVal ByColumn As Boolean, ByVal Type As Integer, ByVal _Stream As Boolean, ByRef A As Object, ByRef B As Object, ByRef Data As Object)
Component.Params.Input(0).Name = "Path"
Component.Params.Input(0).Description = "Optional input for the XL Path component which specifies the Target Workbook and Sheet. If blank the active workbook and worksheet is used, or the worksheet index supplied by an origin component"
Component.Params.Input(1).Name = "Data Origin"
Component.Params.Input(1).Description = "Optional point input which specifies the lower bounds from which data will be read where X = Row, Y = Column, and Z = Sheet Index. If Z = 0 the active sheet will be used. If input is empty first used cell on active sheet will be used"
Component.Params.Input(2).Name = "Data Bound"
Component.Params.Input(2).Description = "Optional point input which specifies the upper bounds from which data will be read where X = Row, Y = Column, and Z = Sheet Index. If Z = 0 the active sheet will be used, If input is empty last used cell on active sheet will be used"
Component.Params.Input(3).Name = "By Column"
Component.Params.Input(3).Description = "Sets if data will be transposed"
Component.Params.Input(4).Name = "Type"
Component.Params.Input(4).Description = "Optional input for the XL Data Type component or integer value specifying the type of data being read [Value = 0, Value2 = 1, Formula = 2, FormulaLocal = 3, FormulaR1C1 = 4, FormulaR1C1Local = 5]"
Component.Params.Input(5).Name = "Stream"
Component.Params.Input(5).Description = "If true, data will be read"
Component.Params.Output(1).Name = "Origin"
Component.Params.Output(1).Description = "List output of points which specify the lower bounds of read data"
Component.Params.Output(2).Name = "Bound"
Component.Params.Output(2).Description = "List output of points which specify the upper bounds of read data"
Component.Params.Output(3).Name = "Data"
Component.Params.Output(3).Description = "Datatree of generic data read from Excel"
If _Stream = True Then
'If _LIVE = True Then owner.ExpireSolution(True)
Dim objExcel, excelWorkbook, excelSheet As Object
If XL_Path.Count() > 1 Then
objExcel = XL_Path.item(0)
excelWorkbook = XL_Path.item(1)
excelSheet = XL_Path.item(2)
Else
Dim oldCI As System.Globalization.CultureInfo = system.Threading.Thread.CurrentThread.CurrentCulture
System.Threading.Thread.CurrentThread.CurrentCulture = New System.Globalization.CultureInfo("en-US")
'Access Active Session of Excel if no Path is specified
objExcel = System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application")
excelWorkbook = objExcel.activeWorkbook
excelSheet = objExcel.ActiveSheet
End If
objExcel.screenUpdating = False
Dim arrStr As New datatree(Of Object)
Dim i,j,k,m,n As Integer
If XL_Path.count() <= 1 Then
If CInt(origin.z) = 0 Then
n = 0
excelSheet = objExcel.ActiveSheet
ElseIf CInt(bound.z) = 0 Then
n = 0
excelSheet = excelWorkbook.Sheets.item(CInt(origin.Z))
Else
n = (bound.z - origin.z)
excelSheet = excelWorkbook.Sheets.item(CInt(origin.Z))
End If
End If
'specify a range in excel and stream data
For m = 0 To n Step 1
If m <> 0 Then
excelSheet = excelWorkbook.Sheets.item(CInt(origin.Z + n))
End If
If Origin = Nothing Then
Origin.Y = excelSheet.usedrange.row
Origin.X = excelSheet.usedrange.column
End If
If Bound = Nothing Then
Bound.Y = excelSheet.usedrange.rows(excelSheet.usedrange.rows.count).row
Bound.X = excelSheet.usedrange.columns(excelSheet.usedrange.columns.count).column
End If
Dim rng As Object
If (origin.x = bound.x) And (origin.y = bound.y) Then
arrStr.add(excelSheet.Cells(Origin.Y, Origin.X).value, New GH_Path(0))
Else
If type = 1 Then
rng = excelSheet.Range(excelSheet.Cells(Origin.Y, Origin.X), excelSheet.Cells(Bound.Y, Bound.X)).value2
ElseIf type = 2 Then
rng = excelSheet.Range(excelSheet.Cells(Origin.Y, Origin.X), excelSheet.Cells(Bound.Y, Bound.X)).formula
ElseIf type = 3 Then
rng = excelSheet.Range(excelSheet.Cells(Origin.Y, Origin.X), excelSheet.Cells(Bound.Y, Bound.X)).formulalocal
ElseIf type = 4 Then
rng = excelSheet.Range(excelSheet.Cells(Origin.Y, Origin.X), excelSheet.Cells(Bound.Y, Bound.X)).FormulaR1C1
ElseIf type = 5 Then
rng = excelSheet.Range(excelSheet.Cells(Origin.Y, Origin.X), excelSheet.Cells(Bound.Y, Bound.X)).FormulaR1C1Local
Else
rng = excelSheet.Range(excelSheet.Cells(Origin.Y, Origin.X), excelSheet.Cells(Bound.Y, Bound.X)).value
End If
If ByColumn = True Then
rng = objExcel.transpose(rng)
End If
k = 0
For i = LBound(rng, 1) To UBound(rng, 1) Step 1
For j = LBound(rng, 2) To UBound(rng, 2) Step 1
If n = 0 Then
arrStr.add(rng(i, j), New GH_Path(k))
Else
arrStr.add(rng(i, j), New GH_Path({m,k}))
End If
Next
k = k + 1
Next
End If
Next
excelSheet.activate
objExcel.screenUpdating = True
A = New point3d(Origin.x, origin.Y, excelSheet.Index)
B = New point3d(Bound.x, Bound.Y, excelSheet.Index)
Data = arrStr
End If
End Sub
'<Custom additional code>
'</Custom additional code>
Private __err As New List(Of String)
Private __out As New List(Of String)
Private doc As RhinoDoc = RhinoDoc.ActiveDoc 'Legacy field.
Private owner As Grasshopper.Kernel.IGH_ActiveObject 'Legacy field.
Private runCount As Int32 'Legacy field.
Public Overrides Sub InvokeRunScript(ByVal owner As IGH_Component, _
ByVal rhinoDocument As Object, _
ByVal iteration As Int32, _
ByVal inputs As List(Of Object), _
ByVal DA As IGH_DataAccess)
'Prepare for a new run...
'1. Reset lists
Me.__out.Clear()
Me.__err.Clear()
'Current field assignments.
Me.Component = owner
Me.Iteration = iteration
Me.GrasshopperDocument = owner.OnPingDocument()
Me.RhinoDocument = TryCast(rhinoDocument, Rhino.RhinoDoc)
'Legacy field assignments
Me.owner = Me.Component
Me.runCount = Me.Iteration
Me.doc = Me.RhinoDocument
'2. Assign input parameters
Dim XL_Path As List(Of System.Object) = Nothing
If (inputs(0) IsNot Nothing) Then
XL_Path = GH_DirtyCaster.CastToList(Of System.Object)(inputs(0))
End If
Dim Origin As Point3d = Nothing
If (inputs(1) IsNot Nothing) Then
Origin = DirectCast(inputs(1), Point3d)
End If
Dim Bound As Point3d = Nothing
If (inputs(2) IsNot Nothing) Then
Bound = DirectCast(inputs(2), Point3d)
End If
Dim ByColumn As Boolean = Nothing
If (inputs(3) IsNot Nothing) Then
ByColumn = DirectCast(inputs(3), Boolean)
End If
Dim Type As Integer = Nothing
If (inputs(4) IsNot Nothing) Then
Type = DirectCast(inputs(4), Integer)
End If
Dim _Stream As Boolean = Nothing
If (inputs(5) IsNot Nothing) Then
_Stream = DirectCast(inputs(5), Boolean)
End If
'3. Declare output parameters
Dim A As System.Object = Nothing
Dim B As System.Object = Nothing
Dim Data As System.Object = Nothing
'4. Invoke RunScript
Call RunScript(XL_Path, Origin, Bound, ByColumn, Type, _Stream, A, B, Data)
Try
'5. Assign output parameters to component...
If (A IsNot Nothing) Then
If (GH_Format.TreatAsCollection(A)) Then
Dim __enum_A As IEnumerable = DirectCast(A, IEnumerable)
DA.SetDataList(1, __enum_A)
Else
If (TypeOf A Is Grasshopper.Kernel.Data.IGH_DataTree) Then
'merge tree
DA.SetDataTree(1, DirectCast(A, Grasshopper.Kernel.Data.IGH_DataTree))
Else
'assign direct
DA.SetData(1, A)
End If
End If
Else
DA.SetData(1, Nothing)
End If
If (B IsNot Nothing) Then
If (GH_Format.TreatAsCollection(B)) Then
Dim __enum_B As IEnumerable = DirectCast(B, IEnumerable)
DA.SetDataList(2, __enum_B)
Else
If (TypeOf B Is Grasshopper.Kernel.Data.IGH_DataTree) Then
'merge tree
DA.SetDataTree(2, DirectCast(B, Grasshopper.Kernel.Data.IGH_DataTree))
Else
'assign direct
DA.SetData(2, B)
End If
End If
Else
DA.SetData(2, Nothing)
End If
If (Data IsNot Nothing) Then
If (GH_Format.TreatAsCollection(Data)) Then
Dim __enum_Data As IEnumerable = DirectCast(Data, IEnumerable)
DA.SetDataList(3, __enum_Data)
Else
If (TypeOf Data Is Grasshopper.Kernel.Data.IGH_DataTree) Then
'merge tree
DA.SetDataTree(3, DirectCast(Data, Grasshopper.Kernel.Data.IGH_DataTree))
Else
'assign direct
DA.SetData(3, Data)
End If
End If
Else
DA.SetData(3, Nothing)
End If
Catch ex As Exception
__err.Add(String.Format("Script exception: {0}", ex.Message))
Finally
'Add errors and messages...
If (owner.Params.Output.Count > 0) Then
If (TypeOf owner.Params.Output(0) Is Grasshopper.Kernel.Parameters.Param_String) Then
Dim __errors_plus_messages As New List(Of String)
If (Me.__err IsNot Nothing) Then __errors_plus_messages.AddRange(Me.__err)
If (Me.__out IsNot Nothing) Then __errors_plus_messages.AddRange(Me.__out)
If (__errors_plus_messages.Count > 0) Then
DA.SetDataList(0, __errors_plus_messages)
End If
End If
End If
End Try
End Sub
End Class