/* global $, Plotly, d3 */

// eslint-disable-next-line no-use-before-define
var cluster_data = cluster_data || {};

// eslint-disable-next-line no-unused-vars
function createCytoscape(id, data, tissuename, otherNodeSize, width) {
	var color = {
		1: '#ff9d13',
		2: '#cdccca',
		3: '#e41c20',
		4: '#000000',
		5: '#50c8eb',
		6: '#fb0096'
	};
	var textcolor = {
		1: '#000',
		2: '#000',
		3: '#000',
		4: '#fff',
		5: '#000',
		6: '#000'
	};
	if (typeof otherNodeSize === 'undefined') {
		otherNodeSize = 30;
	}

	if (typeof width === 'undefined') {
		width = 650;
	}
	var height = 650;

	var svg = d3.select('#cytoscapeplot' + id)
		.attr('tabindex', 1)
		.append('svg')
		.attr('width', width)
		.attr('height', height);

	var link = svg
		.append('g')
		.attr('class', 'link')
		.selectAll('line');

	var node = svg
		.append('g')
		.attr('class', 'nodecontainer')
		.selectAll('.node');

	var node_converter = [];
	var filtered_nodes = [];
	data.nodes.forEach(function(d) {
		if (d.name != '0') {
			node_converter[d.id] = d;
			filtered_nodes.push(d);
		}
	});
	data.nodes = filtered_nodes;

	var filtered_links = [];
	data.links.forEach(function(d) {
		if (node_converter[d.source] && node_converter[d.target]) {
			d.source = node_converter[d.source];
			d.target = node_converter[d.target];
			filtered_links.push(d);
		}
	});
	data.links = filtered_links;

	var graph = {
		nodes: data.nodes,
		links: data.links
	};

	link = link
		.data(graph.links)
		.enter()
		.append('line')
		.attr('x1', function(d) { return d.source.x; })
		.attr('y1', function(d) { return d.source.y; })
		.attr('x2', function(d) { return d.target.x; })
		.attr('y2', function(d) { return d.target.y; })
		.style('stroke', '#000')
		.style('stroke-width', '1.5px');

	node = node
		.data(graph.nodes)
		.enter()
		.append('g')
		.attr('transform', function(d) { return 'translate(' + d.x + ',' + d.y + ')'; })
		.attr('class', 'node')
		.call(d3.drag()
			.on('drag', function() {
				nudge(d3.event.dx, d3.event.dy);
			}));

	var anchor = node.append('a')
		.attr('xlink:href', function(d) {
			return d.url;
		});

	anchor.append('circle')
		.attr('class', 'circle')
		.attr('r', function(d) {
			if (isNaN(d.name)) {
				if (d.group == 4) {
					return 40;
				}
				return otherNodeSize;
			}
			if (d.name <= 1) {
				return 9;
			}
			if (d.name <= 20) {
				return 9 + Math.sqrt(d.name) * 1.5;
			}
			return Math.log(d.name) * 6;
		})
		.style('fill', function(d) { return color[d.group]; })
		.attr('title', function(d) {
			if (d.group == 5 || d.group == 6) {
				return d.group == 5 ? 'Overrepresented' : 'Underrepresented';
			}
			return '';
		});

	anchor.append('text')
		.each(function (d) {
			d.name = d.name.toString();
			if (d.name === 'endometrium') {
				d.name = 'endo- metrium';
			}
			var arr = d.name.split(' ');
			if (arr !== undefined) {
				var line_diff = 1.15;
				var dy;
				for (var i = 0; i < arr.length; i++) {
					if (i === 0) {
						dy = 0.35 - (arr.length - 1) / 2 * line_diff;
					} else {
						dy = line_diff;
					}
					d3.select(this).append('tspan')
						.text(arr[i])
						.attr('dy', dy.toPrecision(3) + 'em')
						.attr('x', '-0.5')
						.attr('text-anchor', 'middle')
						.attr('class', 'text')
						.style('fill', function(d2) { return textcolor[d2.group]; });
				}
			}
		});

	anchor.on('mouseover', function(d) {
		if (!d.mouseoverselected) {
			node.classed('mouseoverselected', function(p) {
				p.mouseoverselected = d === p;
				return p.mouseoverselected;
			});
		}
		d3.select(this).style('fill', 'transparent');
		link.filter(function(d2) {
			return d2.target.mouseoverselected;
		}).style('stroke', '#3366ff');
		link.filter(function(d2) {
			return d2.source.mouseoverselected;
		}).style('stroke', '#3366ff');
	}).on('mouseout', function(d) {
		link.filter(function(d2) {
			return d2.target.mouseoverselected;
		}).style('stroke', '#000000');
		link.filter(function(d2) {
			return d2.source.mouseoverselected;
		}).style('stroke', '#000000');
		if (d.mouseoverselected) {
			node.classed('mouseoverselected', d.mouseoverselected = false);
		}
	}).on('mousedown', function(d) {
		if (!d.selected) {
			node.classed('selected', function(p) {
				p.selected = d === p;
				return p.selected;
			});
		}
	}).on('mouseup', function(d) {
		if (d.selected) {
			d3.select(this).classed('selected', d.selected = false);
		}
	});

	if (tissuename === 'TS' || tissuename.substr(0, 3) === 'TS_') {
		anchor.attr('transform', 'scale(0.8)');
		anchor.select('circle').attr('transform', 'scale(0.85)');
	}

	function nudge(dx, dy) {
		node.filter(function(d) {
			return d.selected;
		}).attr('transform', function(d) {
			d.x = parseFloat(d.x) + dx;
			d.y = parseFloat(d.y) + dy;
			return 'translate(' + d.x + ',' + d.y + ')';
		});

		link.filter(function(d) { return d.source.selected; })
			.attr('x1', function(d) { return d.source.x; })
			.attr('y1', function(d) { return d.source.y; });

		link.filter(function(d) { return d.target.selected; })
			.attr('x2', function(d) { return d.target.x; })
			.attr('y2', function(d) { return d.target.y; });

		if (d3.event.preventDefault) {
			d3.event.preventDefault();
		} else {
			d3.event.returnValue = false;
		}
	}
}

