Python send a class to another component

I am doing something wrong. I am trying to transport a class to another component (which worked when working with simple lists but now it is a tree within a class).

Do you might know how to solve this puzzle?
Thank you for your response :slight_smile:

problem send class 00.gh (30.7 KB)

Hi F,

Classes are a major part of object-oriented programming, meaning that first you need to make an instance/object, before you can use it. The class itself is only part of the script, nothing more!

1st component:

class Dataset:
    def __init__(self, npnts):
        self.npnts = th.three_to_list(npnts)

# Output
dataset = Dataset(npnts)
print dataset

2nd component:

print dataset.npnts
1 Like

Just like functions, classes donā€™t do anything unless you instantiate/call them first.

Thank you.

What I want to do is this.
Having multiple data input to a class migrated through one connection to another component.

I am able to manage it with lists but not with trees.

problem send class 02.gh (41.6 KB)

Yes, I get that! There are numerous ways to accomplish this, but what - in my opinion - isnā€™t possible, is to pass code from one component to another. This seems to be, what you are currently trying to do, but you need to pass data instead!
Code can also be passed through the optional code input of the GHPython component, however that would have to be in form of a string (i.e. external .py file), which isnā€™t practical or necessary for this application.

I guess you need to understand a little more what classes are, given that itā€™s a complex topic!
Just imagine your class as being the blueprint to a factory. You can build as many factories (i.e. objects, class instances) as you want with this blueprint (code), but letā€™s say that beyond that, it doesnā€™t do much.
Each factory gets build/instantiated with some inherent functionality. def init(ā€¦) defines what is done/setup on instantiation of your class, analog to the day the factory opens, or rather the construction time.
However, as your factories grow economically, you might have to add machines to increase productivity, and thus update your blueprint. In Python, you can extend your class with methods/functions that help you manage class functionality and data.

Thereā€™s much more to classes, but itā€™s important to get the basics first!

problem send class 03.gh (38.9 KB)

Furthermore, if you donā€™t add more functionality to classes, than just saving data inside variables, it is much more efficient to use dictionaries, instead of class objects. You can also use dictionaries inside classes.

For example, this ā€¦:

class Node:
    def __init__():
        self.pos = None
        self.vel = None
        self.acc = None

nd = Node()
print nd.pos

ā€¦ and this ā€¦:

node = dict()

node["pos"] = None
node["vel"] = None
node["acc"] = None

print node["pos"]

ā€¦ does practically the same, in terms of data storage, but the dictionary handles for instance being searched much more efficiently.

Hereā€™s a more extended example of the above code using a single dictionary inside the class to handle your points lists:
problem send class 04.gh (38.8 KB)

2 Likes

Good news: see attached.
Bad news: you date the wrong girl ā€¦ meaning: you must do the C# > P thingy.

CastClass_EntryLevel_V1.gh (11.8 KB)

best

2 Likes

Another option for quickly creating immutable class objects would be:

from collections import namedtuple

Node = namedtuple('Node','pos vel acc')
n = Node(1,2,3)
print n
print n.pos
n.pos = 2
Traceback (most recent call last):
  File "<string>", line 1, in <module>
AttributeError: can't set attribute
2 Likes

When using the component data output and data input in another file the class does not go there.
Do you know why?

I have three trees. For C#, do you know a mighty manual of C#?

I am trying to make a class and with the components data output and date input to another file to transport the data.

Do you know if it is possible to transport classes to other files with the components data ouput and data input?

Reading your other questions, do you mean, instead of passing the instantiated class objects from your first component to the second, you want to pass it to another Grasshopper file?

Hm, for that you can use the sticky dictionary to transport all kinds of data.

Example GH File 1:

from scriptcontext import sticky
import Rhino.Geometry as rg

# Put your data into the sticky dictionary
sticky["test"] = rg.Point3d(3, 2, 1)

Example GH File 2:

from scriptcontext import sticky

# Fetch your data from the sticky dictionary and output it
a = sticky["test"]

I guess for this to work, both GH files need to be open! Instead of the point, you can also save class instances, as well as all kinds of other data types.

