title: Creating a symmetrical grid of random size squares in Python3/Tkinter
body: <p>I have a question revolving around what would be a viable approach to placing out random-sized squares on a symmetrical, non-visible grid on a tkinter-canvas. I'm going to explain it quite thoroughly as it's a somewhat proprietary problem.</p>
  
  <p>This far I've tried to solve it mostly mathematically. But I've found it to be quite a complex problem, and it seems reasonable that there would be a better approach to take it on than what I've tried.</p>
  
  <p>In its most basic form the code looks like this:</p>
  
  <pre><code>while x_len &gt; canvas_width:
                  xpos = x_len + margin
                  squares[i].place(x=xpos, y=ypos)
                  x_len += square_size + space
                  i += 1
  </code></pre>
  
  <p>x_len is the total width of all the squares on a given row, and resets when exiting the while-loop (eg. when x_len > window width), among with xpos (the position on X), as well as altering Y-axis to create a new row.</p>
  
  <p>When placing same-size squares it looks like this:
  <a href="https://i.stack.imgur.com/2Ndz8.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/2Ndz8.png" alt="same-size squares"></a></p>
  
  <p>So far so good.</p>
  
  <p>However when the squares are of random-size it looks like this (at best):
  <a href="https://i.stack.imgur.com/XdAJJ.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/XdAJJ.png" alt="random-size squares"></a></p>
  
  <p>The core problem, beyond that the layout can be quite unpredictable, is that the squares aren't centered to the "invisible grid" - because there is none.</p>
  
  <p>So to solve this I've tried an approach where I use a fixed distance and a relative distance based on every given square. This yields satisficing results for the Y-axis on the first row, but not on the X-axis, nor the following rows on Y.</p>
  
  <p>See example (where first row is centered on Y, but following rows and X is not):</p>
  
  <p><a href="https://i.stack.imgur.com/Gj2YR.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/Gj2YR.png" alt="random-size squares with new function"></a></p>
  
  <p>So with this method I'm using a per-square alteration in both Y- and X-axis, based on variables that I fetch from a list that contain widths for all of the generated squares.</p>
  
  <p>In it's entirety it looks like this (though it's work in progress so it's not very well optimized):</p>
  
  <pre><code>square_widths = [60, 75, 75, 45...]
  
  space = square_size*0.5
  margin = (square_size+space)/2
  xmax = frame_width - margin - square_size
  xmin = -1 + margin
  
  def iterate(ypos, xpos, x_len):
      y = ypos
      x = xpos
      z = x_len
      i=0
      m_ypos = 0
      extra_x = 0
  
      while len(squares) &lt;= 100:
          n=-1
          # row_ypos alters y for every new row
          row_ypos += 200-square_widths[n]/2
  
          # this if-statement is not relevant to the question
          if x &lt; 0:
              n=0
              xpos = x
              extra_x = x
              x_len = z
              while x_len &lt; xmax:
                  ypos = row_ypos
                  extra_x += 100
                  ypos = row_ypos + (200-square_widths[n])/2
                  xpos = extra_x + (200-square_widths[n])/2
                  squares[i].place(x=xpos, y=ypos)
                  x_len = extra_x + 200
                  i += 1
                  n += 1
  </code></pre>
  
  <p>What's most relevant here is row_ypos, that alters Y for each row, as well as ypos, that alters Y for each square (I don't have a working calculation for X yet). What I would want to achieve is a similar result that I get for Y-axis on the first row; on all rows and columns (eg. both in X and Y). To create a symmetrical grid with squares of different sizes.</p>
  
  <p>So my questions are:
  Is this really best practice to solve this?
  If so - Do you have any tips on decent calculations that would do the trick?
  If not - How would you approach this?</p>
  
  <p>A sidenote is that it has to be done "manually" and I can not use built-in functions of tkinter to solve it.</p>