what´s the easiest way to disassemble a grid randomly
into various squares and/or rectangles like shown in the picture?
Im trying to find a solution but it seems pretty difficult to me.
thanks in advance
- grid_rect.png 10.3 KB
|?||Show this help|
|ESC||Blurs the current field|
|r||Focus the comment reply box|
|^ + ↩||Submit the comment|
You can use
Command ⌘ instead of
Control ^ on Mac
Support Staff 1 Posted by john on 19 May, 2020 08:12 PM
Your goal is indeed a bit trickier than it seems.
It's easy to generate a list of randomly sized rectangles. Finding a list of randomly sized rectangles that fit perfectly into a larger rectangle is a harder problem.
Most algorithms that do this require recursion. They subdivide the outer rectangle into smaller rectangles, then do the same to each of those, and so on until some limit is reached. Unfortunately NodeBox does not support recursion.
What you are trying to do is similar to a treemap. Treemaps, essentially rectangular versions of pie charts, are used in information visualization. I do this all the time so made my own treemap custom node (included in my node library). Because the algorithm requires recursion, I had to use Python to make the custom node.
I have attached an example NodeBox network with the treemap node included (see screenshot). I generate 12 random rectangles and fit them into an outer rectangle with the same dimensions as your example image. I color them with classic Mondrian colors to produce something similar to a Mondrian style drawing. You can change the seeds in the nodes defining the small rectangle sizes and the shuffling of the colors to try many variations.
You will notice I said that this is similar to a Mondrian. The actual paintings Mondrian produced were not, of course, totally random. In addition to his careful balancing of color (with more white than other colors), he chose from a limited set of box sizes and was careful about the way he subdivided the grid.
The treemap is not as careful about subdividing the grid. It does whatever it needs to do to pack all the rectangles perfectly into the assigned space. You can influence this by picking rectangle sizes more carefully. This may or may not be acceptable to you.
If it's not, you need to think more clearly about exactly what constraints you want to place on the way you subdivide the grid. If you can describe those constraints I can help you find a way to implement them in Nodebox (even without recursion).
Good luck and please consider sharing some of the designs you produce in our Show Your Work forum.
Support Staff 2 Posted by john on 19 May, 2020 08:58 PM
Attached is a revised version of my Mondrian demo that comes a little closer to your example.
I made two changes:
This gets you slightly closer to what you want, but the grid is still not subdivided in a constrained way.
3 Posted by tom on 20 May, 2020 01:43 AM
thank you for the fast reply!
the mondrian approach and treemap are very interesting and i learnt a bit by exploring these nodes.
i think it can lead me in the right direction.
but what i am really trying to achieve is not just dissecting a single rectangle, rather a grid consisting of points into rectangles containing these points.
these "point-groups" should be accessible in order to sort their content
(in my case randomly sized squares on the grid)
Support Staff 4 Posted by john on 20 May, 2020 08:57 AM
I think a slight modification of my earlier example will do what you want.
My solution (attached, see screenshot) starts with a grid of points, uses that to define a rectangle for my treemap node, then uses a snap node to snap the output back to the original grid.
At the top of the network you will see five nodes that define the output:
To clarify that the output really does produce the point groups you want within the original grid, I show both a Mondrian coloring of the boxes and an outline of the boxes superimposed over the dots of the grid.
The ungrouped output of the snap grid is N rectangles. If you want the "point group" corresponding to each rectangle you can just attach each rectangle to a point node to get its four corner points. There are several ways to get the interior points if you want those as well - let me know if you have any trouble deriving them.
The snap grid is a tad finicky. I used an align node set to left bottom to make sure the grid is not offset from the origin. Snap only has a single distance port, so vertical and horizontal grid spacing must be the same. If you need to have a vertical separation that differs from the horizontal separation, you can use a scale node to stretch or shrink the grid in one dimension after the snap is complete.
Play with all five of the top nodes to see what kind of directions you get. If the distribution of box sizes is too even, you can replace the simple random node with something more complex. For example, you could produce one big box, a few medium sized boxes, and the rest small. Or explicitly define relative box sizes using a make_numbers node as I did in my second example.
Let me know if this does what you need. Thanks for an interesting challenge!
5 Posted by tom on 20 May, 2020 10:59 AM
thanks again for your fast and profound reply!
to be honest, i´m even already having trouble outputting the n-rectangles from the ungrouped snap. it´s more than just adding a point and rect node, is it?
extruding the interior points of the individual rectangles, would be the next big challenge for me.
Support Staff 6 Posted by john on 21 May, 2020 05:50 AM
Sorry - I didn't see your last note till just now.
if you render the ungroup node just below the snap node and switch to data view you will see there are 12 paths corresponding to the 12 rectangles. You can feed them into a slice node and look at them one at a time to see which is which.
If you hook a point node to that ungroup node you will get 48 points (4 for each rectangle). If you want to deal with one rectangle at a time, one way is to make a simple subnetwork. Hook a null node from the ungroup node, control-click it, and "Group into Network".
You now have a subnetwork that fires once for each of the 12 rectangles feeding into it. If you "Edit Children" and look inside your subnetwork you can attach a point node to the null node and operate on its four corners. Or attach a centroid node to return the center position of each rectangle. Or resample the rectangle to create points around its perimeter. Or feed in the point ellipses through a new port (set to list so they come in all at once) and use a compound node to capture the intersection of your rectangle and the Grid points. Or whatever else you want to do.
That is the question: what exactly do you want to do with each rectangle?
P.S. Just for fun I made an animation of Mondrian patterns (attached).
7 Posted by tom on 24 May, 2020 02:00 PM
no problem, thanks for your effort!
i managed to make the subnetwork and extract the individual rectangles.
i also managed to capture the intersection of rectangle and your ellipse based grid points.
but what i´m struggling with, is doing the same with points values.
especially extracting the points of the individual rectangles and those within (as seen in the picture of my first post)
to answer your question:
i have this grid filled with about 2500 individually sized rectangles.
because this already gives me a kind of three-dimensional impression, i´m trying to provoke it a bit more.
my idea was to seperate the whole grid into rectangles, like you did with the treemap. and then sort the rectangles within by size, starting from the centerpoint of a tile to the borders
Support Staff 8 Posted by john on 24 May, 2020 09:33 PM
I have attached another version which decomposes each rectangle into a mini-grid of interior cells (see screenshot).
To demonstrate I show the Mondrian decomposition superimposed on the mini-grids on the left, with an exploded view of the mini-grids on the right. There are 50 boxes and a total of 2500 individual cells.
The interior_grid subnetwork takes each rectangle and spits out an array of square-shaped cells which fill that rectangle as a grouped geometry. If you want the actual points you can ungroup and take the centroids.
I don't quite follow what you are trying to do, but I hope this will get you one step closer.
I am enjoying this. Please let me know if there's anything else you need.
9 Posted by jen on 30 May, 2022 05:22 AM
I am loving NB. I was actually able to create a football team data viz shortly after discovering it. See attached. As I am a total non-coder this was thrilling for me.
That said I have a noobie question for you. I would like to add your treemap node to the dropdown list of node options to use in any new NB file I create, but I don't know how to do this. I've read thru the creating new nodes tutorial but not getting far. Can you help please?
Support Staff 10 Posted by john on 30 May, 2022 07:37 AM
Welcome to the Nodebox community. Your data viz is quite interesting. Nodebox is an amazing tool for data visualization ; I hope you will keep playing with it.
The reason you are having trouble figuring out how to add one of my nodes to the standard node creation dialog is that, sadly, it cannot be done. It sure would be nice if you could. I once requested this feature, as have others, but it was never implemented.
So we have to rough it. Fortunately, the workaround is not too hard.
I trust you already have the latest Cartan Node library 3-1 installed on your hard drive somewhere and have already opened it to find nodes like treemap. So the next time you are inside your own Nodebox project and need to add any one of my nodes, do the following:
Choose "Open Recent" from the File Menu and choose Cartan node library 3-1. (If it's not already in the list it will be from now on if you get into this habit).
When my library opens, find the node you want, select, and copy
Return to your project and paste
With a little practice this becomes second nature and can be done in under ten seconds. Be sure to use the latest 3-1 version: I reformatted it to make it as easy as possible to find the nodes you need.
Most of my nodes are actually subnetworks and do not require external code libraries. But, as you probably already know, treemap is one of the handful that DO require external code to work. If in doubt, hover over my node; the comment will say if a code module is required and, if so, which one.
External modules are a slight pain to deal with. If you need one I strongly recommend first creating a folder for your NDBX file. You can then drag a COPY of the module from the Cartan Node Library folder into your project folder (on the Mac option-drag the file). For the treemap node the required file is treemap.py. Once you have a local copy inside your project folder, you can add it from the Code Libraries dialog under the File menu. Keeping the external code in the same folder as your NDBX file will ensure that you won't encounter errors if you ever move your files to a different location or send them to someone else.
A slight pain I know, but you only have to do it once and only when you use nodes that require external code.
I hope you can learn to live with this mild inconvenience, and that you stick with Nodebox. Please write me anytime you have any questions at all or if you get stuck on a project. I actually enjoy helping people get unstuck.
Hope to hear from you again soon!
11 Posted by Jennifer Concan... on 02 Jun, 2022 02:48 AM
Thanks for your node library, I used it for the first time today and
using your workaround of copying and pasting is no big deal. I LOVE that
you have examples; I wish there were examples for some of the built-in
My company has 4 pillars that it works pretty hard to instill: Excellence
in client services; Strong financial returns; Support the community; Honor
employees and families. The company president is also very religious and
so I thought I would play with NB to see if I could come up with a cool
gift for him. The attached shows how these principles can be found in the
Bible, albeit some are loose interpretations. I used your Curve node to
create the concave curves in the pillar tops and bottoms and it was VERY
helpful. I know that the alignment is off, but this is actually a scaled
down version; there's a TON more verses to be added so I'll fine tune later.
One thing I noticed was that when I put together the shapes to make the
column headers, I couldn't figure out how to get all the components grouped
together such that NB treated them as one object so that if I decrease the
alpha color value, the individual components would not show. Any tips?
PS, NB is crazy addictive!
Support Staff 12 Posted by john on 02 Jun, 2022 10:08 AM
I don't see an attachment so I can't tell exactly what you're doing. But in general the group node is what you use to make Nodebox treat multiple components as a single group.
If you are trying to make some things disappear you can do it a little easier using my fade node.
If you're still stuck, feel free to attach the code and I will fix it for you.
And yes, NB is crazy addictive!
13 Posted by Jennifer Concan... on 02 Jun, 2022 10:19 PM
Sigh...forgetting the attachment sounds like something I would do. Here it
is, along with the columns when alpha is reduced.
Also, is there a way to create a background color that only appears where
nothing else is? I used your backdrop node with the default color that was
perfect for the chart but I don't want it to skew the appearance of all the
colorful lines that have reduced alpha values. I like the way the
transparency gives more variety of colors, but I don't want the color of
everything yellowed by a light beige background. Any ideas?
Support Staff 14 Posted by john on 02 Jun, 2022 11:58 PM
Thanks for the attachments. The first one came through, but the second was unreadable for some reason. In general when seeking my input it is better to attach zipped versions of the NDBX files (if you don't mind sharing them); that way I can see all of your parameters and discover exactly what you are doing. This also allows me to return you versions with fixes in place.
I think I see what might be happening with your grouped elements. When applying colorize to such a group, the color will be applied to all members of the group in order. If some overlap, and if the common color has reduced alpha, the overlapping areas will appear darker. This is just the way translucent coloring works.
One way around this is to use compound instead of combine to produce a single shape (as you do elsewhere). With a single compounded shape there are no more overlaps.
Another way is to avoid translucent colors. I'm not sure why you need them in this case. If you set a group of overlapping components to the same solid fill color (with no stroke outlines) the overlapping areas will be invisible.
This point may also apply to your second question. Translucent colors are handy for creating shadows and can produce interesting effects in animations. But once they are rendered as a PNG or PDF, they are replaced with whatever solid RGB color is produced by the combination of the translucent color and the base color beneath it.
If you want to preserve an interesting translucent color arising against NodeBox's default gray background while also supplying a general background in some other color, I would recommend using a solid color for your foreground elements instead. If you are having trouble finding the exact RGB for the solid equivalent, you can use my new blend node (which will appear in the next rev of my library):
(You can use #e8e8e8ff for the background value to simulate your translucent color against NodeBox gray.)
It is a good idea to always supply a solid color background to any Nodebox image you export by using my backdrop node or placing a simple colorized rectangle the same dimensions as the canvas at the bottom of the combined elements. Without such a backdrop, different applications may interpret the canvas differently, coloring it white or gray or even black. Using such a backdrop from the beginning also allows you to see the colors as they will actually appear in the final product - especially important If some of them are translucent.
Hope that helps. Keep the questions coming!