Another possibility would be to export structured data to a file (i.e. text file, JSON, etc.) on your hard-drive, which would be loaded into your second GH file, but thatā€™s more complicated!

I am going to use several datasets. Naming something sticky[ā€œAā€], sticky[ā€œBā€] will make it a little bit difficult.

Like with that one python component and input of three trees, I have several python components of those.

Do you might know a way to make it possible to use the components output and input in order to transfer classes to other files?

Or do people in general do that in a smarter way than I can came up with?

@PeterFotiadis @Dancergraham I am going to have several files with some repetition.
I now use the components output and input to let GH files communicate with each other and to transport data.
Making a class and transporting it through such portals as the components output and input works very handy for me.

I donā€™t know much about GH.
Have you tried defining your class in one python file, eg node.py then using eg from node import Node at the top of each of your python components ?

2 Likes

Is the thing to do (see attached as well: with regard entry level query matters). Provide a full case of yours: data, what exactly you want to do, why, queries, more queries, clustering goals etc etc.

CastClass_EntryLevel_V1A.gh (15.2 KB)

Other than that Reset Now For Ever:

  1. C# 7.0 in a Nutshell (Joseph/Ben Albahari) - my favorite.

http://www.albahari.com/

  1. C# in Depth (Jon Skeet) - the Bible.

  2. Effective, More Effective C# (Bill Wagner)

  3. Concurrency in C# Cookbook (Stephen Cleary)

  4. C# 6 for Programmers (Paul/Harvey Dietel)

1 Like

Itā€™s quite hard to tell what exactly it is youā€™re aiming for, but it definitely feels like you might be overcomplicating things. Implementing both classes, datatrees, and sticky for structuring/piping around data seems like a lot complexity (generally speaking, you can pass around whatever you like between GHPython components without much fuss). Perhaps you can provide us with a more explicit description of the pipeline you are imaging?

GH_file_00 | Class_A, Class_B, Class_C > component output

GH_file_01 | component input > Class_A, Class_B, Class_C

The class contains several types of data such as numbers, points, curves, breps, meshes.

All classes are build the same because they receive the same kind of data; like for example a ring, it has a size, amount of diamonds, and informing curves and points all ā€˜zippedā€™ to a class in order to unzip it in other files.
I have three rings therefor I made three classes.

During the process of different files I cut the ring, curves, points, etc. to get to a smaller scale; and I intend not to call the new datasets ā€˜smallpnts, smallerpnts, smallersmallerpntsā€™ in the naming.
I just want to say Class_A through several files just recognizing the data by the input component like GH_file_04 for example.

As you can read out of this, I am trying to find a workflow without having the output component containing many names (27 names).
Because I am aware of the possibility to make classes I am trying to make it classes to just work with (3 names) for the output component.

Do you have a better idea?

EDIT: please wait a second

@diff-arch
@PeterFotiadis
@Dancergraham
@AndersDeleuran

Please safe the output file again.
I am looking to this basic workflow. Within this workflow I can theoretically add as many data to a class as possible.
I tried C# but could not figure it completely out right.

And imagine this added many more data to the classes which I can input to other python and C# files in other GH_files as well.
What I win with doing it like this is winning time because I do not have to name all the stuff to the output component anymore because it is made a dataset.

@Dancergraham I could not figure out the Node thing yet.

Or is there a better workflow for transporting classes or data without naming everything over and over again you know about?

GH_file_01.gh (16.3 KB) GH_file_00.gh (98.8 KB)

Well ā€¦ if I got it correctly (?):

  1. You have some objects (cats, dogs, alligators etc) sampled in some sort of collection (List, DataTree, Stack etc etc).
  2. Each of them has meta-data assigned (kinda the BIM thingy works on AEC objects). Meta-data could be things/data related with the geometry of the object OR the hierarchy in the classic assemply/component approach OR something else like price, build date etc etc. Meta-data can be outsourced (BIM like) or partially outsourced while some are made on the fly or all made on the fly according a variety of filters (donā€™t bother with the price if an object is a mesh).
  3. Then ā€¦ basically ā€¦ you want to perform RDBMS queries on these (nested ones obvioulsy) like GroupBy by color and cost, then Select the ones that have vertices within a given Interval then OrderBy the build date then OrderBy availability then GroupBy whatever else etc etc.