function createFoldenrichmentPlot(data, id, settings) {
	var defaultColorScale = ['#CCCCFF', '#0000FF'];
	if (typeof settings === 'undefined') settings = {};
	if (typeof settings.colorset !== 'undefined') {
		if (settings.colorset === 'blue') {
			settings.colorscale = defaultColorScale;
		} else if (settings.colorset === 'red') {
			settings.colorscale = ['#FFCCCC', '#FF0000'];
		} else if (settings.colorset === 'Cytoplasm') {
			settings.colorscale = ['#bede8a', '#94c83d'];
		} else if (settings.colorset === 'Nucleus') {
			settings.colorscale = ['#87d3ff', '#017bc0'];
		} else if (settings.colorset === 'Endomembrane system') {
			settings.colorscale = ['#ffaf91', '#f26531'];
		}
	}
	if (typeof settings.colorscale === 'undefined') settings.colorscale = defaultColorScale;
	if (typeof settings.dimension === 'undefined') settings.width = 600;
	if (typeof settings.barheight === 'undefined') settings.barheight = 20;
	if (typeof settings.bgcolor === 'undefined') settings.bgcolor = '#FFFFFF';
	if (typeof settings.maxvalue === 'undefined') settings.maxvalue = 40;
	if (typeof settings.xAxisLabel === 'undefined') settings.xAxisLabel = '';
	if (typeof settings.padding === 'undefined') {
		settings.padding = {
			top: 30, bottom: 0, left: 200, right: 40
		};
	}
	if (typeof settings.xLabelTransform === 'undefined') settings.xLabelTransform = '';
	if (typeof settings.valueLabels === 'undefined') settings.valueLabels = false;
	if (typeof settings.grid === 'undefined') settings.grid = false;
	if (typeof settings.showRows === 'undefined') settings.showRows = false;
	var barHeight = settings.barheight;
	var chartHeight = settings.barheight * data.length;
	var height = chartHeight + settings.padding.top + settings.padding.bottom;
	var chartWidth = settings.width - settings.padding.left - settings.padding.right;
	var svg = d3.select(id)
		.attr('tabindex', 1)
		.append('svg')
		.attr('class', 'chart cluster')
		.attr('width', settings.width)
		.attr('height', height);
	if (settings.bgcolor !== '#FFFFFF') {
		svg.append('rect')
			.attr('class', 'background')
			.attr('width', settings.width)
			.attr('height', height)
			.attr('fill', settings.bgcolor);
	}
	var chart = svg
		.append('g')
		.attr('width', chartWidth)
		.attr('height', chartHeight)
		.attr('transform', 'translate(' + settings.padding.left + ',' + settings.padding.top + ')');

	// Bar color
	var color = d3.scaleLinear()
		.domain([0, settings.maxvalue])
		.range(settings.colorscale);

	// X axis
	var x = d3.scaleLinear()
		.range([0, chartWidth])
		.domain([0, d3.max(data, function(d) { return d.value; })]);
	var xAxis = d3.axisTop().scale(x).tickSizeOuter(0);
	if (settings.grid) xAxis.tickSizeInner(-chartHeight);

	// Y axis
	var y = d3.scaleBand()
		.range([0, chartHeight])
		.domain(data.map(function(d) { return d.name; }));
	var yAxis = d3.axisLeft().scale(y).tickSizeOuter(0);

	chart.append('g')
		.attr('class', 'x axis')
		.call(xAxis);

	chart.selectAll('.x.axis')
		.append('text')
		.attr('class', 'xAxisLabel')
		.attr('y', -20)
		.attr('x', chartWidth / 2)
		.style('text-anchor', 'middle')
		.style('fill', '#000')
		.text(settings.xAxisLabel);

	// The bar's
	var bar = chart.selectAll('rect')
		.data(data)
		.enter().append('g')
		.attr('class', 'bar')
		.attr('transform', function(d, i) { return 'translate(0,' + i * settings.barheight + ')'; });
	// The visual bar
	var link = bar.append('a')
		.attr('xlink:href', function(d) { return d.url; });
	link.append('rect')
		.attr('width', function(d) { return x(d.value); })
		.attr('height', settings.barheight - 1)
		.attr('fill', function(d) { return color(d.value); })
		.attr('y', 0)
		.attr('title', function(d) { return d.value_tooltip; })
		.on('mouseover', function() {
			var r = getHighlightColor($(this).css('fill'));
			$(this).attr('fill-old', $(this).css('fill'));
			d3.select(this).transition().style('fill', 'rgb(' + r[1] + ',' + r[2] + ',' + r[3] + ')');
		})
		.on('mouseout', function() {
			if ($(this).attr('fill-old')) {
				d3.select(this).transition().style('fill', $(this).attr('fill-old'));
			}
		});
	if (settings.valueLabels) {
		bar.append('text')
			.text(function(d) { return d.value; })
			.attr('text-align', 'right')
			.attr('dominant-baseline', 'middle')
			.attr('y', barHeight / 2)
			.attr('x', function(d) { return x(d.value) + 2; });
	}

	chart.append('g')
		.attr('class', 'y axis')
		.attr('width', settings.padding.left - 5)
		.call(yAxis);
	chart.selectAll('.y.axis text').attr('width', settings.padding.left - 5).text(function(d) {
		if (d.length > 31) {
			return d.substring(0, 28) + '...';
		}
		return d;
	});
	adjustClusterPlot(id);
}
function adjustClusterPlot(id) {
	var plot = $(id);
	if (plot.height() < plot.find('svg').height()) {
		$('<a href="#show" style="position:absolute; top:' + (plot.height() - 20) + 'px; right:0px; display:block;">Show full plot</a>').on('click', function() {
			$(this).hide();
			plot.css({ 'max-height': 'none' });
			return false;
		}).appendTo(plot);
	}
}

// eslint-disable-next-line no-unused-vars
function clusterAddPolygonsToLayout(shapes, clusterLayout) {
	let thisLayout = JSON.parse(JSON.stringify(clusterLayout));
	if (shapes) {
		shapes = Object.values(shapes).flat(1);
		thisLayout.shapes = [];
		for (let i in shapes) {
			if (!shapes.hasOwnProperty(i)) {
				continue;
			}
			let path = 'M';
			let first = true;
			for (let z in shapes[i]) {
				if (!shapes[i].hasOwnProperty(z)) {
					continue;
				}
				if (first) {
					first = false;
				} else {
					path += ' L';
				}
				path += `${shapes[i][z].x},${shapes[i][z].y}`;
			}
			path += ' Z';
			thisLayout.shapes.push({
				type: 'path',
				path: path,
				line: {
					color: 'rgb(0, 0, 0)',
					width: 1,
				},
			});
		}
	}
	return thisLayout;
}

