#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
import numpy as np
from sklearn import manifold
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import argparse

def rand_jitter(arr):
	stdev = arr.max() / 100.
	return arr + np.random.randn(len(arr)) * stdev * 2


def read_file(fname, separator):
	distances = np.genfromtxt(fname, delimiter=separator)
	if np.isnan(distances[0][len(distances[0])-1]):#separator after the last element in row
		distances = np.array([row[:-1] for row in distances])
	return distances


def compute_mds(distance_matrix, dim):
	seed = np.random.RandomState(seed=3)
	mds = manifold.MDS(n_components=int(dim), metric=True, max_iter=3000, eps=1e-9, random_state=seed, dissimilarity="precomputed")
	embed = mds.fit(distance_matrix).embedding_
	return embed


def compute_variances(embed):
	variances = []
	for i in range(len(embed[0])):
		variances.append(np.var(embed[:,i]))
	percent_variances = [sum(variances[:i+1])/sum(variances) for i in range(len(variances))]
	return percent_variances


def plot(coordinates, dimensions, jitter=0, outname=""):
	fig = plt.figure()

	if dimensions < 3:
		ax = fig.add_subplot(111)
	else:
		ax = fig.add_subplot(111, projection='3d')

	add_jitter = lambda tab : rand_jitter(tab) if jitter==1 else tab

	x_dim = len(coordinates[0])
	y_dim = len(coordinates)

	ax.scatter(*[add_jitter(coordinates[:, i]) for i in range(x_dim)], alpha=0.5)

	plt.title('Phenotypes distances')
	plt.tight_layout()
	plt.axis('tight')

	if outname == "":
		plt.show()

	else:
		plt.savefig(outname+".pdf")


def main(filename,dimensions=3, outname="", jitter=0, separator='\t'):
	distances = read_file(filename, separator)
	embed = compute_mds(distances, dimensions)

	variances_perc = compute_variances(embed)
	for i,vc in enumerate(variances_perc):
		print(i+1,"dimension:",vc)

	dimensions = int(dimensions)
	if dimensions == 1:
		embed = np.array([np.insert(e, 0, 0, axis=0) for e in embed])
	
	plot(embed, dimensions)


if __name__ == '__main__':
	parser = argparse.ArgumentParser()
	parser.add_argument('--in', dest='input', required=True, help='input file with dissimilarity matrix')
	parser.add_argument('--out', dest='output', required=False, help='output file name without extension')
	parser.add_argument('--dim', required=False, help='number of dimensions of the new space')
	parser.add_argument('--sep', required=False, help='separator of the source file')
	parser.add_argument('--j', required=False, help='for j=1 random jitter is added to the plot')

	args = parser.parse_args()
	set_value = lambda value, default : default if value == None else value
	main(args.input, set_value(args.dim, 3), set_value(args.output, ""), set_value(args.j, 0), set_value(args.sep, "\t"))
