Designing our bathroom with R

[This article was first published on That’s so Random, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

R has been an indispensable tool since I started working with it about five years ago. Of course in my day job as a data scientist I couldn’t live without it, but it also proved to be a great aid in private life. Recently we bought our first house and R came to the rescue several times in the process. We compared the impact of different mortgages on our finances in ten and twenty years time and I kept an eye on our spending through a Shiny app (I’ll admit the latter would have been less time consuming if I would have done it in Excel, like normal people).

I would never had expected that R would also be the go-to tool for decorating our bathrooms. When looking for inspiration online and in showrooms we came across many ugly and boring examples. Just when we were about to settle for a design like this
Ugly bathroom

we came to the luminous idea to create a random pattern from a few colors we liked. It is very difficult for human beings to produce a random pattern, since we tend to avoid clutters of the same color. Of course R’s random number generator does not suffer from this. Turning the random pattern into a nice design is (of course!) done with geom_tile from ggplot2. It is funny how you keep underestimating randomness, even when you work with data daily. I was looking for a nicely scattered design of the four colors we selected, rather we got Tetris-on-steroids patterns like this
True random

Nature needed to be a bit constrained in order to produce the design we were after. An adjustment was made to the function by adding a parameter for the maximum number of adjacent tiles of the same color. Allowing for two adjacent tiles of the same color gave us a very nice result.
Bathroom

Here are the functions that were used, the first two are helpers for the main function. Go ahead and redecorate your own bathroom!

<span class="n">library</span><span class="p">(</span><span class="n">ggplot2</span><span class="p">)</span><span class="w">
</span><span class="n">library</span><span class="p">(</span><span class="n">dplyr</span><span class="p">)</span><span class="w">
</span><span class="n">library</span><span class="p">(</span><span class="n">data.table</span><span class="p">)</span><span class="w">
</span><span class="n">library</span><span class="p">(</span><span class="n">magrittr</span><span class="p">)</span><span class="w">

</span><span class="c1"># helper function that checks for the next tile to be sampled if there
# are any colors that should be excluded because the max adjacent was
# reached either vertically or horizontally
</span><span class="n">check_colors</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">plot_data</span><span class="p">,</span><span class="w">
                         </span><span class="n">cur_width</span><span class="p">,</span><span class="w">
                         </span><span class="n">cur_height</span><span class="p">,</span><span class="w">
                         </span><span class="n">m_a</span><span class="p">){</span><span class="w">
  </span><span class="k">if</span><span class="p">(</span><span class="n">cur_height</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="n">m_a</span><span class="p">){</span><span class="w">
    </span><span class="n">colors_height</span><span class="w"> </span><span class="o"><-</span><span class="w">
      </span><span class="n">plot_data</span><span class="p">[</span><span class="n">Height</span><span class="w"> </span><span class="o">%in%</span><span class="w"> </span><span class="p">(</span><span class="n">cur_height</span><span class="o">-</span><span class="p">(</span><span class="n">m_a</span><span class="p">))</span><span class="o">:</span><span class="p">(</span><span class="n">cur_height</span><span class="m">-1</span><span class="p">)</span><span class="w"> </span><span class="o">&</span><span class="w">
                  </span><span class="n">Width</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">cur_width</span><span class="p">,</span><span class="w"> </span><span class="n">color</span><span class="p">]</span><span class="w"> </span><span class="o">%>%</span><span class="w"> </span><span class="n">unique</span><span class="w">
  </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w">
    
    </span><span class="n">colors_height</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="kc">NULL</span><span class="w">
  </span><span class="p">}</span><span class="w">
  
  </span><span class="k">if</span><span class="p">(</span><span class="n">cur_width</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="n">m_a</span><span class="p">){</span><span class="w">
    </span><span class="n">colors_width</span><span class="w"> </span><span class="o"><-</span><span class="w">
      </span><span class="n">plot_data</span><span class="p">[</span><span class="n">Width</span><span class="w"> </span><span class="o">%in%</span><span class="w"> </span><span class="p">(</span><span class="n">cur_width</span><span class="o">-</span><span class="p">(</span><span class="n">m_a</span><span class="p">))</span><span class="o">:</span><span class="p">(</span><span class="n">cur_width</span><span class="m">-1</span><span class="p">)</span><span class="w"> </span><span class="o">&</span><span class="w">
                  </span><span class="n">Height</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">cur_height</span><span class="p">,</span><span class="w"> </span><span class="n">color</span><span class="p">]</span><span class="w"> </span><span class="o">%>%</span><span class="w"> </span><span class="n">unique</span><span class="w">
  </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="n">colors_width</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="kc">NULL</span><span class="w">
  </span><span class="p">}</span><span class="w">
  
  </span><span class="k">if</span><span class="p">(</span><span class="nf">length</span><span class="p">(</span><span class="n">colors_height</span><span class="p">)</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="m">1</span><span class="p">)</span><span class="w"> </span><span class="n">colors_height</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="kc">NULL</span><span class="w">
  </span><span class="k">if</span><span class="p">(</span><span class="nf">length</span><span class="p">(</span><span class="n">colors_width</span><span class="p">)</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="m">1</span><span class="p">)</span><span class="w"> </span><span class="n">colors_width</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="kc">NULL</span><span class="w">
  </span><span class="n">exclude</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="n">colors_height</span><span class="p">,</span><span class="w"> </span><span class="n">colors_width</span><span class="p">)</span><span class="w">
  </span><span class="k">if</span><span class="p">(</span><span class="nf">length</span><span class="p">(</span><span class="n">exclude</span><span class="p">)</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="m">0</span><span class="p">)</span><span class="w"> </span><span class="n">exclude</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="m">0</span><span class="w">
  
  </span><span class="nf">return</span><span class="p">(</span><span class="n">exclude</span><span class="p">)</span><span class="w">
</span><span class="p">}</span><span class="w">

</span><span class="c1"># helper function that samples a tile color from a vector with remaining tiles
# excluding a color if necesarry. Returns the sample color and the vector with
# remaining colors for the next iteration.
</span><span class="n">sample_color</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">exclude</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">0</span><span class="p">,</span><span class="w">
                         </span><span class="n">cts</span><span class="p">){</span><span class="w">
  </span><span class="k">if</span><span class="p">(</span><span class="n">cts</span><span class="w"> </span><span class="o">%>%</span><span class="w"> </span><span class="n">is_in</span><span class="p">(</span><span class="n">exclude</span><span class="p">)</span><span class="w"> </span><span class="o">%>%</span><span class="w"> </span><span class="n">all</span><span class="p">){</span><span class="w">
    </span><span class="n">stop</span><span class="p">(</span><span class="s1">'There is no valid solution due to adjacency constraint, please try again'</span><span class="p">)</span><span class="w">
  </span><span class="p">}</span><span class="w">
  
  </span><span class="n">valid_color</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="kc">FALSE</span><span class="w">
  </span><span class="k">while</span><span class="p">(</span><span class="n">valid_color</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="kc">FALSE</span><span class="p">){</span><span class="w">
    </span><span class="n">color</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">sample</span><span class="p">(</span><span class="n">cts</span><span class="p">,</span><span class="w"> </span><span class="m">1</span><span class="p">)</span><span class="w">
    </span><span class="k">if</span><span class="p">(</span><span class="n">color</span><span class="w"> </span><span class="o">%>%</span><span class="w"> </span><span class="n">is_in</span><span class="p">(</span><span class="n">exclude</span><span class="p">)</span><span class="w"> </span><span class="o">%>%</span><span class="w"> </span><span class="n">not</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="n">valid_color</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="kc">TRUE</span><span class="w">
      </span><span class="n">return_list</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">list</span><span class="p">(</span><span class="n">color</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">color</span><span class="p">,</span><span class="w">
                          </span><span class="n">cts</span><span class="w"> </span><span class="o">=</span><span class="w">
                            </span><span class="n">cts</span><span class="p">[</span><span class="o">-</span><span class="p">((</span><span class="n">cts</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">color</span><span class="p">)</span><span class="w"> </span><span class="o">%>%</span><span class="w"> </span><span class="n">which.max</span><span class="p">)])</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">}</span><span class="w">
  </span><span class="nf">return</span><span class="p">(</span><span class="n">return_list</span><span class="p">)</span><span class="w">
</span><span class="p">}</span><span class="w">

</span><span class="c1"># This function will generate a random pattern of tiles.
</span><span class="n">tiles_pattern</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="w">
  </span><span class="n">colors</span><span class="w">         </span><span class="o">=</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="s1">'darkblue'</span><span class="p">,</span><span class="w"> </span><span class="s1">'cyan3'</span><span class="p">,</span><span class="w"> </span><span class="s1">'lightblue1'</span><span class="p">,</span><span class="w"> </span><span class="s1">'white'</span><span class="p">),</span><span class="w">   </span><span class="c1"># vector with the colors
</span><span class="w">  </span><span class="n">nr_of_each_col</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">rep</span><span class="p">(</span><span class="m">40</span><span class="p">,</span><span class="w"> </span><span class="m">4</span><span class="p">),</span><span class="w">     </span><span class="c1"># prevalence of each color in colors vector
</span><span class="w">  </span><span class="n">nr_height</span><span class="w">      </span><span class="o">=</span><span class="w"> </span><span class="m">8</span><span class="p">,</span><span class="w"> </span><span class="c1"># nr of tiles in vertical direction
</span><span class="w">  </span><span class="n">nr_width</span><span class="w">       </span><span class="o">=</span><span class="w"> </span><span class="m">20</span><span class="p">,</span><span class="w"> </span><span class="c1"># nr of tiles in horizontal directions
</span><span class="w">  </span><span class="n">max_adjacent</span><span class="w">   </span><span class="o">=</span><span class="w"> </span><span class="m">2</span><span class="p">)</span><span class="w">  </span><span class="c1"># maximimum nr of adjacent tiles of the same color
</span><span class="p">{</span><span class="w">
  
  </span><span class="k">if</span><span class="p">(</span><span class="nf">length</span><span class="p">(</span><span class="n">colors</span><span class="p">)</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="nf">length</span><span class="p">(</span><span class="n">nr_of_each_col</span><span class="p">)){</span><span class="w">
    </span><span class="n">stop</span><span class="p">(</span><span class="s1">'nr_of_each_col vector should be same length as the colors vector'</span><span class="p">)</span><span class="w">
  </span><span class="p">}</span><span class="w">
  </span><span class="k">if</span><span class="p">(</span><span class="nf">sum</span><span class="p">(</span><span class="n">nr_of_each_col</span><span class="p">)</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="n">nr_height</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">nr_width</span><span class="p">){</span><span class="w">
    </span><span class="n">stop</span><span class="p">(</span><span class="s1">'Sum nr_of_each_col should equal nr_height * nr_width'</span><span class="p">)</span><span class="w">
  </span><span class="p">}</span><span class="w">
  
  </span><span class="n">plot_data</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">expand.grid</span><span class="p">(</span><span class="m">1</span><span class="o">:</span><span class="n">nr_height</span><span class="p">,</span><span class="w"> </span><span class="m">1</span><span class="o">:</span><span class="n">nr_width</span><span class="p">)</span><span class="w"> </span><span class="o">%>%</span><span class="w"> </span><span class="n">as.data.table</span><span class="w">
  </span><span class="n">colnames</span><span class="p">(</span><span class="n">plot_data</span><span class="p">)</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="s1">'Height'</span><span class="p">,</span><span class="w"> </span><span class="s1">'Width'</span><span class="p">)</span><span class="w">
  </span><span class="n">plot_data</span><span class="o">$</span><span class="n">color</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">integer</span><span class="p">(</span><span class="n">nrow</span><span class="p">(</span><span class="n">plot_data</span><span class="p">))</span><span class="w">
  
  </span><span class="n">colors_to_sample</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">rep</span><span class="p">(</span><span class="m">1</span><span class="o">:</span><span class="nf">length</span><span class="p">(</span><span class="n">colors</span><span class="p">),</span><span class="w"> </span><span class="n">nr_of_each_col</span><span class="p">)</span><span class="w">
  
  </span><span class="k">for</span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="m">1</span><span class="o">:</span><span class="p">(</span><span class="n">nr_width</span><span class="p">)){</span><span class="w">
    </span><span class="k">for</span><span class="p">(</span><span class="n">j</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="m">1</span><span class="o">:</span><span class="n">nr_height</span><span class="p">){</span><span class="w">
      </span><span class="n">exclude_iter</span><span class="w">     </span><span class="o"><-</span><span class="w"> </span><span class="n">check_colors</span><span class="p">(</span><span class="n">plot_data</span><span class="p">,</span><span class="w"> </span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="n">j</span><span class="p">,</span><span class="w"> </span><span class="n">max_adjacent</span><span class="p">)</span><span class="w">
      </span><span class="n">color_iter</span><span class="w">       </span><span class="o"><-</span><span class="w"> </span><span class="n">sample_color</span><span class="p">(</span><span class="n">exclude_iter</span><span class="p">,</span><span class="w"> </span><span class="n">colors_to_sample</span><span class="p">)</span><span class="w">
      </span><span class="n">plot_data</span><span class="p">[</span><span class="n">Height</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="n">Width</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="n">color</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="n">color_iter</span><span class="o">$</span><span class="n">color</span><span class="p">]</span><span class="w">
      </span><span class="n">colors_to_sample</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">color_iter</span><span class="o">$</span><span class="n">cts</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">}</span><span class="w">
  
  </span><span class="n">plot_data</span><span class="p">[</span><span class="w"> </span><span class="p">,</span><span class="n">color</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="n">color</span><span class="w"> </span><span class="o">%>%</span><span class="w"> </span><span class="n">as.character</span><span class="p">]</span><span class="w">
  
  </span><span class="c1"># build the plot
</span><span class="w">  </span><span class="n">ggplot</span><span class="p">(</span><span class="n">plot_data</span><span class="p">,</span><span class="w"> </span><span class="n">aes</span><span class="p">(</span><span class="n">Width</span><span class="p">,</span><span class="w"> </span><span class="n">Height</span><span class="p">))</span><span class="w"> </span><span class="o">+</span><span class="w">
    </span><span class="n">geom_tile</span><span class="p">(</span><span class="n">aes</span><span class="p">(</span><span class="n">fill</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">color</span><span class="p">),</span><span class="w"> </span><span class="n">col</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">'grey'</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w">
    </span><span class="n">scale_fill_manual</span><span class="p">(</span><span class="n">values</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="s1">'1'</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">colors</span><span class="p">[</span><span class="m">1</span><span class="p">],</span><span class="w">
                                 </span><span class="s1">'2'</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">colors</span><span class="p">[</span><span class="m">2</span><span class="p">],</span><span class="w">
                                 </span><span class="s1">'3'</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">colors</span><span class="p">[</span><span class="m">3</span><span class="p">],</span><span class="w">
                                 </span><span class="s1">'4'</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">colors</span><span class="p">[</span><span class="m">4</span><span class="p">]))</span><span class="w"> </span><span class="o">+</span><span class="w">
    </span><span class="n">xlab</span><span class="p">(</span><span class="s1">''</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w">
    </span><span class="n">ylab</span><span class="p">(</span><span class="s1">''</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w">
    </span><span class="n">guides</span><span class="p">(</span><span class="n">fill</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">FALSE</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w">
    </span><span class="n">theme_bw</span><span class="p">()</span><span class="w"> </span><span class="o">+</span><span class="w">
    </span><span class="n">theme</span><span class="p">(</span><span class="w">
      </span><span class="n">plot.background</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">element_blank</span><span class="p">()</span><span class="w">
      </span><span class="p">,</span><span class="n">panel.grid.major</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">element_blank</span><span class="p">()</span><span class="w">
      </span><span class="p">,</span><span class="n">panel.grid.minor</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">element_blank</span><span class="p">()</span><span class="w">
      </span><span class="p">,</span><span class="n">panel.border</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">element_blank</span><span class="p">()</span><span class="w">
      </span><span class="p">,</span><span class="n">axis.ticks.x</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">element_blank</span><span class="p">()</span><span class="w">
      </span><span class="p">,</span><span class="n">axis.ticks.y</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">element_blank</span><span class="p">()</span><span class="w">
      </span><span class="p">,</span><span class="n">axis.text.x</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">element_blank</span><span class="p">()</span><span class="w">
      </span><span class="p">,</span><span class="n">axis.text.y</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">element_blank</span><span class="p">()</span><span class="w">
    </span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w">
    </span><span class="n">coord_fixed</span><span class="p">()</span><span class="w">
</span><span class="p">}</span><span class="w">
</span>

To leave a comment for the author, please follow the link and comment on their blog: That’s so Random.

R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Never miss an update!
Subscribe to R-bloggers to receive
e-mails with the latest R posts.
(You will not see this message again.)

Click here to close (This popup will not appear again)