function attemptPlotlyFullscreen(data) {
	const element = document.getElementById(data.id);
	if (!document.fullscreenElement) {
		element.dataset.originalWidth = element.clientWidth;
		element.dataset.originalHeight = element.clientHeight;
	}
	let p;
	if (element.requestFullscreen) {
		p = element.requestFullscreen();
	} else if (element.mozRequestFullScreen) {
		p = element.mozRequestFullScreen();
	} else if (element.webkitRequestFullscreen) {
		p = element.webkitRequestFullscreen();
	} else if (element.msRequestFullscreen) {
		p = element.msRequestFullscreen();
	} else {
		throw new Error('Cannot open fullscreen');
	}
	if (p) {
		p.then(function() {
			document.addEventListener('fullscreenchange', () => {
				if (document.fullscreenElement) {
					Plotly.relayout(element, {
						width: element.clientWidth,
						height: element.clientHeight
					});
				} else {
					Plotly.relayout(element, {
						width: element.dataset.originalWidth,
						height: element.dataset.originalHeight
					});
				}
			});
		});
	}
}

function attemptPlotlyFullscreenSubcell(data) {
	const plot = document.getElementById(data.id);
	var element = document.getElementById('fullScreenSubcell');
	if (document.fullscreenElement === element) {
		if (document.exitFullscreen) {
			document.exitFullscreen();
		} else if (document.webkitExitFullscreen) { /* Safari */
			document.webkitExitFullscreen();
		} else if (document.msExitFullscreen) { /* IE11 */
			document.msExitFullscreen();
		}
		return;
	}
	if (!document.fullscreenElement) {
		plot.parentElement.dataset.originalWidth = plot.clientWidth;
		plot.parentElement.dataset.originalHeight = plot.clientHeight;
		if ($('#filterGenes .fieldsForm').is(':visible')) {
			$('#filterGenes #fieldsLink').trigger('click');
		}
	}

	if (element.requestFullscreen) {
		element.requestFullscreen();
	} else if (element.mozRequestFullScreen) {
		element.mozRequestFullScreen();
	} else if (element.webkitRequestFullscreen) {
		element.webkitRequestFullscreen();
	} else if (element.msRequestFullscreen) {
		element.msRequestFullscreen();
	} else {
		throw new Error('Cannot open fullscreen');
	}
}

var fullscreenButton = {
	name: 'Fullscreen',
	icon: {
		'width': 1000,
		'height': 1000,
		'path': 'M 1000,250 850,100 600,350 500,250 750,0 600,-150 v 0 h 400 z M 500,450 250,700 400,850 v 0 H 0 v -400 L 150,600 400,350 z',
		'transform': 'matrix(1 0 0 1 0 150)'
	},
	direction: 'up',
	click: attemptPlotlyFullscreen
};

var fullscreenButtonSubcell = {
	name: 'Fullscreen',
	icon: {
		'width': 1000,
		'height': 1000,
		'path': 'M 1000,250 850,100 600,350 500,250 750,0 600,-150 v 0 h 400 z M 500,450 250,700 400,850 v 0 H 0 v -400 L 150,600 400,350 z',
		'transform': 'matrix(1 0 0 1 0 150)'
	},
	direction: 'up',
	click: attemptPlotlyFullscreenSubcell
};

let plotlyConfigurations = {
	genes: {
		responsive: true,
		modeBarButtonsToRemove: [
			'select2d',
			'lasso2d',
			'toggleSpikelines',
			'hoverClosestPie',
			'toggleHover',
			'hoverCompareCartesian',
			'hoverClosestCartesian',
			'resetScale2d'
		],
		displaylogo: false,
		scrollZoom: true,
		modeBarButtonsToAdd: [
			fullscreenButton,
		],
	},
	clusters: {
		displayModeBar: false,
	},
	clusteroutlines: {
		displayModeBar: false,
	},
	cell2d: {
		responsive: true,
		modeBarButtonsToRemove: [
			'select2d',
			'lasso2d',
			'toggleSpikelines',
			'hoverClosestPie',
			'toggleHover',
			'hoverCompareCartesian',
			'hoverClosestCartesian',
			'resetScale2d'
		],
		displaylogo: false,
		scrollZoom: true,
		modeBarButtonsToAdd: [
			fullscreenButtonSubcell,
		],
	},
	cell3d: {
		responsive: true,
		displaylogo: false,
		modeBarButtonsToAdd: [
			fullscreenButtonSubcell,
		],
	}
};

let clusterLayout = {
	xaxis: {
		showgrid: false,
		zeroline: false,
		ticks: '',
		showticklabels: false,
		showline: true,
		title: {
			text: 'UMAP1'
		},
	},
	yaxis: {
		showgrid: false,
		zeroline: false,
		ticks: '',
		showticklabels: false,
		showline: true,
		scaleanchor: 'x',
		scaleratio: 1,
		title: {
			text: 'UMAP2'
		},
	},
	showlegend: true,
	legend: {
		itemsizing: 'constant'
	},
	font: {
		size: 10,
		family: 'sans-serif'
	},
	title: {
		font: {
			size: 17
		},
		text: '',
	},
	hoverinfo: '',
	hovermode: 'closest',
	height: 500,
	margin: {
		l: 20,
		r: 20,
		b: 20,
		t: 20,
		pad: 4
	},
	dragmode: 'pan',
};

function clusterCreateLayout(polygons, settings) {
	let thisLayout = clusterLayout;
	if (settings.plot_type == 'genes' && polygons) {
		thisLayout = clusterAddPolygonsToLayout(polygons, clusterLayout);
	}
	if (settings.plot_type == 'clusters' || settings.plot_type == 'clusteroutlines') {
		thisLayout.xaxis.fixedrange = true;
		thisLayout.yaxis.fixedrange = true;
		thisLayout.height = settings.height? settings.height : 450;
		if (settings.width) thisLayout.width = settings.width;
	}
	if (settings.title) {
		thisLayout.title.text = settings.title;
		thisLayout.margin.t = 50;
	}
	if (settings.plot_type == 'clusteroutlines') {
		thisLayout.xaxis.visible = false;
		thisLayout.yaxis.visible = false;
	}
	if (typeof settings.showlegend !== 'undefined') {
		thisLayout.showlegend = settings.showlegend;
	}
	if (typeof settings.showaxis !== 'undefined') {
		thisLayout.xaxis.visible = settings.showaxis;
		thisLayout.yaxis.visible = settings.showaxis;
		//thisLayout.margin.t = 5;
		thisLayout.margin.b = 5;
		thisLayout.margin.r = 5;
		thisLayout.margin.l = 5;
	}
	return thisLayout;
}

