/* globals OpenSeadragon, seadragon, d3, getD3Symbol, addDefaultPlotSettings, $, jQuery, geneFilters, getSubcellActivePlotID, imageLoad */

// eslint-disable-next-line no-unused-vars
var subcellColorMap = {
	'Actin filaments': '#37B2D2',
	'Aggresome': '#37BACF',
	'Cell Junctions': '#F9A237',
	'Centriolar satellite': '#37C2CC',
	'Centrosome': '#37C8C2',
	'Cleavage furrow': '#37C9B6',
	'Cytokinetic bridge': '#37C4A4',
	'Cytoplasmic bodies': '#37BF91',
	'Cytosol': '#37BB77',
	'Endoplasmic reticulum': '#F58D37',
	'Endosomes': '#F27937',
	'Focal adhesion sites': '#37B854',
	'Golgi apparatus': '#EB5B37',
	'Intermediate filaments': '#4AB737',
	'Kinetochore': '#F13791',
	'Lipid droplets': '#E83F37',
	'Lysosomes': '#F1374E',
	'Microtubule ends': '#79BB37',
	'Microtubules': '#A4C237',
	'Midbody ring': '#D9C537',
	'Midbody': '#C2C637',
	'Mitochondria': '#E9C237',
	'Mitotic chromosome': '#E837A4',
	'Mitotic spindle': '#F7BE37',
	'Nuclear bodies': '#DC37B8',
	'Nuclear membrane': '#CB37CD',
	'Nuclear speckles': '#A037CE',
	'Nucleoli fibrillar center': '#4737CD',
	'Nucleoli rim': '#3757CB',
	'Nucleoli': '#7437CE',
	'Nucleoplasm': '#3774C9',
	'Peroxisomes': '#F83765',
	'Plasma membrane': '#FB3770',
	'Rods & Rings': '#F9B037',
	'Vesicles': '#F9377E',
	'Multilocalizing': '#b0b0b0',
};

$(window).on("load", function() {
	'use strict';
	var svgCell = $("#svg_cell");
	if (svgCell.length) {
		var svg = $(svgCell[0].contentDocument).find('svg');
		svg.prependTo(svgCell.parent());
		svgCell.hide();
		// Highlight organelles gene page
		var loc_txt = '';
		var all_locs = '';
		$('td.main_location, td.other_location').each(function() {
			var locs = $(this).attr('data-name').split(',');
			if (locs.length>0 && locs[0] !== "") {
				for (var i in locs) {
					if (locs.hasOwnProperty(i)) {
						var loc = locs[i].trim();
						$('g.'+loc+' path').css({'fill':'#7fd822', 'opacity':0.5});
						all_locs += (all_locs? ', ' : '')+loc.replace(/_/g, ' ').ucfirst();
					}
				}
			}
		});
		if (all_locs) {
			loc_txt += ' detected in '+all_locs.replace(/,([^,]*)$/,' and$1');
		}
		var extracellular_td = $('td.extracellular_location');
		if (extracellular_td.length && extracellular_td.html().length > 0) {
			$('g.secreted_proteins path').css({'fill': '#7fd822', 'opacity': 0.5});
			loc_txt += (loc_txt ? '; and' : '') + ' is predicted to be secreted';
		}
		if (loc_txt) {
			D3wrap
			var $txt = $('#cell_grey .legend').show().find('#cell_legend').text($('.gene_name[id]').text() + loc_txt);
			if (loc_txt.length > 100) d3.selectAll('#cell_legend').call(D3wrap, 520);
		}
		// Hover highlight organelles
		$('tr.organelle a, span.cell_organelle, #cell g[id], #cell_grey g[id]').on('mouseover', function() {
			$('svg g.col').hide();
			var names;
			if ($(this).is('g')) {
				names = $(this).attr('id').split(' ');
			} else if ($(this).is('span.cell_organelle')) {
				names = $(this).attr('name').split(',');
			} else {
				names = $(this).closest('div').attr('name').split(',');
			}
			for (var i in names) {
				if (names.hasOwnProperty(i)) {
					var loc = names[i].replace('_ton','').trim();
					$('svg g.'+loc).show();
					$('svg g.'+loc+'.ton').hide();
				}
			}
		}).on('mouseout', function() {
			$('svg g:not(.legend)').show();
		});
		// Make cell elements links
		$("svg#cell g[id], svg#cell_grey g[id]").each(function() {
			var loc = $(this).attr("id").replace(/_ton$/, "").trim();
			if ($("span[name='"+loc+"'] a").length) {
				$(this).css('cursor', 'pointer');
				$(this).on("click", function() {
					document.location.href=$('span[name="'+loc+'"] a').attr('href');
				});
			}
		});
	}
});

