function makeAxisGroups(gd, traces) {
    var groups = [];
    var i, j;

    for(i = 0; i < traces.length; i++) {
        var groupsi = [];
        var xi = gd._fullData[traces[i]].xaxis;
        var yi = gd._fullData[traces[i]].yaxis;
        if(!xi || !yi) continue; // not a 2D cartesian trace?

        for(j = 0; j < groups.length; j++) {
            if(groups[j].x.indexOf(xi) !== -1 || groups[j].y.indexOf(yi) !== -1) {
                groupsi.push(j);
            }
        }

        if(!groupsi.length) {
            groups.push({x: [xi], y: [yi]});
            continue;
        }

        var group0 = groups[groupsi[0]];
        var groupj;

        if(groupsi.length > 1) {
            for(j = 1; j < groupsi.length; j++) {
                groupj = groups[groupsi[j]];
                mergeAxisGroups(group0.x, groupj.x);
                mergeAxisGroups(group0.y, groupj.y);
            }
        }
        mergeAxisGroups(group0.x, [xi]);
        mergeAxisGroups(group0.y, [yi]);
    }

    return groups;
}
Find all margin pushers for 2D axes and reserve them for later use
Both label and rangeslider automargin calculations happen later so
we need to explicitly allow their ids in order to not delete them.

TODO: can we pull the actual automargin calls forward to avoid this hack?
We're probably also doing multiple redraws in this case, would be faster
if we can just do the whole calculation ahead of time and draw once.