// eslint-disable-next-line no-unused-vars
function plotUMAP(elem, data_in, settings) {
	let data = data_in.scatter.data;
	let annotations = data_in.annotations;
	let d;
	if (settings.plot_type == 'genes') {
		d = data.points;
	} else if (settings.plot_type == 'clusters' || settings.plot_type == 'clusteroutlines') {
		d = data;
	}
	var config = plotlyConfigurations[settings.plot_type];
	var thisLayout = clusterCreateLayout(data.polygons, settings);
	if (annotations.length) {
		thisLayout.annotations = annotations;
	}
	var plot = Plotly.newPlot(elem, d, thisLayout, config);
	if (settings.plot_type == 'clusters') {
		document.getElementById(elem).on('plotly_click', function(eventData) {
			var clusterNumber = eventData.points[0].data.cluster_no;
			window.location = settings.clickURL + '#cluster' + clusterNumber;
			return false;
		});
	}
	return plot;
}

function getClusterPlotSingleColor(plotID) {
	var elem = document.getElementById(plotID);
	if (elem) {
		return elem.getAttribute('data-singlecolor');
	}
	return undefined;
}

// eslint-disable-next-line no-unused-vars
function highlightClusterRow(tableID, clusterNumber) {
	var elem = $('#' + tableID);
	elem.find('tr.selected').removeClass('selected');
	elem.find('tr[data-clusterno="' + clusterNumber + '"]').addClass('selected');
}

// eslint-disable-next-line no-unused-vars
function updateUMAPPlot(plotID, clusterNumber, title, filters, colorType) {
	var plot_data = JSON.parse(JSON.stringify(cluster_data[plotID].scatter.data));
	var points = [];
	var polygons = {};
	if (filters && typeof filters.genes !== "undefined") {
		var selectedPoints = {
			x: [],
			y: [],
			marker: {
				color: [],
			},
			text: [],
			customdata: [],
		};
		var otherPoints = {
			x: [],
			y: [],
			text: [],
			marker: {
				color: '#444444',
			},
			customdata: [],
		};
		// Pull the genes from the different subplots and divide the selected genes and the other genes into
		// two different subplots putting the selected genes last so they are rendered last
		var clusterKeys = Object.keys(plot_data.points);
		for (var key in clusterKeys) {
			var clusterPoints = plot_data.points[key];
			for (var i = 0; i < clusterPoints.x.length; i++) {
				if (filters.genes.indexOf(clusterPoints.ensg[i]) !== -1) {
					selectedPoints.x.push(clusterPoints.x[i]);
					selectedPoints.y.push(clusterPoints.y[i]);
					selectedPoints.marker.color.push(clusterPoints.marker.color[0]);
					selectedPoints.text.push(clusterPoints.text[i]);
					selectedPoints.customdata.push(clusterPoints.customdata);
				} else {
					otherPoints.x.push(clusterPoints.x[i]);
					otherPoints.y.push(clusterPoints.y[i]);
					otherPoints.text.push(clusterPoints.text[i]);
					otherPoints.customdata.push(clusterPoints.customdata);
				}
			}
		}
		if (colorType === 'single') {
			selectedPoints.marker.color = getClusterPlotSingleColor(plotID);
		}
		otherPoints.mode = selectedPoints.mode = plot_data.points[0].mode;
		otherPoints.type = selectedPoints.type = plot_data.points[0].type;
		otherPoints.marker.size = selectedPoints.marker.size = plot_data.points[0].marker.size;
		selectedPoints.hovertemplate = plot_data.points[0].hovertemplate.replace(/data.customdata/g, 'customdata');
		otherPoints.hoverinfo = 'skip';
		otherPoints.hovertemplate = '';
		points.push(otherPoints);
		points.push(selectedPoints);
	} else if (clusterNumber) {
		var keys = Object.keys(plot_data.points);
		var highlightPoints;
		var highlightIdx;
		for (var idx in keys) {
			if (plot_data.points[idx].customdata.cluster_no === clusterNumber) {
				// Points are plotted in order of the data so push the highlighted cluster to the end
				// to ensure it is rendered last
				highlightPoints = plot_data.points[idx];
				highlightIdx = idx;
			} else {
				var point = plot_data.points[idx];
				point.marker.color = '#cccccc';
				point.hoverinfo = 'skip';
				point.hovertemplate = '';
				points.push(point);
			}
		}
		if (highlightPoints) {
			points.push(highlightPoints);
		}
		if (highlightIdx) {
			// Remove the highlighted cluster in the original array position so we dont plot it twice
			plot_data.points.splice(highlightIdx, 1);
		}

		if (plot_data.polygons) {
			if (typeof plot_data.polygons[clusterNumber] !== 'undefined') {
				polygons[clusterNumber] = plot_data.polygons[clusterNumber];
			}
		}
	} else {
		points = plot_data.points;
		polygons = plot_data.polygons;
	}

	var elem = document.getElementById(plotID);
	if (!title) {
		// eslint-disable-next-line no-underscore-dangle
		title = elem._fullLayout.title.text;
	}
	// eslint-disable-next-line no-underscore-dangle
	var showLegend = elem._fullLayout.showlegend;
	var showAxis = elem._fullLayout.showaxis;
	var config = plotlyConfigurations[elem.dataset.config];
	var layout = clusterCreateLayout(polygons, {'plot_type':'genes', 'showlegend':showLegend, 'showaxis':showAxis, 'title':title});
	Plotly.newPlot(plotID, points, layout, config);
}

// eslint-disable-next-line no-unused-vars
function assignColors(locations, colorMap) {
	return locations.map((code) => {
		if (colorMap.hasOwnProperty(code)) {
			return colorMap[code];
		}
		return colorMap.Multilocalizing;
	});
}

function mapSubcellCustomData(customdata) {
	var cdKeys = Object.keys(customdata);
	return customdata[cdKeys[0]].map(function(val, idx) {
		var d = {};
		// eslint-disable-next-line guard-for-in
		for (var k of cdKeys) {
			if (k === 'gene') {
				continue;
			}
			if (k === 'ensg') {
				var genes = customdata[k][idx].split(',');
				var ensgIDs = [];
				var geneIDs = [];
				for (var i = 0; i < genes.length; i++) {
					var g = genes[i].split(':');
					ensgIDs.push(g[0]);
					geneIDs.push(g[1]);
				}
				d.ensg = ensgIDs;
				d.gene = geneIDs;
			} else {
				d[k] = customdata[k][idx];
			}
		}
		return d;
	});
}

