After clarifying your criteria for niceness as suggested in another answer, you may utilize a constraint solving algorithm, which are often pretty successful at graphical layout problems. Choosing which one depends a bit on experience and availability for your programming language, you may need to look around and experiment a little to find one that suits you.
If you're into Python or C++, the kiwisolver package may be a possible approach. It's an implementation of the Cassowary algorithm which is able to solve linear constraints in an intuitive manner.
For fun, I've tried running the example through kiwisolver (was too lazy to add painting the graph):
from kiwisolver import Variable, Solver
solver = Solver()
# row 1
a = Variable("a")
b = Variable("b")
c = Variable("c")
d = Variable("d")
# row 2
e = Variable("e")
f = Variable("f")
g = Variable("g")
# row 3
h = Variable("h")
i = Variable("i")
# row 4
j = Variable("j")
k = Variable("k")
l = Variable("l")
m = Variable("m")
# row 5
n = Variable("n")
o = Variable("o")
constraints = [
# row 1
b >= 0, a >= b+10, d >= a+10, c >= d+10, c <= 30,
# row 2
f >= 0, e >= f+10, g >= e+10, g <= 30,
# row1 -> row2
(f == (b + d) / 2) | "strong", (e == (a + d) / 2) | "strong", (g == (d + c) / 2) | "strong",
# row 3
h >= 0, i >= h+10, i <= 30,
# row 2 -> row 3
(h == (f + e) / 2) | "strong", (i == (e + g) / 2) | "strong",
# row 4
l >= 0, m >= l+10, j >= m+10, k >= j+10, k <= 30,
# row 3 -> row 4
(l == h) | "strong", (m == h) | "strong", (j == i) | "strong", (k == i) | "strong",
# row 5
n >= 0, o >= n+10, o <= 30,
# row 4 -> row 5
(n == (l + j) / 2) | "strong", (o == (m + j) / 2) | "strong",
]
for constraint in constraints:
solver.addConstraint(constraint)
solver.updateVariables()
for v in [b,a,d,c,f,e,g,h,i,l,m,j,k,n,o]:
print(v.name(), "=", v.value())
Result:
b = 0.0
a = 10.0
d = 20.0
c = 30.0
f = 5.0
e = 15.0
g = 25.0
h = 10.0
i = 20.0
l = 0.0
m = 10.0
j = 20.0
k = 30.0
n = 10.0
o = 20.0