plotTree = function (dat) {
    # settings
    width = 500    # pixel
    plt = c(5, 98) / 100
    asp = 1.25     # ratio (y / x)
    circle = 20    # ratio to par('cin')[1]
    text = 0.25    # ratio to circle
    lwd = 0.5      # line width
    bgcolor = 'whiteSmoke'

    xlm = c(1, 2 ^ floor(log2(nrow(dat))))
    xpd = diff(xlm) / 18 * c(-1, 1)
    ypd = xpd / asp
    xlm = xlm + xpd
    ylm = range(dat$y) + ypd
    height1 = width * (plt[2] - plt[1]) * diff(ylm) * asp / diff(xlm)
    height2 = width * plt[1] + height1 + width * (1 - plt[2])

    plt[3] = width * plt[1] / height2
    plt[4] = (width * plt[1] + height1) / height2

    svg('.test.svg', width=width/96, height=height2/96)
    par(bg=bgcolor, plt = plt, xpd=NA)
    cexCircle = par('cin')[1] * circle
    cexText = cexCircle * text

    plot(asp=asp, axes=F, type='n',
        x=xlm, y=ylm, xlab='', ylab='', xaxs='i', yaxs='i')
    for (i in 2:nrow(dat)) lines(dat[c(i, floor(i / 2)),], col='red')
    points(dat, cex=cexCircle, pch=21, bg='white', lwd=lwd)
    text(dat, label=dat$val, cex=cexText)

    par(cex=cexText, tck=0.03)
    xat = seq(1, xlm[2] - 1, by=2)
    yat = unique(dat$y)
    for (i in 1:2) {
        if (i == 1) { at = xat } else { at = yat }
        axis(i, at=at, col=NA, col.ticks=1, labels=NA, lwd=lwd)
    }
    
    usr = par('usr')
    xlbAt = usr[1] - diff(usr[1:2]) / diff(plt[1:2]) * (plt[1] / 4)
    ylbAt = usr[3] - diff(usr[3:4]) / diff(plt[3:4]) * (plt[3] / 2)
    text(label=xat, x=xat, y=ylbAt)
    text(adj=1, label=yat, x=xlbAt, y=yat)
    box(lwd=lwd)

    graphics.off()
}
plotTree(dat)