function showImageDetails(show) {
	if (show) {
		document.getElementById('imageDetails').style.display = 'block';
	} else {
		document.getElementById('imageDetails').style.display = 'none';
	}
}

function updateSubcellPlotCount(imageCount, geneCount) {
	$('#imageCount').html(imageCount);
	$('#geneCount').html(geneCount);
}

function getSubcellMarkerSize() {
	return document.querySelector('.markerSize').value;
}

function addPlotActions(plotID) {
	var plot = document.getElementById(plotID);
	plot.on('plotly_click', async function(data) {
		var detailsDiv = document.getElementById('imageData');
		var cd = data.points[0].customdata;
		detailsDiv.querySelector('.antibody .data').textContent = cd.antibody;
		detailsDiv.querySelector('.cellline .data').textContent = cd.cell_line;

		var geneElement = detailsDiv.querySelector('.genes .data');
		geneElement.innerHTML = '';
		var genes = cd.ensg;
		for (var i = 0; i < genes.length; i++) {
			var href = '/' + genes[i] + '-' + cd.gene[i] + '/subcellular';
			$(geneElement).append($('<p><a href="' + href + '">' + cd.gene[i] + '</a></p>'));
		}
		detailsDiv.querySelector('.genes .plural').style.display = genes.length > 1 ? '' : 'none';

		var locations = cd.locations.split(',');
		detailsDiv.querySelector('.location .data').innerHTML = locations.map(function(val) {
			return '<p>' + val + '</p>';
		}).join('');
		detailsDiv.querySelector('.location .plural').style.display = locations.length > 1 ? '' : 'none';

		// Image
		detailsDiv.querySelector('.image a').href = '/' + genes[0] + '-' + cd.gene[0] + '/subcellular#image_' + cd.img.split('/')[2];
		detailsDiv.querySelector('.image img').src = 'https://images.proteinatlas.org' + cd.img + '_blue_red_green_medium.jpg';
		showImageDetails(true);
	});
	var dragLayer = document.getElementsByClassName('nsewdrag')[0];
	plot.on('plotly_hover', function() {
		dragLayer.style.cursor = 'pointer';
	});
	plot.on('plotly_unhover', function() {
		dragLayer.style.cursor = '';
	});
}

function subcellPlotFilterHandler(event) {
	var id = event.target.id;
	// eslint-disable-next-line no-use-before-define
	filterClusterPlot(id, geneFilters);
}

// eslint-disable-next-line no-unused-vars
function subcell2DPlotConfig(id, dataIn) {
	if (!cluster_data.hasOwnProperty(id)) {
		var customdata = mapSubcellCustomData(dataIn.customdata);
		// eslint-disable-next-line no-undef
		var colors = assignColors(dataIn.customdata.locations, subcellColorMap);
		cluster_data[id] = {
			data: {
				x: dataIn.x,
				y: dataIn.y,
				colors: colors,
				customdata: customdata
			},
			trace: {
				x: [],
				y: [],
				type: 'scattergl',
				mode: 'markers',
				marker: {
					size: 2,
					// eslint-disable-next-line no-undef
					color: [],
				},
				hovertemplate: '%{customdata.gene}(%{customdata.cell_line}): %{customdata.locations}'
					+ '<extra></extra>',
				customdata: [],
			},
			layout: {
				hovermode: 'closest',
				xaxis: {
					showticklabels: false,
					nticks: 10,
					zeroline: false,
					showgrid: false,
					ticks: '',
					showline: true,
					title: {
						text: 'UMAP1'
					},
				},
				yaxis: {
					showticklabels: false,
					nticks: 10,
					zeroline: false,
					showgrid: false,
					ticks: '',
					showline: true,
					scaleanchor: 'x',
					scaleratio: 1,
					title: {
						text: 'UMAP2'
					},
				},
				margin: {
					l: 20,
					r: 5,
					t: 30,
					b: 20
				},
			},
			config: plotlyConfigurations.cell2d
		};
	}
	cluster_data[id].trace.marker.size = getSubcellMarkerSize();
	var trace = cluster_data[id].trace;
	trace.x = cluster_data[id].data.x;
	trace.y = cluster_data[id].data.y;
	trace.marker.color = cluster_data[id].data.colors;
	trace.customdata = cluster_data[id].data.customdata;
	var data = [
		trace,
	];
	var layout = JSON.parse(JSON.stringify(cluster_data[id].layout));
	var config = cluster_data[id].config;
	return {data: data, layout: layout, config: config};
}

function subcell2DPlotRender(id, dataIn, options) {
	let d = subcell2DPlotConfig(id, dataIn);
	var elem = document.getElementById(id);
	if (typeof options.width !== 'undefined') {
		d.layout.width = options.width;
		d.layout.height = options.height;
		elem.style.width = options.width + 'px';
		elem.style.height = options.height + 'px';
	}
	var pr = Plotly.newPlot(id, d.data, d.layout, d.config);
	pr.then(function() {
		if (typeof options.width === 'undefined') {
			elem.style.width = elem.clientWidth + 'px';
			elem.style.height = elem.clientHeight + 'px';
		}
		addPlotActions(id);
		$('#' + id).trigger('plot_filter');
	});
	return pr;
}

function loadSubcell2DPlot(id, options) {
	$('#' + id).html('<div class="loading"><img alt="loading" src="/images_static/loading.gif" class="loading"></div>');
	$.get({
		url: '/subcell/umap_data.php?data_name=subcell_umap_2d',
	}).done(function(data) {
		$('#' + id).on('plot_filter', subcellPlotFilterHandler);
		$('#filterGenes').on('change', function() {
			$('#' + id).trigger('plot_filter');
		});
		var pr = subcell2DPlotRender(id, data, options);
		pr.then(function() {
			$('#' + id + ' div.loading').remove();
		});
	});
}