Clustering in plain English (Flat, HAC, whatever) or some sort of Data mining.

If this schema is correct ā€¦ then the only way to cut the mustard is by doing LINQ stuff - like the primitive stuff in V1A above - in a List of a properly written custom class that contains all (or some) of the properties required.

For instance imagine going after 3d object equality (a chimera ā€¦ but anyway): thereā€™s a lot of things to compare while if one comparison fails thereā€™s no need to proceed to the next.

So : are the above generally describe your goal(s)?

1 Like

Hello,

So if you want to put your data into and out of files you can use pickle and/or shelve. Shelve basically acts like a dictionary - you can put any pickleable object in it.

Warning
The pickle module is not secure against erroneous or maliciously constructed data. Never unpickle data received from an untrusted or unauthenticated source.

2 Likes

@ForestOwl, I feel like you already have all the information to get to your goal. Remember the class is the blueprint, the instantiated object of it your collection of information.

So, this should read ā€œGH_file_00 | Object_A, Object_B, Object_C > component outputā€, and ā€œGH_file_01 | component_input > Object_A, Object_B, Object_Cā€.

No worries here, classes can swallow all kinds of data. Thereā€™s no type declaration in Python, meaning your variables can hold pretty much everything!

I donā€™t get what the problem is. Hereā€™s another example:

Example GH_file_00

In this file, you create your blueprint class, initialise as many class objects as you need, and store them in the sticky dictionary!
The information that you want to provide from the outside to the class on initialisation, is passed as arguments/attributes to the initialisation method (e.g. def__init__(self, base_curve)), and stored into class variables (i.e. self.base_curve=base_curve) inside this method.
Other information also gets initialised inside def__init__(self), but doesnā€™t have to be provided on initialisation (i.e. div_points=None), but the empty variable needs to be initialised (to be available later).

import Rhino.Geometry as rg
import scriptcontext as sc
import random

class Ring:
    """A ring.
    
    Attributes:
        base_curve (Rhino.Geometry.Curve): A ring base curve.
        size (float): A ring radius.
        num_diamonds (int): A number of diamonds.
    """
    def __init__(self, base_curve, size, num_diamonds):
        """Inits a ring."""
        self.base_curve = base_curve
        self.size = size
        self.num_diamonds = num_diamonds
        self.div_points = None # Get done when needed!
    
    def divide(self):
        """Equally divides the ring base curve."""
        # Save division points in self.div_points, previously initialised as empty variable
        self.div_points = self.base_curve.DivideByCount(self.num_diamonds, True)
        # And return the new division points, or don't! This is optional.
        return self.div_points

sc.sticky["my_rings"] = [] # stores your ring objects (not the class, but the class objects)

# base_curves provided through input
for i in xrange(len(base_curves)):
    curve = base_curves[i]
    size = random.uniform(1.7, 2.5)
    num_diamonds = random.randint(1, 12)
    # Instantiate a new ring
    ri = Ring(curve, size, num_diamonds)
    # Store your ring inside a list in sticky under "my rings"
    sc.sticky["my_rings"].append(ri)

Note how all the rings are saved under a single key ā€œmy_ringsā€, which can be used as such in each and every GH file that you want to fetch the information in.

Example GH_file_01, 02, 03, ā€¦ X

In the other files, you simply fetch the information from the sticky dictionary.
Note how we use the class method Ring.divide() here, to perform something after the rings have been initialised. Cool right!

import Rhino.Geometry as rg
import scriptcontext as sc

if "my_rings" in sc.sticky.keys():
    # Get the rings from sticky
    rings = sc.sticky["my_rings"]
    
    # Divide the rings
    for ri in rings:
        print "Diamonds: {}".format(ri.num_diamonds)
        print ri.div_points
        ri.divide()
        print ri.div_points

No, problem doing this with this method! Forget about C#, this doesnā€™t need its performance benefits and is easily achievable with Python.

You donā€™t have to name everything over and over again!

2 Likes