function imgClickHandler(elem) {
	var chImage = elem.querySelector('.channel_image');
	return imageLoad(elem, chImage.dataset.imgload1, chImage.dataset.imgload2, chImage.dataset.imgload3, '', chImage.dataset.zindex);
}

$(function() {
	'use strict';
	// LUT button
	$(document).on('click', '.lut_button', function() {
		var $container = $(this).closest('.cellImages, #seadragon');
		$(this).toggleClass('channel_inactive').trigger('blur');
		// If lut active limit to 1 channel
		if (!$(this).hasClass('channel_inactive')) {
			$container.find('.channel_button:not(.channel_inactive):not(:first)').addClass('channel_inactive');
			$container.find('.cell_intensity_legend').show();
		}
		else {
			$container.find('.cell_intensity_legend').hide();
		}
		$container.toggleChannel();
	});
	// Segmentation button
	$(document).on('click', '.segm_button', function() {
		$(this).toggleClass('channel_inactive').trigger('blur');
		$('img.segm_image').trigger('toggle_segm_image');
		$('#seadragon').trigger('toggle_segm_seadragon');
	});
	$(document).on('toggle_segm_image', 'img.segm_image', function() {
		var $container = $(this).closest('.cellImages, #seadragon');
		var segm_button = $container.find('.segm_button');
		if (segm_button.length) {
			// Segmentation button exists
			if (segm_button.hasClass('channel_inactive')) {
				$(this).hide();
			}
			else {
				var $img = $(this).prev('img');
				if ($img.attr("base") === "") {
					return;
				}
				var base = $img.attr('base').replace('//images.proteinatlas.org','').replace('/images', '');
				var medium = $img.attr('src').indexOf('medium') === -1? '' : '_medium';
				var thumb = $img.attr('src').indexOf('thumb') === -1? '' : '_thumb';
				$(this).attr('src', '/images_cell_segmentation' + base + '_segmentation' + medium + thumb +'.png').show();
			}
		}
	});
	$(document).on('toggle_segm_seadragon', '#seadragon', function() {
		var $container = $(this).closest('.cellImages, #seadragon');
		var segm_button = $container.find('.segm_button');
		if (segm_button.length) {
			// Segmentation button exists
			var OsViewer = ($container.attr('id') === 'seadragon')? seadragon() : false;
			if (segm_button.hasClass('channel_inactive')) {
				OsViewer.removeOverlay($('#seadragon_overlay_img')[0]);
			}
			else {
				var $overlay = $('#seadragon_overlay').find('img').clone(true).attr('id', 'seadragon_overlay_img');
				var coord = OsViewer.viewport.imageToViewportRectangle(0, 0, $overlay.data('width'), $overlay.data('height'));
				OsViewer.addOverlay($overlay[0], coord, OpenSeadragon.OverlayPlacement.TOP_LEFT);
			}
		}
	});
	
	// Compare sample
	$('.cellImg.thumb').draggable({
		start: function() {
		},
		stop: function() {
			var over = $(this).data('over');
			if (over) {
				placeImage($(this), over, true);
			}
		},
		revert: true,
		revertDuration: 50
	}).each(function() {
		$(this).draggable("option", "containment", $(this).closest('.cellImages'));
	}).on('click', function() {
		return imgClickHandler(this);
	}).each(function() {
		$(this).attr('onclick', '');
	});
	$('.cellImg.medium').droppable({
		over: function(event, ui) {
			ui.draggable.data('over', $(this));
		},
		out: function(event, ui) {
			ui.draggable.removeData('over');
		}
	});
	$('button.compare').on('click', function() {
		var container = $(this).closest('.cellImages');
		if (typeof container.data('checked') !== 'undefined') {
			for (var i in container.data('checked')) {
				if (container.data('checked').hasOwnProperty(i)) {
					placeImage(container.find('.cellImg.thumb[data-name="'+container.data('checked')[i].val()+'"]'), container.find('.medium[data-name="'+(i*1+1)+'"]'));
				}
			}
		}
	});
	$('input.compare').on('change', function() {
		var container = $(this).closest('.cellImages');
		if (typeof container.data('checked') === 'undefined') {
			container.data('checked', []);
		}
		var checked = [];
		// remove me from selected
		for (var i in container.data('checked')) {
			if (container.data('checked').hasOwnProperty(i)) {
				if (!container.data('checked')[i].is($(this))) {
					checked.push(container.data('checked')[i]);
				}
			}
		}
		// add me if checked
		if ($(this).is(':checked')) {
			checked.push($(this));
		}
		// remove first  if too many
		if (checked.length > 3) {
			checked.shift().prop('checked', false);
		}
		container.data('checked', checked);
	});
	
	function placeImage($el, $slot, drag) {
		var outerContainer = $el.closest('.cellImages');
		var imgContainer = $slot.closest('.cellImage');
		$slot.off('click');
		$slot.on('click', function() {
			return imgClickHandler(this);
		});
		// Replace image
		$slot.html($el.html().replace(/thumb/g, 'medium')).attr({
			'href': $el.attr('href')
		});
		var imgElem = $el.find('img.channel_image').get(0).dataset;
		if (imgElem.hasOwnProperty('stack')) {
			$slot.get(0).stackData = JSON.parse(imgElem.stack);
		} else {
			$slot.get(0).stackData = undefined;
		}
		// Text
		updateImageInfo(imgContainer, $el);
		// Update numbers & checkboxes(drag)
		if (drag) {
			outerContainer.find('input.compare').prop('checked', false).trigger('change');
		}
		outerContainer.find('.thumb .image_number').text("");
		outerContainer.find('.medium .channel_image[base]').each(function() {
			var num = $(this).parent().attr('data-name');
			var base = $(this).attr('base');
			$(this).siblings('.image_number').text(num);
			outerContainer.find('.thumb img[base="'+base+'"]').siblings('.image_number').each(function() {
				var txt = $(this);
				txt.text((txt.text() ? txt.text()+',' : '')+num);
			});
			if (drag) {
				var name = $(this).attr('data-name');
				outerContainer.find('#compare_'+name).prop('checked', true).trigger('change');
			}
		});
	}

	function updateImageInfo(container, $el) {
		var imageinfoEl = container.find('span.imageinfo');
		imageinfoEl.text($el.find('.channel_image').attr('alt'));
		var channelImage = $el.find('.channel_image').get(0);
		var zindex = parseInt(channelImage.dataset.zindex, 10);
		var stackImageEl = container.find('.stack_image');
		var stackSliderP = container.find('.stackSlider');
		if (zindex) {
			var ztotal = channelImage.dataset.ztotal;
			stackImageEl.text(subcell_stack_text(zindex, ztotal));
			var slider = stackSliderP.find('input[type="range"]');
			slider.prop('value', zindex);
			slider.prop('max', ztotal);
			stackSliderP.show();
		} else {
			stackImageEl.text('');
			stackSliderP.hide();
		}
	}
	$('.stackSlider .slider').on('input', function() {
		var newValue = this.value;
		var maxValue = this.max;
		$(this).closest('.cellImage').find('.stack_image').text(subcell_stack_text(newValue, maxValue));
		var c1 = $(this).parents('.cellImages').get(0);
		var c = $(c1).getChannelString($(c1).getActiveChannels());
		var cellImg = $(this).parentsUntil('.cellImage').parent();
		var imgData = cellImg.find('.cellImg').get(0).stackData[newValue];
		var newSrc = imgData.filename + '_' + c + '_medium.jpg';
		cellImg.find('.channel_image').get(0).src = newSrc;
		cellImg.find('.cellImg').get(0).href = newSrc;
		cellImg.find('.channel_image').get(0).dataset.zindex = newValue;
		cellImg.find('.channel_image').prop('base', imgData.filename);
		cellImg.find('.channel_image').attr('base', imgData.filename);

	});
	$('body').on('input', '#seadragon_meta input.stackSlider', function() {
		var newValue = this.value;
		var maxValue = this.max;
		$(this).parent().find('.stack_image').text(subcell_stack_text(newValue, maxValue));
		var sea = $(this).closest('#seadragon');
		var imgData = $('#seadragon_meta').get(0).stackData[newValue];
		sea.data('base', imgData.filename);
		sea.toggleChannel(true);
	});
	
	$('.cellImages, #seadragon').each(function() {
		if ($(this).find('input.compare:checked').length) {
			$(this).find('input.compare:checked').trigger('change');
		}
		else {
			var interval = $(this).attr('interval');
			if (!interval) {
				interval = 2;
			}
			var inpts = $(this).find('td:not(.nocompareinit) input.compare');
			var c = 0;
			if ($(this).closest("#sirna").length) {
				var z = $("#sirna tr.scrambled td:not(.nocompareinit) input.compare:first");
				var ab = z.closest("tr").attr("class").match("ab[0-9]+")[0];
				var z2 = $("#sirna tr.notscrambled."+ab+" td:not(.nocompareinit) input.compare");
				z.prop('checked', true).trigger('change');
				c = 1;
				z2.each(function() {
					if (c>=3) {
						return;
					}
					$(this).prop('checked', true).trigger('change');
					c++;
				});
			} else {
				inpts.each(function(i) {
					if (c===3) {
						return;
					}
					if (i%interval === 0 || inpts.length<5) {
						$(this).prop('checked', true).trigger('change');
						c++;
					}
				});
			}
		}
		$(this).find('button.compare').trigger('click');
	});
	
	// Reactome
	// Check if gene exists in Reactome
	if ($(".reactome").length) {
		$.get('https://reactome.org/ContentService/data/mapping/ENSEMBL/'+$('.gene_name[id]').attr('id')+'/pathways', function() {
			$(".reactome").each(function() {
				// The URL of the analysis method
				var reactomeURI = 'https://reactome.org/AnalysisService/identifiers/url/projection?pageSize=1&page=1';
				// The URL of our sample to be submitted for analysis
				var dataUrl = 'https://'+window.location.hostname+"/download/if_location.php?";
				var locs = $(this).attr('data-name').split(',');
				if (locs.length>0 && locs[0] !== "") {
					for (var i in locs) {
						if (locs.hasOwnProperty(i)) {
							dataUrl += "locations[]=" + locs[i].trim() + "&";
						}
					}
				}
				var $container = $(this);
				// Perform the ajax call to the analysis service
				jQuery.ajax({
					type: "POST",
					url: reactomeURI,
					data: dataUrl,
					dataType: "json",
					headers: {
						"Content-Type": "text/plain"
					}
				}).done(function (data, textStatus) {
					if (textStatus === 'success') {
						$.each(data.pathways, function(){
							$container.find(".reactomeLink").html('<a href="https://reactome.org/PathwayBrowser/#/DTAB=AN&ANALYSIS='+data.summary.token+'&FLG='+$('.gene_name[id]').text()+'" target="_blank" rel="noopener">View proteome in REACTOME</a>');
						});
					}
				}).fail(function () {
					$container.find(".reactomeLink").html("(Failed to get Reactome Data)");
				});
			});
		});
	}

	$('div#clusterPlotSlider .active').trigger('change');
	$('#locationLegend .location .locationName, #locationLegend .location .color').on('click', function() {
		// Add or remove active class from the clicked element
		var elem;
		if (!$(this).hasClass('locationName')) {
			elem = $(this).siblings('.locationName');
		} else {
			elem = $(this);
		}
		elem.toggleClass('active');
		if (elem.hasClass('active')) {
			elem.removeClass('inactive');
		}
		if ($('#locationLegend .location .locationName.active').length) {
			// If at least one location is active, make sure all non-active locations have the inactive class
			// to grey out the inactive legends
			$('#locationLegend .location .locationName:not(.active):not(.inactive)').addClass('inactive');
		} else {
			$('#locationLegend .location .locationName').removeClass('inactive');
		}
		var name = [];
		$('#locationLegend .location .locationName.active').each(function() {
			name.push($(this).text());
		});
		geneFilters.location = name.length ? name : undefined;
		$('#' + getSubcellActivePlotID()).trigger('plot_filter');
	});
});