// eslint-disable-next-line no-unused-vars
function subcell3DPlot(id, dataIn, options) {
	if (!cluster_data.hasOwnProperty(id)) {
		var customdata = mapSubcellCustomData(dataIn.customdata);
		// eslint-disable-next-line no-undef
		var colors = assignColors(dataIn.customdata.locations, subcellColorMap);
		cluster_data[id] = {
			data: {
				x: dataIn.x,
				y: dataIn.y,
				z: dataIn.z,
				colors: colors,
				customdata: customdata
			},
			trace: {
				x: [],
				y: [],
				z: [],
				type: 'scatter3d',
				mode: 'markers',
				marker: {
					size: 2,
					// eslint-disable-next-line no-undef
					color: [],
				},
				hovertemplate: '%{customdata.gene}(%{customdata.cell_line}): %{customdata.locations}'
					+ '<extra></extra>',
				customdata: [],
			},
			layout: {
				hovermode: 'closest',
				xaxis: {
					showticklabels: false,
					nticks: 10,
					zeroline: false,
					showgrid: false,
					ticks: '',
					showline: true,
					title: {
						text: 'UMAP1'
					},
				},
				yaxis: {
					showticklabels: false,
					nticks: 10,
					zeroline: false,
					showgrid: false,
					ticks: '',
					showline: true,
					scaleanchor: 'x',
					scaleratio: 1,
					title: {
						text: 'UMAP2'
					},
				},
				margin: {
					l: 20,
					r: 5,
					t: 30,
					b: 20
				},
			},
			config: plotlyConfigurations.cell3d
		};
	}

	cluster_data[id].trace.marker.size = getSubcellMarkerSize();
	var trace = cluster_data[id].trace;
	trace.x = cluster_data[id].data.x;
	trace.y = cluster_data[id].data.y;
	trace.z = cluster_data[id].data.z;
	trace.marker.color = cluster_data[id].data.colors;
	trace.customdata = cluster_data[id].data.customdata;
	var data = [
		trace,
	];
	var layout = JSON.parse(JSON.stringify(cluster_data[id].layout));
	var elem = document.getElementById(id);
	if (typeof options.width !== 'undefined') {
		layout.width = options.width;
		layout.height = options.height;
		elem.style.width = options.width + 'px';
		elem.style.height = options.height + 'px';
	}
	var config = cluster_data[id].config;
	var pr = Plotly.newPlot(id, data, layout, config);
	pr.then(function() {
		if (typeof options.width === 'undefined') {
			elem.style.width = elem.clientWidth + 'px';
			elem.style.height = elem.clientHeight + 'px';
		}
		addPlotActions(id);
		$('#' + id).trigger('plot_filter');
	});
	return pr;
}

function loadSubcell3DPlot(id, options) {
	$('#' + id).html('<div class="loading"><img alt="loading" src="/images_static/loading.gif" class="loading"></div>');
	$.get({
		url: '/subcell/umap_data.php?data_name=subcell_umap_3d',
	}).done(function(data) {
		$('#' + id).on('plot_filter', subcellPlotFilterHandler);
		var pr = subcell3DPlot(id, data, options);
		pr.then(function() {
			$('#' + id + ' div.loading').remove();
		});
	});
}

// eslint-disable-next-line no-unused-vars
function toggleClusterPlot(id) {
	$('#clusterPlots .clusterPlot').removeClass('active');
	$('#' + id).css('display', 'block').addClass('active');
	var current = $('.clusterPlot:not(#' + id + ')');
	var options = {
		width: undefined,
		height: undefined,
	};
	try {
		options.width = current.get(0).clientWidth;
		if (options.width === 0) {
			options.width = undefined;
		} else {
			options.height = current.get(0).clientHeight;
		}
		// eslint-disable-next-line no-empty
	} catch (e) {
	}
	$('.clusterPlot:not(#' + id + ')').css('display', 'none');
	if (!document.getElementById(id).classList.contains('js-plotly-plot')) {
		if (id === 'cellClusterPlot3D') {
			loadSubcell3DPlot(id, options);
		} else {
			loadSubcell2DPlot(id, options);
		}
	} else {
		$('#' + id).trigger('plot_filter');
	}
}

function getSubcellGeneFilterFunc(genes) {
	var filterFunc;
	if (typeof genes === 'undefined') {
		filterFunc = function () {
			return true;
		};
	} else {
		filterFunc = function (val, idx, that) {
			var ensgIDs = that.customdata[idx].ensg;
			if (ensgIDs.length === 1) {
				return genes.indexOf(ensgIDs[0]) !== -1;
			}
			for (var i = 0; i < ensgIDs.length; i++) {
				if (genes.indexOf(ensgIDs[i]) !== -1) {
					return true;
				}
			}
			return false;
		};
	}
	return filterFunc;
}

// eslint-disable-next-line no-unused-vars
function filterClusterPlot(id, filters) {
	var dataTemp = cluster_data[id].trace;
	if (typeof filters.location === 'undefined' && typeof filters.genes === 'undefined') {
		// Empty filter
		dataTemp.x = cluster_data[id].data.x;
		dataTemp.y = cluster_data[id].data.y;
		if (cluster_data[id].data.hasOwnProperty('z')) {
			dataTemp.z = cluster_data[id].data.z;
		}
		dataTemp.marker.color = cluster_data[id].data.colors;
		dataTemp.customdata = cluster_data[id].data.customdata;
	} else {
		// Non-empty filter
		var f2 = {};
		var filterFunc = (function () {
			var locFilter = getSubcellLocationFilterFunc(filters.location);
			var geneFilter = getSubcellGeneFilterFunc(filters.genes);
			return function (val, idx) {
				// noinspection JSCheckFunctionSignatures
				if (locFilter(val, idx, this) && geneFilter(val, idx, this)) {
					f2[idx] = 1;
					return true;
				}
				return false;
			};
		}());
		var filterFunc2 = function (val, idx) {
			return f2.hasOwnProperty(idx);
		};
		dataTemp.x = cluster_data[id].data.x.filter(filterFunc, cluster_data[id].data);
		dataTemp.y = cluster_data[id].data.y.filter(filterFunc2);
		if (cluster_data[id].data.hasOwnProperty('z')) {
			dataTemp.z = cluster_data[id].data.z.filter(filterFunc2);
		}
		dataTemp.marker.color = cluster_data[id].data.colors.filter(filterFunc2);
		dataTemp.customdata = cluster_data[id].data.customdata.filter(filterFunc2);
	}
	dataTemp.marker.size = getSubcellMarkerSize();
	var data = [
		dataTemp,
	];
	var imageCount = dataTemp.x.length;
	var genes = {};
	dataTemp.customdata.forEach(function(val) {
		for (var i = 0; i < val.ensg.length; i++) {
			genes[val.ensg[i]] = 1;
		}
	});
	var geneCount = Object.keys(genes).length;
	var layout = cluster_data[id].layout;
	var config = cluster_data[id].config;
	var pr = Plotly.react(id, data, layout, config);
	pr.then(function() {
		showImageDetails(false);
		updateSubcellPlotCount(imageCount, geneCount);
	});
}

