In [1]:
%matplotlib inline
from copy import deepcopy
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.mlab import griddata
from matplotlib import colors, cm, ticker
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.axes_grid1 import AxesGrid
import pylab
pylab.rcParams['figure.figsize'] = (20.0, 20.0)

In [2]:
def bruteforce_to_dict(data):
    assert data.ndim == 2 and data.shape[1]
    if data.shape[1] == 1:
        assert data[:, 0].size == 1
        return float(data[0, 0])
    output = {}
    for value in np.unique(data[:, 0]):
        output[value] = bruteforce_to_dict(data[data[:, 0] == value, 1:])
    return output

In [3]:
def print_dict(data, level=0):
    space = ' ' * level
    if isinstance(data, float):
        print('{}{}'.format(space, data))
    elif isinstance(data, dict):
        for key, value in sorted(data.items(), key=lambda x: x[0]):
            print('{}{}:'.format(space, key))
            print_dict(value, level + 1)
    else:
        assert False

In [4]:
def get_deepness(data, level=0):
    if isinstance(data, float):
        return level
    return get_deepness(list(data.values())[0], level + 1)

In [5]:
def flatten_dict(data):
    if isinstance(data, float):
        return ([data], )
    result = [[] for _ in range(get_deepness(data) + 1)]
    for key in data:
        tmp = flatten_dict(data[key])
        result[0] += [key] * len(tmp[0])
        for i in range(len(tmp)):
            result[i+1] += tmp[i]
    return result

In [6]:
def draw(plot, norm, data, X_grid, Y_grid, annotate=False):
    y, x, z = data
    min_index = np.argmin(z)
    x_min, y_min, z_min = x[min_index], y[min_index], z[min_index]
    y_text = -1.5 if y_min > 0 else 1.5
    y_text /= 2
    x_text = -2.5 + 2.75
    if annotate:
        plot.annotate('min %2.2f' % z_min, xy=(x_min, y_min), xytext=(x_text, y_text),
                       arrowprops=dict(facecolor='black', arrowstyle='->'))
    Z = griddata(x, y, z, X_grid, Y_grid, interp='linear')
    return plot.pcolormesh(X_grid, Y_grid, Z, cmap=cm.jet_r, norm=norm)

In [7]:
def draw_grid(axes, data, norm, X, Y, z):
    if get_deepness(data) == 2:
        current_data = flatten_dict(data)
        return draw(axes[0], norm, current_data, X, Y, np.allclose(min(current_data[-1]), min(z)))
    for i, (key, value) in enumerate(sorted(data.items(), key=lambda x: x[0])):
        axes_amount = len(axes) // len(data)
        result = draw_grid(axes[axes_amount * i: axes_amount * (i + 1)], value, norm, X, Y, z)
    return result

In [8]:
def draw_topology(data, X, Y, grid_size=None):
    if grid_size is None:
        if get_deepness(data) == 3:
            grid_size = (1, len(data))
        if get_deepness(data) == 4:
            grid_size = (len(data[list(data.keys())[0]]), len(data))
    if get_deepness(data) == 4:
        assert (len(data[list(data.keys())[0]]) - 1) % (grid_size[1] - 1) == 0
        assert (len(data) - 1) % (grid_size[0] - 1) == 0
        steps = ((len(data) - 1) // (grid_size[0] - 1), (len(data[list(data.keys())[0]]) - 1) // (grid_size[1] - 1))
    elif get_deepness(data) == 3:
        assert (len(data) - 1) % (grid_size[1] - 1) == 0
        steps = (len(data) - 1) // (grid_size[1] - 1)
    else:
        assert False, 'Unable to draw plot with {} dimensions'.format(get_deepness(data))

    z = np.unique(flatten_dict(data)[-1])
    norm = colors.Normalize(vmin=z.min(), vmax=z.max())
    fig = plt.figure()
    axes = AxesGrid(fig, 111, nrows_ncols=grid_size,
                    axes_pad=0.3,
                    share_all=True,
                    label_mode="L",
                    cbar_location="right",
                    cbar_mode="single")

    if get_deepness(data) == 4:
        data = {key1: {key2: data[key1][key2]
                       for key2 in list(sorted(data[key1].keys()))[::steps[1]]}
                for key1 in list(sorted(data.keys()))[::steps[0]]}
    elif get_deepness(data) == 3:
        data = {key1: data[key1] for key1 in list(sorted(data.keys()))[::steps]}
    else:
        assert False

    for i, key in enumerate(sorted(data.keys())):
        if get_deepness(data) > 3:
            axes[i  * grid_size[1]].set_ylabel('Fourth = %2.2f' % key)
        else:
            axes[i].set_title('Third = %2.2f' % key)

    if get_deepness(data) > 3:
        for i, key in enumerate(sorted(data[list(data.keys())[0]].keys())):
            axes[i].set_title('Third = %2.2f' % key)

    axes.cbar_axes[0].colorbar(draw_grid(axes, data, norm, X, Y, z))
    plt.show()

In [9]:
def preprocess_raw_data(filename, drop_columns=()):
    assert isinstance(drop_columns, tuple)
    raw_data = np.load(filename)
    if drop_columns:
        data_mask = raw_data[:, drop_columns] == raw_data[:, drop_columns][raw_data[:, -1].argmin()]
        raw_data = np.delete(raw_data[data_mask.all(axis=1)], drop_columns, axis=1)
    assert 3 < raw_data.shape[1] < 6
    X, Y = np.meshgrid(np.linspace(min(raw_data[:, 0]), max(raw_data[:, 0]), 100),
                       np.linspace(min(raw_data[:, 1]), max(raw_data[:, 1]), 100))
    data = raw_data.copy()
    for i in range(raw_data.shape[1] - 1):
        data[:, i] = raw_data[:, raw_data.shape[1] - 2 - i]
    return bruteforce_to_dict(data), X, Y

In [10]:
def process_file(filename, names=(), drop_columns=()):
    draw_topology(*preprocess_raw_data(filename, drop_columns))

In [11]:
process_file('light_scale_sasha.npy', names=('Scale x', 'Scale y', 'Light alpha', 'Scale z'), drop_columns=(0, 1))



In [12]:
process_file('light_scale_sasha.npy', names=('Light x', 'Light y', 'Light alpha', 'Scale z'), drop_columns=(2, 3))



In [13]:
process_file('light_test_004.npy')



In [14]:
process_file('topology.npy')