Data Science

Machine learning & data science for beginners and experts alike.
Don't forget to submit your entry for the Excellence Awards by October 30! | Need more information about the program? Check out the blog here
Alteryx Certified Partner
Alteryx Certified Partner

Legolytics Part 1: Extracting Colours From an Image With Alteryx and R

Legolytics Part 2: Assigning the Lego Colour Palette

Legolytics Part 3: All Possible Bricks (you are here)

Legolytics Part 4: Optimizing Cost

Legolytics Part 5: The Product

The Lego Store

 

We now have our final image that we want to create with Lego bricks, but there is a level of optimization that can be done to reduce the cost of the image.

 

In order to do said optimization, we need to acknowledge what bricks can fit in the image, and at what positions can they fit into our image.

 

To do this, we will perform a two-step process. Step 1 is to acknowledge every possible brick position in our image. For step 2, we will check the validity of the brick position, by seeing if it crosses any colour boundaries, in that, a brick cannot be half Bright Yellow and half Black.

 

We also need to somehow acknowledge what Lego pieces are available. Unfortunately, this was a very boring, manual task, as the information loaded to the Lego website uses ‘Client-side’ rendering, which means you cannot use traditional web-scraping techniques to extract the data automatically.

 

Starting Positions

 

To do this in Alteryx, we can use the Generate Rows tool to increment both the X and Y position of our brick.

 

The image below shows the configuration for the Generate Rows tool. The initialization expression we have set the value to 1 (i.e., the left side of our image). We then create a new row, adding 1 for each loop.

 

We limit our expression so that we stop generating rows once the Starting Position X value exceeds 49, when combined with the width of the brick.

 

For example, in the instance of our 4x2 brick in portrait, the expression will stop looping when the Starting Position X hits 48, that is because 48, plus the width of the brick (2), equals 49; if we were to do one further iteration, then the brick the brick would go over the edge of our image.

 

BenMoss_0-1587666460474.png

 

We can then repeat this process for our Starting Position Y, but this time setting the limit to add the height of our object rather than the width.

 

By using the Generate Rows tool sequentially, we end up with all possible starting coordinates (that being the bottom left position) for all of our different brick types.

 

BenMoss_1-1587666460481.png

 

Validating Objects

 

Now that we have a data table which contains a list of all possible bricks that will fit into our grid, we now need to reduce this to only valid objects, by which I mean, objects which line up with the requirements of our image. (As an example, I can’t use a black 1x1 brick on a space which requires a bright yellow brick.)

 

To perform this process, we must first start by generating the X and Y position of each pixel, within each brick for our generated list (generating again being a key word), we can then merge this against our image pixel detail to acknowledge if the brick is valid or not. The process looks something like this:

 

Image Colours Required:

 

Pixel ID

Lego Colour

X

Y

1

Bright Yellow

1

1

2

Bright Yellow

1

2

3

Black

1

3


Objects Available:

 

Brick ID

Brick Size

Lego Colour

X

Y

1

1x3

Bright Yellow

1

1

1

1x3

Bright Yellow

1

2

1

1x3

Bright Yellow

1

3


By joining our Image Colours - Left and Objects Available - Right tables together using Lego Colour, X and Y as key fields we create two data streams, one in the Join output anchor, which would look as follows:

 

Brick ID

Brick Size

Lego Colour

X

Y

Pixel ID

1

1x3

Bright Yellow

1

1

1

1

1x3

Bright Yellow

1

2

2


And another stream in the Right output anchor, which would look like:

 

Brick ID

Brick Size

Lego Colour

X

Y

1

1x3

Bright Yellow

1

3


This is because the colour required for the pixel at position (1,3) is Black, but our brick colour is Bright Yellow; thus, by acknowledging if any part of a brick falls into the right output anchor, then we can assume these bricks are invalid, and remove them from our process.

 

BenMoss_2-1587666460485.png

 

Next Steps

 

Now that we have our image and have mapped and created a list of all bricks that will fit into our image, we can now go about a process of cost optimisation, in order to maximise our savings when compared with Lego’s algorithm! This process of optimization will be done using, you guessed it, the Optimization tool.

Comments
11 - Bolide

This series is so much fun, @BenMoss - thanks for sharing! How are different orientations of the bricks handled (for example, a 4x2 brick oriented horizontally with width=4 and height=2, vs. oriented vertically with width=2 and height=4)? Are they listed twice in the input dictionary (or the dictionary is self-unioned)?