function getSubcellLocationFilterFunc(names) {
	var filterFunc;
	if (typeof names !== "undefined" && names.length) {
		filterFunc = function(val, idx, that) {
			for (var i = 0; i < names.length; i++) {
				var name = names[i];
				var regex = new RegExp('(^|, *)' + name + '(, *|$)');
				if (name === 'Multilocalizing') {
					if (that.customdata[idx].locations.includes(',')) {
						return true;
					}
				} else if (that.customdata[idx].locations.match(regex)) {
					return true;
				}
			}
			return false;
		};
	} else {
		filterFunc = function () {
			return true;
		};
	}
	return filterFunc;
}

function getSubcellActivePlotID() {
	return $('#clusterPlots .clusterPlot.active').attr('id');
}

$(function() {
	$('body').on('click', '.show_text > div.text_toggle span', function() {
		var body = $(this).closest('.show_text');
		if (body.hasClass('show')) {
			if (window.pageYOffset + 110 > body.offset().top) {
				$(document).scrollTop(body.offset().top - 110);
			}
		}
		body.toggleClass('show');
	});
	// remove tooltip from atlasImage on single nuclei brain
	$('.learnbody[markdown_name^="/humanproteome/single cell/single nuclei brain/"] .atlasImage span a').attr("title","");
	
	var markerSize = $('#cellUMAP .markerSize');
	markerSize.selectmenu({
		width: 130,
		appendTo: '#plotMenu',
		position: {
			collision: 'flip',
		},
	});
	markerSize.on('selectmenuchange', function() {
		$(this).trigger('change');
	}).on('change', function() {
		var size = $(this).val();
		var id = getSubcellActivePlotID();
		Plotly.restyle(id, { 'marker.size': size });
	});

	document.addEventListener('fullscreenchange', () => {
		var plots;
		var i;
		var element = document.getElementById('fullScreenSubcell');
		if (!element) {
			return;
		}
		if (document.fullscreenElement) {
			element.querySelector('.left.legend').appendChild(document.getElementById('locationLegend'));
			element.querySelector('.middle .plot').appendChild(document.getElementById('plotPlacement'));
			element.querySelector('.right.details').appendChild(document.getElementById('imageDetails'));
			element.querySelector('.middle .search').appendChild(document.getElementById('filterGenes'));
			element.style.display = null;
			var plotElem = element.querySelector('#fullScreenSubcell .plotSize');
			plots = document.querySelectorAll('.plot .clusterPlot.js-plotly-plot');
			var maxHeightSearch = 125;
			if (!element.querySelector('.middle .search')) {
				maxHeightSearch = 0;
			}
			var elemHeight = plotElem.clientHeight - document.querySelector('.middle #plotMenu').clientHeight - maxHeightSearch;
			var size = Math.max(plotElem.clientWidth, elemHeight);
			for (i = 0; i < plots.length; i++) {
				plots[i].style.width = size + 'px';
				plots[i].style.height = size + 'px';
				Plotly.relayout(plots[i], {
					width: size,
					height: size,
				});
			}
		} else {
			// Exiting fullscreen
			// Revert all elements to their previous position
			document.getElementById('locationLegendPlacement').appendChild(document.getElementById('locationLegend'));
			document.getElementById('plotDiv').prepend(document.getElementById('plotPlacement'));
			document.getElementById('rightDetails').appendChild(document.getElementById('imageDetails'));
			document.getElementById('filterPlacement').appendChild(document.getElementById('filterGenes'));
			element.style.display = 'none';
			plots = document.querySelectorAll('.clusterPlot.js-plotly-plot');
			for (i = 0; i < plots.length; i++) {
				plots[i].style.width = plots[i].parentElement.dataset.originalWidth + 'px';
				plots[i].style.height = plots[i].parentElement.dataset.originalHeight + 'px';
				Plotly.relayout(plots[i], {
					width: plots[i].parentElement.dataset.originalWidth,
					height: plots[i].parentElement.dataset.originalHeight
				});
			}
		}
	});
});