$.fn.mvavgScatterPlot = function(data, inSettings) {
	'use strict';
	var plot = {};
	var extraDefaults = {
		xMin: false,
		xMax: false,
		yMin: false,
		yMax: false,
		xTickFormat: ".2s",
		xNumMaxTicks: 6,
		xNumMinTicks: 4,
		yNumMaxTicks: 10,
		yNumMinTicks: 4,
		transitionTime: 1000
	};
	var settings = addDefaultPlotSettings(inSettings, extraDefaults);
	plot.settings = settings;

	// Inner dimension
	var w = plot.w = settings.dimension.w - settings.padding.l - settings.padding.r; // inner width
	var h = plot.h = settings.dimension.h - settings.padding.t - settings.padding.b; // inner height

	var xMin = Infinity;
	var xMax = -Infinity;
	var yMin = Infinity;
	var yMax = -Infinity;
	var scatter = data.scatter;
	for (var i in scatter) {
		if (!scatter.hasOwnProperty(i)) {
			continue;
		}
		for (var j in scatter[i].data) {
			if (!scatter[i].data.hasOwnProperty(j)) {
				continue;
			}
			
			xMin = settings.xMin===false? Math.min(xMin, scatter[i].data[j].x) : settings.xMin;
			xMax = settings.xMax===false? Math.max(xMax, scatter[i].data[j].x) : settings.xMax;
			yMin = settings.yMin===false? Math.min(yMin, scatter[i].data[j].y) : settings.yMin;
			yMax = settings.yMax===false? Math.max(yMax, scatter[i].data[j].y) : settings.yMax;
		}
	}
	plot.xMin = xMin; plot.xMax = xMax; plot.yMin = yMin; plot.yMax = yMax;

	var color = plot.color = d3.scaleOrdinal()
		.range(settings.color)
		.domain(d3.map(data.scatter, function(d, idx) {
			return idx;
		}));

	// X axis
	var xScale = plot.x = d3.scaleLinear()
		.domain([xMin, xMax])
		.range([0, w]);

	// Y axis
	var yScale = plot.y = d3.scaleLinear()
		.domain([yMin, yMax])
		.range([h, 0]);

	var xAxis = d3.axisBottom(xScale)
		.tickFormat(d3.format(settings.xTickFormat))
		.ticks(Math.min(Math.max(Math.ceil(xMax), settings.xNumMinTicks), settings.xNumMaxTicks));

	var yAxis = d3.axisLeft(yScale)
		.tickFormat(d3.format(settings.yTickFormat))
		.ticks(Math.min(Math.max(Math.ceil(yMax), settings.yNumMinTicks), settings.yNumMaxTicks));
	if (settings.grid) {
		yAxis.tickSizeInner(-w);
	}

	// Visualisation selection
	var vis = plot.vis = d3.select($(this).get(0))
		.append("svg")
		.attr("width", settings.dimension.w)
		.attr("height", settings.dimension.h)
		.attr("class", "chart scatterplot")
		.append("g")
		.attr("transform", "translate(" + settings.padding.l + "," + settings.padding.t + ")");

	// Plot area background
	vis.append("rect")
		.attr("class", "plotBG")
		.attr("width", xScale(xMax))
		.attr("height", yScale(0));

	// The background areas
	var area = d3.area()
		.x(function(d) {
			return xScale(parseFloat(data.confidence[0].data[d].mvavg_x));
		})
		.y0(function(d) {
			return yScale(parseFloat(data.confidence[0].data[d].mvavgs_10p));
		})
		.y1(function(d) {
			return yScale(parseFloat(data.confidence[0].data[d].mvavgs_90p));
		});
	vis.append("path")
		.datum(d3.range( data.confidence[0].data.length))
		.attr("fill", data.confidence[0].colors.outer)
		.attr('d', area);
	area = d3.area()
		.x(function(d) {
			return xScale(parseFloat(data.confidence[0].data[d].mvavg_x));
		})
		.y0(function(d) {
			return yScale(parseFloat(data.confidence[0].data[d].mvavgs_25p));
		})
		.y1(function(d) {
			return yScale(parseFloat(data.confidence[0].data[d].mvavgs_75p));
		});
	vis.append("path")
		.datum(d3.range( data.confidence[0].data.length))
		.attr("fill", data.confidence[0].colors.inner)
		.attr('d', area);
	
	// The points
	var group = vis.selectAll(".group")
		.data(scatter)
		.enter().append("g")
		.attr("class", function(d, idx) {
			return "group group" + idx;
		})
		.attr("name", function(d, idx) {
			return "group" + idx;
		})
		.style("fill", function(d, idx) {
			return d.color ? d.color : color(idx);
		})
		.attr("fill-opacity", "0.3")
		.each(function(d) {
			d3.select(this).selectAll('.dot')
				.data(d.data)
				.enter()
				.append("a")
				.attr('class', function(d) {
					return d.class ? 'dot ' + d.class : 'dot';
				})
				.attr('transform', function(d) {
					return 'translate(' + [xScale(d.x), yScale(d.y)] + ')';
				})
				.each(function(d) {
					if (d.url) {
						d3.select(this).attr("xlink:href", d.url);
					}
					if (d.tooltip) {
						d3.select(this).attr("title", d.tooltip);
					}
					if (settings.valueLabels) {
						d3.select(this).append('text').text(d.x+','+d.y);
					}
				})
				.append("path")
				.attr('d', d3.symbol().size(d.size||15).type(getD3Symbol(d.symbol)));
		});

	// The line for average
	var average = d3.line()
		.x(function(d) {
			return xScale(parseFloat(data.confidence[0].data[d].mvavg_x));
		})
		.y(function(d) {
			return yScale(parseFloat(data.confidence[0].data[d].mvavg_y));
		});
	vis.append("path")
		.datum(d3.range( data.confidence[0].data.length))
		.attr("fill", "none")
		.attr("stroke", data.confidence[0].colors.line)
		.attr('d', average);

	// Add larger tooltip area behind dot
	group.selectAll("a")
		.append("circle")
		.attr("r", 4)
		.style("fill", 'transparent');
	


	// Y axis
	if (settings.yAxisLabel) {
		var xPos = -h/2;
		var yPos = -30;
		var yAxisLabel = vis.append("g")
			.attr("class", "y axis")
			.call(yAxis)
			.append("text")
			.attr("transform", "rotate(-90)")
			.attr("y", yPos)
			.attr("x", xPos)
			.attr("class", "label")
			.attr("text-anchor", "middle");

		if (settings.yAxisLabel.indexOf("\n") !== -1) {
			var yLabels = settings.yAxisLabel.split("\n");
			var dy = -1 * (yLabels.length-1);
			for (var label of yLabels) {
				yAxisLabel.append("tspan")
					.attr("x", xPos)
					.attr("dy", dy+"em")
					.text(label);
				dy = 1.2;
			}
		} else {
			yAxisLabel.text(settings.yAxisLabel);
		}
	}

	// X axis
	if (settings.xAxisLabel) {
		vis.append("g")
			.attr("class", "x axis")
			.attr("transform", "translate(0," + h + ")")
			.call(xAxis)
			.append("text")
			.attr("y",30)
			.attr("x", w/2)
			.attr("class", "label")
			.style("text-anchor", "middle")
			.text(settings.xAxisLabel);
	}

	// Legend
	if (settings.legend !== '') {
		var legend = vis.selectAll(".legend")
			.data(data)
			.enter().append("g")
			.attr("class", function(d, i) {
				return 'legend legend' + i;
			})
			.attr("name", function(d, i) {
				return 'legend' + i;
			})
			.attr("transform", function(d, i) {
				return 'translate(' + settings.legend.x + ',' + (settings.legend.y + i * (settings.legend.size + 2)) + ')';
			});

		legend.append("rect")
			.attr("width", settings.legend.size)
			.attr("height", settings.legend.size)
			.style("fill", function(d, i) {
				return d.color ? d.color : color(i);
			});

		legend.append("text")
			.attr("x", settings.legend.size+2)
			.attr("y", settings.legend.size/2)
			.attr("dy", ".35em")
			.text(function(d) {
				return d.name;
			});
	}

	$(this).on('rescale', function(e, scale) {
		var plot = $(this).data('plot');
		if (scale === 'xlog') {
			xScale = plot.x = d3.scaleLog()
				.domain([Math.max(0.0001, xMin), xMax])
				.range([0, w]);
			xAxis = d3.axisBottom(xScale)
				.tickValues([1e-3,1e-2,1e-1,1e0,1e1,1e2,1e3].filter(function(d) {
					return (d < xMax);
				}));
			vis.selectAll('.x.axis .label').text(function() {
				return 'log ' + d3.select(this).text();
			});
		} else if (scale === 'xlin') {
			xScale = plot.x = d3.scaleLinear()
				.domain([xMin, xMax])
				.range([0, w]);
			xAxis = d3.axisBottom(xScale)
				.tickFormat(d3.format(".2s"));
			vis.selectAll('.x.axis .label').text(function() {
				return d3.select(this).text().replace('log ', '');
			});
		} else if (scale === 'ylog') {
			yScale = plot.y = d3.scaleLog()
				.domain([Math.max(0.0001, yMin), yMax])
				.range([h, 0]);
			yAxis = d3.axisLeft(yScale)
				.tickValues([1e-3,1e-2,1e-1,1e0,1e1,1e2,1e3].filter(function(d) {
					return (d < yMax);
				}));
			vis.selectAll('.y.axis .label').text(function() {
				return 'log ' + d3.select(this).text();
			});
		} else if (scale === 'ylin') {
			yScale = plot.y = d3.scaleLinear()
				.domain([yMin, yMax])
				.range([h, 0]);
			yAxis = d3.axisLeft(yScale)
				.tickFormat(d3.format(".2s"));
			vis.selectAll('.y.axis .label').text(function() {
				return d3.select(this).text().replace('log ', '');
			});
		} else {
			return;
		}

		var t = d3.transition().duration(settings.transitionTime);
		group.each(function(d) {
			d3.select(this).selectAll('.dot')
				.data(d.data)
				.transition(t)
				.attr('transform', function(d) {
					var xp = xScale(d.x);
					var yp = yScale(d.y);
					return (xp === -Infinity || yp === -Infinity) ? 'translate(0,' + h + ')' : 'translate(' + [xp, yp] + ')';
				});
		});
		vis.selectAll(".xScaleDependent")
			.transition(t)
			.attr('transform', function() {
				var node = d3.select(this);
				if (node.classed('yScaleDependent')) {
					return 'translate('+xScale(node.attr('xVal'))+', '+yScale(node.attr('yVal'))+')';
				} else {
					return 'translate('+xScale(node.attr('xVal'))+')';
				}
			});
		vis.selectAll(".axis.x")
			.transition(t)
			.call(xAxis);
		vis.selectAll(".axis.y")
			.transition(t)
			.call(yAxis);

		$(this).data('plot', plot);
	});
	$(this).data('plot', plot);
	return plot;
};

function subcell_stack_text(currentValue, maxValue) {
	return `Z-stack: ${currentValue}/${maxValue}`;
}