$.fn.cellinePathway = function(data, inSettings) {
    var plot = {};
    var extraDefaults = {
        yLabels: '',
        yTickFormat: '',
        minY: 0,
        dimension: {w: 850, h: 300},
        padding: {t: 20, r: 20, b: 85, l: 50},
        bgColor: '',
        barWidth: 11,
        xLabelsHide: false,
        extendedTooltip: false
    };
    var settings = addDefaultPlotSettings(inSettings, extraDefaults);
    plot.settings = settings;
    // Inner dimension
    var width = plot.width = settings.dimension.w - settings.padding.l - settings.padding.r; // inner width
    var height = plot.height = settings.dimension.h - settings.padding.t - settings.padding.b; // inner height

    var xScale = plot.x = d3.scaleBand()
        .range([0, width])
        .domain(data.map(function(d) { return d.label; }));
    var xAxis = d3.axisBottom(xScale)
        .tickSizeOuter(0)
        .tickSize(0);

    if (settings.xLabelsHide) {
        xAxis
            .tickFormat('')
            .tickSize(0);
    }
    var yScale;
    var yMin, yMax, yAxis;
    if (settings.yLabels) {
        yMin = plot.yMin = d3.min(d3.keys(settings.yLabels));
        yMax = plot.yMax = d3.max(d3.keys(settings.yLabels));
        yScale = plot.y = d3.scaleLinear()
            .range([height, 0])
            .domain([yMin, yMax]);
        yAxis = d3.axisLeft(yScale)
            //.tickFormat(function(d) { return settings.yLabels[d]; })
        //.tickValues(d3.keys(settings.yLabels));
    }
    else {
        yMin = plot.yMin = Math.min(d3.min(data, function(d) { return parseFloat(d.value); }), settings.minY);
        yMax = plot.yMax = Math.max(d3.max(data, function(d) { return parseFloat(d.value); }), settings.minY);
        yScale = plot.y = d3.scaleLinear()
            .range([height, 0])
            .domain([yMin, yMax])
            .nice(5);
        yAxis = d3.axisLeft(yScale)
            .ticks(5);
        if (settings.yTickSize != undefined) {
            yAxis.tickSize(settings.yTickSize);
        }
        if (settings.yTickFormat) {
            yAxis.tickFormat(d3.format(settings.yTickFormat));
        }
    }
    var vis = plot.vis = d3.select($(this).get(0))
        .append("svg")
        .attr("class", "barchart")
        .attr("width", width + settings.padding.l + settings.padding.r)
        .attr("height", height + settings.padding.t + settings.padding.b)
        .append("g")
        .attr("transform", "translate(" + settings.padding.l + "," + settings.padding.t + ")")
        .attr("width", width)
        .attr("height", height);

    $(this).on('click', '[url]', function() {
        document.location.href = $(this).attr('url');
    });

    if (settings.bgColor) {
        vis.append("rect")
            .attr("class", "chart_field")
            .attr("width", width)
            .attr("height", height+4)
            .attr("transform", "translate(0,-4)")
            .style("fill", settings.bgColor);
    }

    var bar_g = vis.selectAll(".bar_g")
        .data(data)
        .enter()
        .append("g")
        .attr("class", function(d) { return d.class? "bar_g "+d.class : "bar_g"; })
        .attr("transform", function(d) { return 'translate('+xScale(d.label)+', 0)'; })
        .attr("title", function(d) { return d.tooltip; });

    var link = bar_g.append("a")
        .each(function(d) { if (d.url) d3.select(this).attr("xlink:href", d.url); });

    if (settings.extendedTooltip) {
        var bar_transp = link.append("rect")
            .attr("class","bartrans")
            .attr("y", 0)
            .attr("x", function(d) { return xScale.bandwidth()/2 - settings.barWidth/2 ; })
            .attr("width", settings.barWidth)
            .attr("height", height)
            .style("fill", "transparent");
    }
    var bar_line = link.append("line")
        .attr("class","bar")
        .style("stroke", "grey")
        .style("stroke-width", 0.5)
        .attr("y1", function(d) { return yScale(0); })
        .attr("x1", function(d) { return xScale.bandwidth()/2 ; })
        .attr("y2", function(d) { return yScale(d.value);})
        .attr("x2", function(d) { return xScale.bandwidth()/2 ; })
    var bar_circle = link.append("circle")
        .attr("class", "bar")
        //.attr("transform", "translate(0,0)")
        .attr("cy", function(d) { return yScale(d.value); })
        .attr("cx", function(d) { return xScale.bandwidth()/2 ; })
        .attr("r", function(d) { if(d.group == 'Significant') {return 4} else {return 2}})
        //.style("stoke","1px solid black")
        .style("stroke", "grey")
        //.attr("width", settings.barWidth)
        //.attr("height", function(d) { return (d.na == 1)?height:(height-yScale(d.value));})
        .style("fill", function(d){
            if (d.na==1) {
                return "#FAFAFA";
            } else if (typeof d.color_group!='undefined') {
                return colorbrewer[d.color_group[0]][d.color_group[1]][d.color_group[2]];
            } else {
                if(d.group == 'Significant') {
                    if (d.value > 0) {
                        return 'red';
                    } else {
                        return '#1560BD';
                    }
                } else {
                    if (d.value > 0) {
                        return '#FFCCCB';
                    } else {
                        return 'lightblue';
                    }
                }
            }
        });

    var bar_text = bar_g.filter(function(d){ return d.na == 1; })
        .append("text")
        .attr("class", "na_text")
        .style("text-anchor", "middle")
        .attr("y", settings.barWidth/2+6)
        .attr("x", -height/2)
        .text("N/A");

    if (settings.valueLabels) {
        link.append("text")
            .attr("class", "valueLabel")
            .style("text-anchor", "middle")
            .attr("x", function(d, i) { return xScale.bandwidth()/2; })
            .attr("y", function(d) { return (d.na == 1)?0:yScale(d.value)-2; })
            .text(function(d) { return (d.na == 1)?'':d.value; });
    }

    vis.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + yScale(0) + ")")
        .call(xAxis)
        .selectAll(".tick text")
        .attr("class", "barchartlabel")
        //.style("text-anchor", function(d,i) {if(data[i].value<0) {console.log(d);return "start"} else {console.log(d);return "end"}})
        .attr("transform","rotate(-90)")

        .each(function(d, i) {
            if (data[i].tooltip) {
                var yd = 0;
                if (data[i].value < 0) {
                    var xd = 4;
                    var anchor = "start";
                } else {
                    xd = -4;
                    anchor = "end";
                }
                d3.select(this).attr('title', data[i].tooltip)
                    .attr("y", -4)
                    .attr("x", xd)
                    .style("text-anchor", anchor);
            }
            if (data[i].url) {
                d3.select(this).attr('url', data[i].url).style('cursor', 'pointer');
            }
        });

    // x axis label
    vis.selectAll(".x.axis")
        .append("text")
        .attr("y", 200)
        .attr("x", width/2)
        .text(settings.xAxisLabel);
    // y axis label
    vis.append("g")
        .attr("class", "y axis")
        .call(yAxis)
        .append("text")
        .attr("y", -8)
        .style("text-anchor", "middle")
        .text(settings.yAxisLabel);

    vis.selectAll(".y .tick text")
        .call(wrap, settings.padding.l);

    // Legend
    if (settings.legend !== '') {
        var x_pos = 320;
        var y_pos = 0;
        vis.append("circle").attr("cx",x_pos).attr("cy",y_pos).attr("r", 4).style("fill", "rgb(255, 26, 26)").style("stroke","grey");
        vis.append("text").attr("x", x_pos+10).attr("y", y_pos).text("Significant - upregulated").style("font-size", "11px").attr("alignment-baseline","middle")

        vis.append("circle").attr("cx",x_pos).attr("cy",y_pos+20).attr("r", 4).style("fill", "#0000FF").style("stroke","grey");
        vis.append("text").attr("x", x_pos+10).attr("y", y_pos+20).text("Significant - downregulated").style("font-size", "11px").attr("alignment-baseline","middle")

        vis.append("circle").attr("cx",x_pos).attr("cy",y_pos+40).attr("r", 2).style("fill", "lightgrey").style("stroke","grey")
        vis.append("text").attr("x", x_pos+10).attr("y", y_pos+40).text("Non significant").style("font-size", "11px").attr("alignment-baseline","middle")
    }

    function wrap(text, width) {
        text.each(function() {
            var text = d3.select(this),
                words = text.text().split(/\s+/).reverse(),
                word,
                line = [],
                lineNumber = 0,
                lineHeight = 1.1, // ems
                y = text.attr("y"),
                x = text.attr("x"),
                dy = parseFloat(text.attr("dy")),
                tspan = text.text(null).append("tspan").attr("x", x).attr("y", y).attr("dy", dy + "em");
            while (word = words.pop()) {
                line.push(word);
                tspan.text(line.join(" "));
                if (tspan.node().getComputedTextLength() > width) {
                    line.pop();
                    tspan.text(line.join(" "));
                    line = [word];
                    tspan = text.append("tspan").attr("x", x).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word);
                }
            }
        });
    }
    return plot;
};