diff --git a/js/expression-fix.js b/js/expression-fix.js
new file mode 100644
index 0000000..6264baa
--- /dev/null
+++ b/js/expression-fix.js
@@ -0,0 +1,749 @@
+(function ($) {
+
+ Drupal.behaviors.expression = {
+ attach: function (context, settings) {
+ // Define variables
+ this.heatMapRaw = JSON.parse(settings.heatMapRaw);
+ this.selectedAnalysis = settings.selectedAnalysis;
+ this.feature_id = settings.feature_id;
+ this.heatMapTotal = '';
+ this.heatMap = [];
+ this.currentSorting = $('#propertySortMenu').find(':selected').text();
+ this.currentColor = $('#propertyColorMenu').find(':selected').text();
+ this.downloadMessage = $('');
+ this.downloadLink = $('#expressionDownloadLink');
+ this.base_url = settings.basePath;
+ var link = this.base_url + 'analysis-expression/download?feature_ids=' + this.feature_id + '&analysis_id=' + this.selectedAnalysis;
+ $('#expressionDownloadLink').attr('href', link);
+
+ //spacing variables
+ this.margin = {top: 50, bottom: 100, horizontal: 20};
+ this.height = 500;
+ this.barwidth = 10
+ this.scaleSize = this.barwidth * 4.5 //this is a thumbnail estimate, im not sure of a better way to do it
+ this.barSpacing = this.barwidth/2
+
+
+
+ // Activate plot
+ this.expNormal();
+ this.attachEventListeners();
+ },
+
+ /**
+ * Attach events to all of our elements here.
+ */
+ attachEventListeners: function () {
+ $('#show-non-zero-only').on('click', this.nonZero.bind(this));
+ $('#reset-expression-plot').on('click', this.expNormal.bind(this));
+ $('#analyses-dropdown').on('change', this.analysisChanged.bind(this));
+ $(window).on('resize', this.expNormal.bind(this));
+ $(document).on('tripal_ds_pane_expanded', this.expNormal.bind(this));
+
+ // If the selector changes, rebuild the figure
+ $(document).on('change', '#propertySortMenu', function (e) {
+ this.currentSorting = e.target.value;
+ d3.selectAll('chart').remove();
+ this.drawPlot();
+ }.bind(this));
+
+ // If the selector changes, rebuild the figure
+ $(document).on('change', '#propertyColorMenu', function (e) {
+ this.currentColor = e.target.value;
+ d3.selectAll('chart').remove();
+ this.drawPlot();
+ }.bind(this));
+
+ var _that = this;
+ this.downloadLink.after(this.downloadMessage);
+ this.downloadLink.on('click', function (e) {
+ _that.initiateDownload.call(this, e, _that);
+ }); // Do not bind this here
+ },
+
+ /**
+ * Create an iframe to start the download.
+ *
+ * @param {Object} e event
+ * @param {Object} object this
+ */
+ initiateDownload: function (e, object) {
+ e.preventDefault();
+ var src = $(this).attr('href');
+ var iframe = $('', {
+ src: src,
+ width: 1,
+ height: 1
+ });
+ $('body').append(iframe);
+ object.downloadMessage.html(' Generating file. Download will start automatically...');
+ },
+
+ /**
+ * updates the download link when an analysis has been selected.
+ */
+ analysisChanged: function (e) {
+ this.selectedAnalysis = e.target.value;
+ this.expNormal();
+
+ // Change the link address
+ var link = this.base_url + 'analysis-expression/download?feature_ids=' + this.feature_id + '&analysis_id=' + this.selectedAnalysis;
+ $('#expressionDownloadLink').attr('href', link);
+ },
+
+ /**
+ * This function will remove biomaterials that have a value of 0.
+ */
+ nonZero: function () {
+ this.heatMap = this.heatMap.filter(function (d) {
+ return d.intensity > 0;
+ });
+ d3.selectAll('chart').remove();
+ this.drawPlot();
+ },
+
+ /**
+ * Normalize
+ */
+ expNormal: function () {
+ this.heatMapTotal = this.heatMapRaw;
+ // Get samples associated with selected analysis
+ this.selectedAnalysis = d3.select('#analyses-dropdown').property('value');
+ this.heatMap = this.heatMapTotal[this.selectedAnalysis].biomaterials;
+ this.buildPropertySelect();
+ d3.selectAll('chart').remove();
+ this.drawPlot();
+ },
+
+ /**
+ * Append the Property selectors. Sort is for what property to group by,
+ * color is for what property to color by.
+ */
+ buildPropertySelect: function () {
+ var $sortMenu = $('#propertySortMenu');
+ var $colorMenu = $('#propertyColorMenu');
+ // Remove the old selectors and store values
+ var previousValueSort = $sortMenu.find(':selected').text();
+ d3.selectAll('#propertySortDiv').selectAll('select').remove();
+ var previousValueColor = $colorMenu.find(':selected').text();
+ d3.selectAll('#propertyColorDiv').selectAll('select').remove();
+
+ // Build list of properties for this analysis
+ var selectorSort = d3.select('#propertySortDiv').append('select').attr('id', 'propertySortMenu');
+ var selectorColor = d3.select('#propertyColorDiv').append('select').attr('id', 'propertyColorMenu');
+
+ // First add "expression value" as default for color
+ selectorColor.append('option')
+ .attr('value', 'Expression value')
+ .text('Expression value');
+
+ this.heatMap.map(function (biomaterial) {
+ Object.keys(biomaterial.properties).map(function (property_key) {
+ // Determine if this property is already in our selector
+ var exists = $('#propertySortDiv option')
+ .filter(function (i, o) {
+ return o.value === property_key;
+ })
+ .length > 0;
+
+ if (!exists) { //append it to both selector lists
+ selectorSort.append('option')
+ .attr('value', function () {
+ return property_key;
+ })
+ .text(function () {
+ return property_key;
+ });
+ selectorColor.append('option')
+ .attr('value', function () {
+ return property_key;
+ })
+ .text(function () {
+ return property_key;
+ });
+ }
+
+ });
+ });
+
+ $colorMenu.val('Expression value');
+
+ if (previousValueSort) {
+ $sortMenu.val(previousValueSort);
+ }
+ if (previousValueColor) {
+ $colorMenu.val(previousValueColor);
+ }
+ },
+
+ drawPlot: function () {
+ var _that = this;
+
+ var maxHeat = d3.max(this.heatMap, function (d) {
+ return Number(d.intensity);
+ });
+
+ var minHeat = d3.min(this.heatMap, function (d) {
+ return Number(d.intensity);
+ });
+
+ // Define color scale based on selected
+ var colorDomain = '';
+ var color = '';
+ if (this.currentColor !== 'Expression value') {
+ colorDomain = this.buildPropertyValuesDomain('color');
+ color = d3.scale.ordinal()
+ .domain(colorDomain)
+ .range(['#A6CEE3', '#1F78B4', '#B2DF8A', '#33A02C', '#FB9A99', '#E31A1C', '#FDBF6F',
+ '#FF7F00', '#CAB2D6', '#6A3D9A', '#FFFF99', '#B15928'
+ ]);
+ }
+ else {
+ // TODO: do we mean min and max or both max here?
+ //we mean what is written here.
+ //You can have very disjointed expression values: the minimum could be 10, and the max 10000000.
+ //This domain maps one blue to 0, HALF the max to gray, and the max to red. If you do 0, min, max, you'll likely end up with only two colors: gray and red. nothing will be blue.
+ colorDomain = [0, maxHeat / 2, maxHeat];
+ color = d3.scale.linear()
+ .domain(colorDomain)
+ .range(['blue', 'gray', 'red']);
+ }
+
+
+ var barwidth = this.barwidth
+ var margin = this.margin
+ var scaleSize = this.scaleSize //this is a thumbnail estimate, im not sure of a better way to do it
+ var barSpacing = this.barSpacing
+
+ /// y values
+ var height = this.height;
+
+ var y = d3.scale.linear()
+ .range([height, (margin.top + margin.bottom)]);//reverse because 0 is
+ // the top.
+
+ var yAxis = d3.svg.axis()
+ .scale(y)
+ .orient('left')
+ .ticks(2);
+
+ var nested = d3.nest()
+ .key(function (d) {
+ if (!d.properties[this.currentSorting]) {
+ return 'Not set';
+ }
+ return d.properties[this.currentSorting];
+ }.bind(this)).entries(this.heatMap);
+
+
+ /// X values
+
+ var groupCount = {}
+ var totalSamples = 0
+ var numberKeys = nested.length
+
+ nested.map(function (d) {
+ groupCount[d.key] = d.values.length
+ totalSamples += d.values.length
+ })
+
+ var numberOfGroups = Object.keys(groupCount).length
+
+
+ //figure out size of figure
+ var minWidth = d3.select('figure').node().getBoundingClientRect().width;
+
+ var width = ((totalSamples + 1) * barwidth ) + (totalSamples * this.barSpacing) + (numberOfGroups * barwidth/2) + scaleSize + (margin.horizontal * 2)
+ var calculatedWidth = Math.max(minWidth, width);
+
+var averageStepSize = calculatedWidth/totalSamples
+ //if there is only one group the domain will break. if thats the case, append an empty group
+ if (numberOfGroups === 1){ //we can't have 0 groups
+ var thisGroupIndex = numberOfGroups //no need to adjust because starts at 0
+ nested[thisGroupIndex.toString()] = {"key": "spacing_group_for_domain", "values": []}
+ numberOfGroups++
+ }
+
+ var rangeMapper = {}
+ var lengthTracker = 0 //keep track of where we are on the scale
+
+ nested.map(function (d, i) {
+ var groupSize = d.values.length *averageStepSize
+ // var location = lengthTracker + groupSize/2 //set the location to the middle of its group
+ var location = lengthTracker //set the location to the start of its group
+
+ rangeMapper[d.key] = location
+ lengthTracker += groupSize
+ nested[i]["position"] = i
+ })
+ var x0 = d3.scale.linear()
+ .rangeRound(nested.map(function(d){
+ return rangeMapper[d.key]
+ }))
+
+ // Set the domains based on the nested data
+ x0.domain(nested.map(function (d, i) {
+ return d.position;
+ }));
+
+ y.domain([0, maxHeat]);
+
+//start plotting here
+ d3.select('figure')
+ .style('overflow', 'auto')
+ .style('max-width', '100%');
+
+ var svg = d3.select('figure')
+ .append('chart')
+ .append('svg')
+ .attr('width', calculatedWidth)
+ .attr('height', height)
+ .append('g');
+
+
+ svg.append('g')
+ .attr('class', 'y-axis')
+ .attr('transform', 'translate(' + ( scaleSize) + ', -' + (margin.bottom) + ')')
+ .style('font-size', '12px')
+ .style('font-weight', 'normal')
+ .call(yAxis)
+ .select('.domain');
+
+ var dragging = {};
+
+ var propertyGroups = svg.selectAll('.propertyGroups')
+ .data(nested)
+ .enter()
+ .append('g')
+ .attr('transform', function (d, i) {
+ if (d.key === "spacing_group_for_domain"){
+ return //skip plotting the spacing group
+ }
+ return 'translate(' + this.translationXOffset(i, x0) + ',0)';
+ }.bind(this));
+
+ //Add a bar along the bottom
+ propertyGroups.append('g')
+ .attr()
+ .append('rect')
+ .style('fill', 'black')
+ .attr('y', height - (margin.bottom -1))
+ .attr('x', barwidth/2)
+ .attr('width', function(d) {
+ var length = d.values.length * (barwidth + barSpacing) - barwidth*1.5
+ return length > barwidth ? length : 1;
+
+ })
+ .attr('height', 1)
+
+
+ var text = propertyGroups.append('text')
+ .attr('class', 'label')
+ .style('font-size', '12px')
+ .style('font-weight', 'normal')
+ .style('padding', '5px')
+ .attr('x', 0)
+ .attr('y', 0)
+ .html(function (d) {
+ if (d.key === "spacing_group_for_domain"){
+ return //skip plotting the spacing group
+ }
+
+ var label = d.key;
+ var characterLimit = 20;
+ if (label.length > characterLimit) {
+ var splitString = label.match(new RegExp('.{1,' + characterLimit + '}', 'g'));
+ label = splitString.map(function (item) {
+ return '' + item + '';
+ }).join(' ');
+ }
+ return label;
+ })
+ .style('text-anchor', 'bottom');
+
+ text.attr('transform', function (d) {
+ return ' translate( ' + ((d.values.length /2) * (barwidth ) + (barSpacing) * ((d.values.length - 1)/2) ) +',' + (height - margin.bottom + 10) + ' ),rotate(45)';
+ });
+
+
+ propertyGroups.call(d3.behavior.drag()
+ .origin(function (d, i) { // define the start drag as the middle of the group
+ // this should match the transformation used when assigning the
+ // group
+ return {x: _that.translationXOffset(d.position, x0)};
+ })
+ .on('dragstart', function (d, i) {
+ // track the position of the selected group in the dragging object
+ dragging[d.key] = _that.translationXOffset(d.position, x0);
+ var sel = d3.select(this);
+ sel.moveToFront();
+ })
+ .on('drag', function (d, i) {// track current drag location
+ dragging[d.key] = d3.event.x;
+
+ nested.sort(function (a, b) {
+ return position(a, a.position, x0) - position(b, b.position, x0);
+ });
+
+
+ ///rebuild the domain
+ //TODO: This is very not - DRY, copied from initial domain set. should be factored out.
+
+ var rangeMapper = {}
+ var lengthTracker = 0 //keep track of where we are on the scale
+
+ nested.map(function (d, i) {
+
+ var groupSize = d.values.length *averageStepSize
+ // var location = lengthTracker + groupSize/2 //set the location to the middle of its group
+ // var location = lengthTracker + groupSize/2 //set the location to the middle of its group
+ var location = lengthTracker //set the location to the start of its group
+
+ rangeMapper[d.key] = location
+ lengthTracker += groupSize
+ nested[i]["position"] = i
+ })
+
+
+ x0 = d3.scale.linear()
+ .rangeRound(nested.map(function(d){
+ return rangeMapper[d.key]
+ }))
+
+ // Set the domains based on the nested data
+ x0.domain(nested.map(function (d, i) {
+ return i;
+ }));
+
+ propertyGroups.attr('transform', function (d) {
+
+ return 'translate(' + position(d, d.position, x0) + ', 0)';
+ });
+ })
+ .on('dragend', function (d, i) {
+ delete dragging[d.key];
+ transition(d3.select(this)).attr('transform', function (d) {
+ return 'translate(' + _that.translationXOffset(d.position, x0) + ',0)';
+ });
+
+ // propertyGroups.selectAll()
+ // .attr('transform', function (d, i ) {
+ // return 'translate(' + _that.translationXOffset(d.position, x0) + ',0)';
+ // });
+ })
+ );
+
+ //plot the actual bars!!
+
+ var bars = propertyGroups.selectAll('.bar')
+ .data(function (d) {
+ return d.values;
+ })
+ .enter().append('rect')
+ .style('fill', function (d) { // fill depends on if user is doing expression based or property based
+ if (this.currentColor === 'Expression value') {
+ return color(d.intensity);
+ }
+ else {
+ var propertyName = '';
+ if (!d.properties[this.currentColor]) {
+ propertyName = 'Not set';
+ }
+ else {
+ propertyName = d.properties[this.currentColor];
+ }
+ return color(propertyName);
+ }
+
+ }.bind(this))
+ .attr('y', function (d) {
+ return y(d.intensity);
+ })
+ .attr('x', function (d, i) {
+ return (i * (barwidth + barSpacing))
+ })
+ .attr('width', this.barwidth)
+ .attr('height', function (d) {
+ return y(0) - y(d.intensity);
+ })
+ .attr('transform', 'translate(0,' + (-margin.bottom) + ')');
+
+
+ // define methods for dragging
+ d3.selection.prototype.moveToFront = function () {
+ return this.each(function () {
+ this.parentNode.appendChild(this);
+ });
+ };
+
+ function position(property, i, x0) {
+ var v = dragging[property.key];
+ // v will be null if we arent dragging it: in that case, get its
+ // position
+
+ //we need this properties key in the array
+ return v == null ? _that.translationXOffset(i, x0) : v;
+ }
+
+ function transition(g) {
+ return g.transition().duration(500);
+ }
+
+//Add the tool tip
+
+ var divTooltip = d3.select('body').append('div')
+ .attr('class', 'toolTip')
+ .style('position', 'absolute')
+ .style('max-width', '250px')
+ .style('padding', '10px')
+ .style('font-size', '12px')
+ .style('font-family', 'Helvetica, Roboto, sans-serif')
+ .style('background', 'rgba(255, 255, 255, .9)')
+ .style('border', '1px solid rgba(0,0,0,.3)')
+ .style('border-radius', '5px')
+ .style('pointer-events', 'none')
+ .style('display', 'none')
+ .style('opacity', 0)
+ .style('transition', 'opacity .25s linear')
+ .style('z-index', 999999);
+ bars.on('mouseover', function (d) {
+ var propTable = _that.buildPropertyTooltipTable(d);
+ divTooltip.transition()
+ .duration(200)
+ .style('opacity', 1)
+ .style('display', 'block');
+ divTooltip.html(
+ 'Biosample: ' + d.name + '
' +
+ 'Expression: ' + d.intensity + ' ' + d.units + '
' +
+ 'Description:
' + d.description + '
'
+ + propTable)
+ .style('left', ($(this).offset().left - 260) + 'px')
+ .style('top', ($(this).offset().top - (y(d.intensity)) + 'px'));
+ }).on('mouseout', function (d) {
+ divTooltip.transition()
+ .duration(500)
+ .style('opacity', 0)
+ .style('display', 'none');
+ });
+
+ this.buildLegend(color, calculatedWidth, margin, height);
+
+ var title = 'Expression by ' + this.currentSorting;
+
+ svg.append('text')
+ .attr('x', (calculatedWidth / 2 - margin.horizontal))
+ .attr('y', margin.top / 2)
+ .attr('text-anchor', 'middle')
+ .style('font-size', '16px')
+ .text(title);
+ },
+
+ /**
+ * This function determines the position of a nested group by returning the
+ * value from the scale and adding half the range band.
+ *
+ * @param d
+ * @param scale
+ * @returns {string}
+ */
+ translationXOffset: function (i, scale) {
+ return(scale(i)) + this.margin.horizontal + this.scaleSize
+ },
+
+ /**
+ * Creates the table for the tooltip
+ * TODO: Use jQuery to build the table
+ * @param d
+ * @returns {string}
+ */
+ buildPropertyTooltipTable: function (d) {
+ var table = '';
+ if (Object.keys(d.properties).length > 0) {
+ table += '
';
+ }
+ return table;
+ },
+
+ /**
+ * Builds the legend.
+ *
+ * @param colorScale
+ * @param width
+ * @param margin
+ * @param height
+ */
+ buildLegend: function (colorScale, width, margin, height) {
+ this.currentColor = $('#propertyColorMenu').find(':selected').text();
+ d3.select('chart').selectAll('legend').remove();
+
+ var legend = {};
+
+ if (this.currentColor !== 'Expression value') {
+ legend = d3.select('chart')
+ .select('g')
+ .append('g')
+ .attr('class', 'legend')
+ .attr('transform', 'translate(' + (width - 10 * margin.horizontal) + ', 10)')
+ .selectAll('.legendItem')
+ .data(colorScale.domain())
+ .enter()
+ .append('g')
+ .attr('class', 'legendItem')
+ .attr('transform', function (d, i) {
+ {
+ return 'translate(0,' + (i * 10) + ' )';
+ }
+ });
+ legend.append('rect')
+ .attr('x', 0)
+ .attr('y', 10)
+ .attr('width', 20)
+ .attr('height', 10)
+ .style('fill', function (d, i) {
+ return colorScale(d);
+ });
+ legend.append('text')
+ .attr('x', 30)
+ .attr('y', 20)
+ .text(function (d, i) {
+ return d;
+ })
+ .attr('class', 'textselected')
+ .style('text-anchor', 'start')
+ .style('font-size', 12);
+
+ //Now add title
+ d3.select('chart').select('.legend')
+ .append('text')
+ .text(this.currentColor)
+ .style('font-size', 12);
+
+ }
+ else {
+ legend = d3.select('chart')
+ .select('g')
+ .append('g')
+ .attr('class', 'legend')
+ .attr('transform', 'translate(' + (width - 10 * margin.horizontal) + ', 10)');
+ // we need the min/max value and the color range. Let's also round.
+ var minHeatValue = Math.round(colorScale.domain()[0]);
+ var midHeatValue = Math.round(colorScale.domain()[1]);
+ var maxHeatValue = Math.round(colorScale.domain()[2]);
+ var minHeatColor = colorScale.range()[0];
+ var midHeatColor = colorScale.range()[1];
+ var maxHeatColor = colorScale.range()[2];
+ // TODO: Refactor all of this to map the domain values and loop through
+ legend.append('text')
+ .attr('x', 0)
+ .attr('y', 0)
+ .text('Expression value')
+ .style('font-size', 12);
+ legend.append('rect')
+ .attr('x', 20)
+ .attr('y', 10)
+ .attr('width', 20)
+ .attr('height', 10)
+ .style('fill', minHeatColor);
+ legend.append('text')
+ .attr('x', 50)
+ .attr('y', 20)
+ .text(minHeatValue)
+ .attr('class', 'text')
+ .style('text-anchor', 'start')
+ .style('font-size', 12);
+ legend.append('rect')
+ .attr('x', 20)
+ .attr('y', 20)
+ .attr('width', 20)
+ .attr('height', 10)
+ .style('fill', midHeatColor);
+ legend.append('text')
+ .attr('x', 50)
+ .attr('y', 30)
+ .text(midHeatValue)
+ .attr('class', 'text')
+ .style('text-anchor', 'start')
+ .style('font-size', 12);
+ legend.append('rect')
+ .attr('x', 20)
+ .attr('y', 30)
+ .attr('width', 20)
+ .attr('height', 10)
+ .style('fill', maxHeatColor);
+ legend.append('text')
+ .attr('x', 50)
+ .attr('y', 40)
+ .text(maxHeatValue)
+ .attr('class', 'text')
+ .style('text-anchor', 'start')
+ .style('font-size', 12);
+
+ }
+ d3.select('.legend').call(d3.behavior.drag() //Add drag behavior to legend
+ .on('drag', function () {
+ //Update the current position
+ var x = d3.event.x;
+ var y = d3.event.y;
+ var estimatedLegendWidth = 100
+
+ var figureXBorder = width - margin.horizontal- estimatedLegendWidth
+
+ var xadj = Math.min(x, figureXBorder);
+ if (xadj < 0 ){
+ xadj = 0
+ }
+
+ var yadj = Math.min(y, (height - margin.bottom))
+
+ if (yadj < 0 ){
+ yadj = 0
+ }
+
+ d3.select(this).attr('transform', 'translate(' + xadj + ',' + yadj + ')');
+ }
+ )
+ );
+ },
+
+ /**
+ * Build an array with lists of biomaterials sorted by value.
+ * if the color param is passed in as "color" it will build the domain from
+ * the color property instead of the sort property.
+ * @returns {Array}
+ */
+ buildPropertyValuesDomain: function (color) {
+ if (color === 'color') {
+ this.currentSortingProperty = $('#propertyColorMenu').find(':selected').text();
+ }
+ else {
+ this.currentSortingProperty = $('#propertySortMenu').find(':selected').text();
+ }
+
+ var list = [];
+
+ this.heatMap.map(function (biomaterial) {
+ // var name = biomaterial.name;
+ var propertyValue = biomaterial.properties[this.currentSortingProperty];
+ if (!propertyValue) {
+ propertyValue = 'Not set';
+ }
+ list.push(propertyValue);
+ }.bind(this));
+
+ // Return unique values only
+ return $.grep(list, function (v, i) {
+ return $.inArray(v, list) === i;
+ });
+ }
+ };
+})(jQuery);
diff --git a/js/heatmap-fix.js b/js/heatmap-fix.js
new file mode 100644
index 0000000..2ce21e4
--- /dev/null
+++ b/js/heatmap-fix.js
@@ -0,0 +1,296 @@
+(function ($) {
+ // To make draggable:
+ // Listening to plotly_click and then calling the appropriate restyle call
+ // should do the trick.
+ Drupal.behaviors.tripal_analysis_expression = {
+ /**
+ * Auto triggered by Drupal when the document is ready.
+ *
+ * @param context
+ * @param settings
+ */
+ attach: function (context, settings) {
+ this.settings = settings.tripal_analysis_expression;
+ this.cache = {};
+ if (!this.settings) {
+ return;
+ }
+
+ this.data = this.settings.data;
+
+ // Build drop down UI
+ var $selectContainer = $('#select_analysis');
+ this.$select = $('');
+ $selectContainer
+ .append(this.$select)
+ .attr('id', 'analysis_selector');
+
+ Object.keys(this.data.analyses).map(function (key) {
+ var $option = $('', {
+ value: key
+ }).text(this.data.analyses[key]);
+ this.$select.append($option);
+ }.bind(this));
+
+ this.selectedAnalysis = parseInt(this.$select.val());
+
+ // Set the download link
+ this.updateDownloadLink();
+
+ // Add the properties sort dropdown
+ this.createPropertiesDropdown();
+
+ this.setup();
+ },
+
+ /**
+ * Deals with changes to the analysis dropdown
+ * to update the download link
+ */
+ updateDownloadLink: function () {
+ // Get analysis and build link for download
+ var feature_ids = Object.keys(this.data.data[this.selectedAnalysis]).map(function (key) {
+ return key;
+ }).join(',');
+
+ var link = this.settings.baseURL;
+ link += '/analysis-expression/download?feature_ids=' + feature_ids;
+ link += '&analysis_id=' + this.selectedAnalysis;
+ $('#heatmap_download').attr('href', link);
+ },
+
+ /**
+ * Create the sort by property dropdown
+ * and append to the page.
+ */
+ createPropertiesDropdown: function () {
+ // Create the dropdown
+ this.$propsSelect = $('');
+
+ // Add the dropdown to the page
+ $('#select_props').append(this.$propsSelect);
+
+ // Initialize the props
+ this.updatePropsDropdown();
+
+ this.$propsSelect.on('change', function (e) {
+ this.selectedProp = e.target.value;
+ this.draw(this.constructHeatMapData());
+ }.bind(this));
+ },
+
+ /**
+ * Respond to changes in analysis selector
+ */
+ updatePropsDropdown: function () {
+ this.$propsSelect.html('');
+ var props = this.data.properties[this.selectedAnalysis];
+ Object.keys(props).map(function (key) {
+ var option = $('', {
+ value: key
+ }).text(props[key]);
+
+ this.$propsSelect.append(option);
+ }.bind(this));
+
+ this.selectedProp = this.$propsSelect.val() || false;
+ this.draw(this.constructHeatMapData());
+ },
+
+ /**
+ * Creates the heat map data structure
+ *
+ * @return {Object}
+ */
+ constructHeatMapData: function () {
+ var expression = this.data;
+ var sortBy = this.selectedProp;
+
+ // Extract data, features and biomaterials for the current analysis
+ var data = {
+ biomaterials: expression.biomaterials[this.selectedAnalysis],
+ features: expression.features[this.selectedAnalysis],
+ matrix: expression.data[this.selectedAnalysis]
+ };
+
+ // Sort by selected prop if available
+ var biomaterialKeys = Object.keys(data.biomaterials);
+ if (sortBy) {
+ biomaterialKeys.sort(function (a, b) {
+ var props1 = data.biomaterials[a].props[sortBy];
+ var props2 = data.biomaterials[b].props[sortBy];
+
+ // Both biomaterials have the prop
+ if (props1 && props2) {
+ return this.compareByType(props1.value, props2.value);
+ }
+
+ // Only the first biomaterial has the prop
+ if (props1) {
+ return -1;
+ }
+
+ // Only the second biomaterial has the prop
+ if (props2) {
+ return 1;
+ }
+
+ // They both do not have the prop
+ return 0;
+ }.bind(this));
+ }
+
+ // Create the X axis
+ var biomaterials = biomaterialKeys.map(function (biomaterial_id) {
+ return data.biomaterials[biomaterial_id].name || '';
+ }.bind(this));
+
+ // Get the Y axis
+ var features = Object.keys(data.features).map(function (key) {
+ return data.features[key];
+ }.bind(this));
+
+ var values = [];
+ var tooltip = [];
+
+ Object.keys(data.features).map(function (feature_id) {
+ var row = [];
+ var text = [];
+ biomaterialKeys.map(function (biomaterial_id) {
+ if (typeof data.matrix[feature_id][biomaterial_id] !== 'undefined') {
+ row.push(parseFloat(data.matrix[feature_id][biomaterial_id]));
+ }
+ else {
+ row.push(0);
+ }
+
+ text.push(this.formatTooltipEntry(data.biomaterials[biomaterial_id], sortBy));
+ }.bind(this));
+
+ values.push(row);
+ tooltip.push(text);
+ }.bind(this));
+
+ return [{
+ x: biomaterials,
+ y: features,
+ z: values,
+ text: tooltip,
+ type: 'heatmap'
+ }];
+ },
+
+ /**
+ * Add information to the tooltip.
+ *
+ * @param {Object} biomaterial
+ * @param {String} sortBy
+ * @return {string}
+ */
+ formatTooltipEntry: function (biomaterial, sortBy) {
+ var props = 'None available';
+ if (biomaterial.props) {
+ props = Object.keys(biomaterial.props).map(function (key) {
+ var prop = biomaterial.props[key];
+ var label = prop.name;
+ if (key === sortBy) {
+ label = '' + label + '';
+ }
+ return label + ': ' + prop.value;
+ }).join('
');
+ }
+
+ return [
+ 'Name: ' + biomaterial.name,
+ 'Collected By:' + biomaterial.contact,
+ 'Description: ' + biomaterial.description,
+ 'Properties:',
+ props
+ ].join('
');
+ },
+
+ /**
+ * Set the scene and create the heat map
+ */
+ setup: function () {
+ var _that = this;
+ this.$select.on('change', function () {
+ _that.selectedAnalysis = parseInt($(this).val());
+ _that.updatePropsDropdown.call(_that);
+ _that.updateDownloadLink.call(_that);
+ });
+
+ var node = Plotly.d3.select('#expression_heat_map_canvas').style({
+ width: '100%'
+ }).node();
+
+ var download_link = $('#heatmap_download');
+ var download_message = $('');
+ download_link.after(download_message);
+ download_link.click(function (e) {
+ e.preventDefault();
+ var src = $(this).attr('href');
+ download_message.html(' Creating file. Download will start automatically ...');
+ var iframe = $('', {
+ src: src,
+ width: 1,
+ height: 1
+ });
+ $('body').append(iframe);
+ });
+
+ $(window).on('resize', function () {
+ Plotly.Plots.resize(node);
+ });
+ },
+
+ /**
+ * Draws the heat map using the given data.
+ *
+ * @param {Object} data
+ */
+ draw: function (data) {
+ var left_margin = (this.data.maxLengths.feature * 14) / 2;
+ var bottom_margin = (this.data.maxLengths.biomaterial * 16) / 2;
+ var layout = {
+ title: this.data.analyses[this.selectedAnalysis] + ' Expression',
+ margin: {
+ l: left_margin,
+ b: bottom_margin
+ }
+ };
+
+ Plotly.newPlot('expression_heat_map_canvas', data, layout);
+ },
+
+ compareByType: function (a, b) {
+ var v1, v2;
+
+ if (typeof a === 'string') {
+ // Ignore case
+ v1 = a.toLowerCase();
+ }
+ else {
+ v1 = a;
+ }
+
+ if (typeof b === 'string') {
+ // Ignore case
+ v2 = b.toLowerCase();
+ }
+ else {
+ v2 = b;
+ }
+
+ if (v1 < v2) {
+ return 1;
+ }
+
+ if (v1 > v2) {
+ return -1;
+ }
+
+ return 0;
+ }
+ };
+})(jQuery);
diff --git a/js/heatmap-search-fix.js b/js/heatmap-search-fix.js
new file mode 100644
index 0000000..71470f6
--- /dev/null
+++ b/js/heatmap-search-fix.js
@@ -0,0 +1,144 @@
+(function ($) {
+ Drupal.behaviors.tripal_analysis_expression_heatmap_search = {
+ attach: function (context, settings) {
+ $(function () {
+ this.setupSearch(settings);
+ }.bind(this));
+ },
+
+ setupSearch: function (settings) {
+ this.term_field = $('#heatmap-search_term');
+ this.organism_field = $('#heatmap-search-organism');
+ this.results_block = $('#feature-heatmap-search-results');
+ this.feature_textarea = $('#heatmap_feature_uniquename');
+ this.request = null;
+ this.base_url = settings.heatmap_search.base_url;
+ this.reset();
+
+ this.term_field.on('keyup', this.search.bind(this));
+ this.organism_field.on('change', this.search.bind(this));
+
+ var that = this;
+
+ $(document).on('click', '.heatmap-results-item', function (event) {
+ var link = $(this);
+
+ if (link.is('.disabled')) {
+ return;
+ }
+
+ that.chooseFeature(link.data('value'));
+ link.addClass('disabled');
+ });
+ },
+
+ reset: function () {
+ this.results_block.html('Type a search term above to search for features
');
+ },
+
+ loadingShow: function () {
+ $('#heatmap-form-throbber').addClass('ajax-progress').addClass('ajax-progress-throbber');
+ },
+
+ loadingHide: function () {
+ $('#heatmap-form-throbber').removeClass('ajax-progress').removeClass('ajax-progress-throbber');
+ },
+
+ search: function (event) {
+ var terms = this.term_field.val();
+ var organism = this.organism_field.val().toString();
+
+ if (terms.length === 0 && organism.length === 0) {
+ return this.reset();
+ }
+
+ if(terms.length > 0) {
+ // Accept only alphanumeric characters and backspace
+ var input = String.fromCharCode(event.keyCode);
+ if (!/[a-zA-Z0-9-_ ]/.test(input) && event.keyCode !== 8) {
+ return;
+ }
+ }
+
+ if (this.request !== null) {
+ this.request.abort();
+ }
+
+ this.request = new window.XMLHttpRequest();
+
+ this.loadingShow();
+ $.ajax({
+ url: this.base_url + '/analysis-expression/heatmap/search',
+ data: {
+ terms: terms,
+ organism: organism
+ },
+ success: this.renderSearchResults.bind(this),
+ error: function (a, b, c) {
+ if (a.status === 0) {
+ return;
+ }
+ this.loadingHide();
+ console.log('Search failed with status code: ' + a.status, b, c);
+ }.bind(this),
+ type: 'get',
+ dataType: 'json',
+ xhr: function () {
+ return this.request;
+ }.bind(this)
+ });
+ },
+
+ renderSearchResults: function (response) {
+ this.loadingHide();
+
+ var html = 'No results found
';
+ if (response.data.length > 0) {
+ html = '';
+ html += '';
+ html += response.data.map(this.renderRow.bind(this)).join('');
+ html += '
';
+ }
+ this.results_block.html(html);
+ },
+
+ renderRow: function (row) {
+ var name = row.uniquename;
+
+ var disabled = this.getFeatures().indexOf(name) > -1 ? ' disabled' : '';
+
+ var html = ''
+ + name
+ + 'Organism: ' + row.common_name + '
';
+
+ if (row.accession) {
+ html += 'Accession: ' + row.accession + '
';
+ }
+
+ html += '';
+
+ return html;
+ },
+
+ chooseFeature: function (feature) {
+ var value = this.getFeatures();
+ if (value.length === 0) {
+ this.feature_textarea.val(feature);
+ return;
+ }
+ value.push(feature);
+ this.feature_textarea.val(value.join(',').trim());
+ },
+
+ getFeatures: function () {
+ var value = this.feature_textarea.val().trim();
+ if (value.length === 0) {
+ return [];
+ }
+
+ return value.split(',').map(function (m) {
+ return m.trim();
+ });
+ }
+ };
+})(jQuery);
diff --git a/tripal_bipaa_ui.install b/tripal_bipaa_ui.install
index a09e739..ddde767 100644
--- a/tripal_bipaa_ui.install
+++ b/tripal_bipaa_ui.install
@@ -28,13 +28,12 @@ function tripal_bipaa_ui_install() {
// TEMP: need to setup at least an alias (temp bug fix)
// https://github.com/tripal/tripal/issues/727
// Dict key needs to be in tripal_term
- // Some links are malformed.. variable not set?
$aliases = array(
"organism" => "organism/[taxrank__genus]/[taxrank__species]",
- "mRNA" => "feature/[obi__organism,TAXRANK:0000005]/[obi__organism,TAXRANK:0000006]/[rdfs__type]/[schema__name]",
+ "mRNA" => "feature/[obi__organism,TAXRANK:0000005]/[obi__organism,TAXRANK:0000006]/[rdfs__type]/[data__identifier]",
"Analysis" => "analysis/[TripalEntity__entity_id]",
- "polypeptide" => "feature/[obi__organism,TAXRANK:0000005]/[obi__organism,TAXRANK:0000006]/[rdfs__type]/[schema__name]"
+ "polypeptide" => "feature/[obi__organism,TAXRANK:0000005]/[obi__organism,TAXRANK:0000006]/[rdfs__type]/[data__identifier]"
);
$includes = array(
@@ -69,9 +68,22 @@ function tripal_bipaa_ui_install() {
),
);
+ $organism_field_list = array(
+ array(
+ "wrapper_name" => "GO Reports",
+ "wrapper_machine_name" =>"go",
+ "field_machine_name" => "local__go_results",
+ ),
+ array(
+ "wrapper_name" => "Biomaterial Browser",
+ "wrapper_machine_name" =>"biomaterials",
+ "field_machine_name" => "sep__biological_sample",
+ )
+ );
+
setup_fields("polypeptide", $field_list);
setup_fields("mRNA", $field_list);
-
+ setup_fields("organism", $organism_field_list);
// Create a custom menu, to avoid unwanted modifications by other modules
create_menu('Content Search', 'custom_search', '');
@@ -87,6 +99,13 @@ function tripal_bipaa_ui_install() {
disable_block('navigation');
disable_block('form');
+ // Need to disable field_groups and their children
+ // Hopefully these group names are not random (they are, need to use the label)..
+
+ disable_fields_groups('organism', ['Annotations', 'Cross Reference', 'Publication', 'Relationship'], True, True);
+ disable_fields_groups('mRNA',['Contact', 'Publication', 'Location on Map'], True, True);
+ disable_fields_groups('polypeptide',['Contact', 'Publication', 'Location on Map'], True, True);
+
//Clear cache
menu_cache_clear_all();
};
@@ -102,6 +121,7 @@ function tripal_bipaa_ui_install() {
function tripal_bipaa_ui_modules_enabled($modules){
refresh_fields("polypeptide");
refresh_fields("mRNA");
+ refresh_fields("organism");
drupal_flush_all_caches();
};
@@ -171,6 +191,8 @@ function set_panel_children($bundle_name, $wrapper_name, $field_name){
function set_panels($bundle_name, $fields_list){
// Rewrited tripal_ds_update_ds_layout
+ // Fix was merge in tripal, so we should use the main function
+
$ds_identifier = 'TripalEntity|'.$bundle_name.'|default';
@@ -210,6 +232,94 @@ function set_panels($bundle_name, $fields_list){
};
};
+function disable_fields_groups($entity_name, $field_group_list=[], $use_labels=False, $disable_children=False){
+ // There is no in house function to disable fields it seems..
+ // Need to revert tripal_ds_update_ds_layout
+ // Need to get children for every field_group
+
+ // We do not know the id of the field (random number)
+ // We can look into the label (which should not change..)
+
+ $bundle_id = get_bundle_id($entity_name);
+ $bundle = tripal_load_bundle_entity(array('id' => $bundle_id));
+ $bundle_name = $bundle->name;
+
+ if($use_labels){
+ // We need to extract the id : iterate on all field_groups for the entity and bundle
+ $field_group_labels = array();
+ $results = db_select('field_group', 'fg')
+ ->fields('fg')
+ ->condition('bundle', $bundle_name, '=')
+ ->condition('entity_type', 'TripalEntity', '=')
+ ->execute()->fetchAll();
+ if($results){
+ foreach ($results as $field_group) {
+ $field_group_data = unserialize($field_group->data);
+ if(in_array($field_group_data["label"], $field_group_list)){
+ $field_group_labels[] = $field_group->group_name;
+ }
+ }
+ }
+ $field_group_list= $field_group_labels;
+
+ }
+ if($disable_children){
+ $children = array();
+ foreach($field_group_list as $field_group){
+ // Get children for each field group
+ $field_group_id = $field_group.'|TripalEntity|'.$bundle_name.'|default';
+
+ $result = db_select('field_group', 'fg')
+ ->fields('fg', array('data'))
+ ->condition('fg.identifier', $field_group_id, '=')
+ ->execute()
+ ->fetchObject();
+
+ if($result) {
+ $layout_info = unserialize($result->data);
+ $children = array_merge($children, $layout_info["children"]);
+ }
+ }
+ if(!empty($children)){
+ // Loop to get children of children (if existing)
+ disable_fields_groups($entity_name, $children, False, True);
+ }
+ $field_group_list = array_merge($field_group_list, $children);
+ }
+
+ $ds_identifier = 'TripalEntity|'.$bundle_name.'|default';
+
+ $result = db_select('ds_layout_settings', 'ds')
+ ->fields('ds', array('settings'))
+ ->condition('ds.id', $ds_identifier, '=')
+ ->execute()
+ ->fetchObject();
+
+ //If the layout exists unserialize it.
+ if(!empty($result)) {
+ $layout_info = $result->settings;
+ $layout_info = unserialize($layout_info);
+
+
+ $region_array = array_diff($layout_info['regions']['right'], $field_group_list);
+ $field_array = array_diff_key($layout_info['fields'], $field_group_list);
+
+ // Need to reindex first array
+ $layout_info['regions']['right'] = array_values($region_array);
+ $layout_info['fields'] = $field_array;
+
+
+ //Update the ds_layout_settings table with the new layout info.
+ db_update('ds_layout_settings')
+ ->fields(array(
+ 'settings' => serialize($layout_info),
+ ))
+ ->condition('ds_layout_settings.id', $ds_identifier, '=')
+ ->execute();
+ };
+}
+
+
function refresh_fields($entity_name){
$bundle_id = get_bundle_id($entity_name);
$bundle = tripal_load_bundle_entity(array('id' => $bundle_id));
diff --git a/tripal_bipaa_ui.module b/tripal_bipaa_ui.module
index f5759c4..6e0a13d 100644
--- a/tripal_bipaa_ui.module
+++ b/tripal_bipaa_ui.module
@@ -14,6 +14,21 @@ function tripal_bipaa_ui_menu() {
'type' => MENU_CALLBACK,
);
+ $items['analysis-expression/heatmap/search'] = [
+ 'title' => '',
+ 'access arguments' => ['access content'],
+ 'page callback' => 'tripal_analysis_expression_search_features_callback',
+ 'type' => MENU_CALLBACK,
+ ];
+
+ $items['analysis-expression/download'] = [
+ 'title' => '',
+ 'access arguments' => ['access content'],
+ 'page callback' => 'analysis_expression_data_downloader::callback',
+ 'type' => MENU_CALLBACK,
+ ];
+
+
return $items;
}
@@ -146,45 +161,209 @@ function tripal_bipaa_ui_views_default_views_alter(&$views) {
3 => 0,
);
+ // Might as well not duplicate the code
+ $gene_handler = array(
+ "mRNA" => array(
+ "view" => $views['mRNA_search'],
+ "table" => 'SO__0000234'
+ ),
+ "Polypeptide" => array(
+ "view" => $views['Polypeptide_search'],
+ "table" => 'SO__0000104'
+ )
+ );
- //mRNA
- $handler = $views['mRNA_search'];
- //Cleanup
- unset($handler->display['default']->display_options['footer']['tripal_area_collections']);
- unset($handler->display['default']->display_options['fields']['data__accession']);
- unset($handler->display['default']->display_options['fields']['schema__alternate_name']);
- unset($handler->display['default']->display_options['filters']['schema__name']['expose']['use_operator']);
- unset($handler->display['default']->display_options['filters']['data__identifier']['expose']['use_operator']);
- unset($handler->display['default']->display_options['filters']['data__accession']);
- unset($handler->display['default']->display_options['filters']['obi__organism']['expose']['use_operator']);
-
- // Set up results without input
- $handler->display['default']->display_options['exposed_form']['type'] = 'basic';
- // Change field name
- $handler->display['default']->display_options['filters']['data__identifier']['expose']['label'] = 'Unique Name';
- $handler->display['default']->display_options['fields']['data__identifier']['label'] = 'Unique Name';
+ foreach ($gene_handler as $key => $value){
+
+ $handler = $value["view"];
+ $table = $value["table"];
+ //Cleanup
+ unset($handler->display['default']->display_options['footer']['tripal_area_collections']);
+ unset($handler->display['default']->display_options['fields']['data__accession']);
+ unset($handler->display['default']->display_options['fields']['schema__alternate_name']);
+ unset($handler->display['default']->display_options['filters']['schema__name']['expose']['use_operator']);
+ unset($handler->display['default']->display_options['filters']['data__identifier']['expose']['use_operator']);
+ unset($handler->display['default']->display_options['filters']['data__accession']);
+ unset($handler->display['default']->display_options['filters']['obi__organism']['expose']['use_operator']);
+ unset($handler->display['default']->display_options['fields']);
+ unset($handler->display['default']->display_options['filters']);
+ // Set up results without input
+ $handler->display['default']->display_options['exposed_form']['type'] = 'basic';
+
+ $handler->display['default']->display_options['style_options']['columns'] = array(
+ 'entity_id' => 'entity_id',
+ 'data__identifier' => 'data__identifier',
+ 'schema__name' => 'schema__name',
+ 'data__accession' => 'data__accession',
+ 'obi__organism' => 'obi__organism',
+ 'schema__alternate_name' => 'schema__alternate_name',
+ );
+ $handler->display['default']->display_options['style_options']['default'] = '-1';
+ $handler->display['default']->display_options['style_options']['info'] = array(
+ 'entity_id' => array(
+ 'sortable' => 1,
+ 'separator' => '',
+ ),
+ 'data__identifier' => array(
+ 'separator' => '',
+ 'sortable' => 1,
+ 'default_sort_order' => 'asc',
+ ),
+ 'schema__name' => array(
+ 'separator' => '',
+ 'sortable' => 1,
+ 'default_sort_order' => 'asc',
+ ),
+ 'data__accession' => array(
+ 'separator' => '',
+ 'sortable' => 1,
+ 'default_sort_order' => 'asc',
+ ),
+ 'obi__organism' => array(
+ 'separator' => '',
+ 'sortable' => 1,
+ 'default_sort_order' => 'asc',
+ ),
+ 'schema__alternate_name' => array(
+ 'separator' => '',
+ 'sortable' => 1,
+ 'default_sort_order' => 'asc',
+ ),
+ );
+ /* Field: Entity ID */
+ $handler->display['default']->display_options['fields']['entity_id']['id'] = 'entity_id';
+ $handler->display['default']->display_options['fields']['entity_id']['table'] = $table;
+ $handler->display['default']->display_options['fields']['entity_id']['field'] = 'entity_id';
+ $handler->display['default']->display_options['fields']['entity_id']['exclude'] = TRUE;
+ /* Field: Genus */
+ $handler->display['default']->display_options['fields']['obi__organism.TAXRANK:0000005']['id'] = 'obi__organism.TAXRANK:0000005';
+ $handler->display['default']->display_options['fields']['obi__organism.TAXRANK:0000005']['table'] = $table;
+ $handler->display['default']->display_options['fields']['obi__organism.TAXRANK:0000005']['field'] = 'obi__organism.TAXRANK:0000005';
+ $handler->display['default']->display_options['fields']['obi__organism.TAXRANK:0000005']['label'] = '';
+ $handler->display['default']->display_options['fields']['obi__organism.TAXRANK:0000005']['exclude'] = TRUE;
+ $handler->display['default']->display_options['fields']['obi__organism.TAXRANK:0000005']['element_label_colon'] = FALSE;
+ /* Field Species */
+ $handler->display['default']->display_options['fields']['obi__organism.TAXRANK:0000006']['id'] = 'obi__organism.TAXRANK:0000006';
+ $handler->display['default']->display_options['fields']['obi__organism.TAXRANK:0000006']['table'] = $table;
+ $handler->display['default']->display_options['fields']['obi__organism.TAXRANK:0000006']['field'] = 'obi__organism.TAXRANK:0000006';
+ $handler->display['default']->display_options['fields']['obi__organism.TAXRANK:0000006']['label'] = '';
+ $handler->display['default']->display_options['fields']['obi__organism.TAXRANK:0000006']['exclude'] = TRUE;
+ $handler->display['default']->display_options['fields']['obi__organism.TAXRANK:0000006']['element_label_colon'] = FALSE;
+ /* Field Identifier */
+ $handler->display['default']->display_options['fields']['data__identifier']['id'] = 'data__identifier';
+ $handler->display['default']->display_options['fields']['data__identifier']['table'] = $table;
+ $handler->display['default']->display_options['fields']['data__identifier']['field'] = 'data__identifier';
+ $handler->display['default']->display_options['fields']['data__identifier']['label'] = 'Unique Name';
+ $handler->display['default']->display_options['fields']['data__identifier']['alter']['alter_text'] = TRUE;
+ $handler->display['default']->display_options['fields']['data__identifier']['alter']['text'] = '[data__identifier]';
+ $handler->display['default']->display_options['fields']['data__identifier']['alter']['make_link'] = TRUE;
+ $handler->display['default']->display_options['fields']['data__identifier']['alter']['path'] = 'feature/[obi__organism.TAXRANK:0000005]/[obi__organism.TAXRANK:0000006]/'.$key.'/[data__identifier]';
+ /* Field Name */
+ $handler->display['default']->display_options['fields']['schema__name']['id'] = 'schema__name';
+ $handler->display['default']->display_options['fields']['schema__name']['table'] = $table;
+ $handler->display['default']->display_options['fields']['schema__name']['field'] = 'schema__name';
+ $handler->display['default']->display_options['fields']['schema__name']['alter']['alter_text'] = TRUE;
+ $handler->display['default']->display_options['fields']['schema__name']['alter']['text'] = '[schema__name]';
+ $handler->display['default']->display_options['fields']['schema__name']['alter']['make_link'] = TRUE;
+ $handler->display['default']->display_options['fields']['schema__name']['alter']['path'] = 'feature/[obi__organism.TAXRANK:0000005]/[obi__organism.TAXRANK:0000006]/'.$key.'/[data__identifier]';
+ /* Field Sequence Length */
+ $handler->display['default']->display_options['fields']['data__sequence_length']['id'] = 'data__sequence_length';
+ $handler->display['default']->display_options['fields']['data__sequence_length']['table'] = $table;
+ $handler->display['default']->display_options['fields']['data__sequence_length']['field'] = 'data__sequence_length';
+ /* Field Organism */
+ $handler->display['default']->display_options['fields']['obi__organism']['id'] = 'obi__organism';
+ $handler->display['default']->display_options['fields']['obi__organism']['table'] = $table;
+ $handler->display['default']->display_options['fields']['obi__organism']['field'] = 'obi__organism';
+ $handler->display['default']->display_options['fields']['obi__organism']['alter']['alter_text'] = TRUE;
+ $handler->display['default']->display_options['fields']['obi__organism']['alter']['text'] = '[obi__organism.TAXRANK:0000005] [obi__organism.TAXRANK:0000006]';
+ $handler->display['default']->display_options['fields']['obi__organism']['alter']['make_link'] = TRUE;
+ $handler->display['default']->display_options['fields']['obi__organism']['alter']['path'] = 'organism/[obi__organism.TAXRANK:0000005]/[obi__organism.TAXRANK:0000006]';
+ /* Sort criterion: : Identifier */
+ $handler->display['default']->display_options['sorts']['priority']['id'] = 'schema__alternate_name';
+ $handler->display['default']->display_options['sorts']['priority']['table'] = $table;
+ $handler->display['default']->display_options['sorts']['priority']['field'] = 'data__identifier';
+ /* Filter criterion: Published */
+ $handler->display['default']->display_options['filters']['status']['id'] = 'status';
+ $handler->display['default']->display_options['filters']['status']['table'] = $table;
+ $handler->display['default']->display_options['filters']['status']['field'] = 'status';
+ $handler->display['default']->display_options['filters']['status']['value'] = '1';
+ /* Filter criterion: Identifier */
+ $handler->display['default']->display_options['filters']['data__identifier']['id'] = 'data__identifier';
+ $handler->display['default']->display_options['filters']['data__identifier']['table'] = $table;
+ $handler->display['default']->display_options['filters']['data__identifier']['field'] = 'data__identifier';
+ $handler->display['default']->display_options['filters']['data__identifier']['operator'] = 'contains';
+ $handler->display['default']->display_options['filters']['data__identifier']['group'] = 1;
+ $handler->display['default']->display_options['filters']['data__identifier']['exposed'] = TRUE;
+ $handler->display['default']->display_options['filters']['data__identifier']['expose']['operator_id'] = 'data__identifier_op';
+ $handler->display['default']->display_options['filters']['data__identifier']['expose']['label'] = 'Unique Name';
+ $handler->display['default']->display_options['filters']['data__identifier']['expose']['operator'] = 'data__identifier_op';
+ $handler->display['default']->display_options['filters']['data__identifier']['expose']['identifier'] = 'data__identifier';
+ $handler->display['default']->display_options['filters']['data__identifier']['expose']['remember_roles'] = array(
+ 2 => '2',
+ 1 => 0,
+ 3 => 0,
+ );
+ /* Filter criterion: Name */
+ $handler->display['default']->display_options['filters']['schema__name']['id'] = 'schema__name';
+ $handler->display['default']->display_options['filters']['schema__name']['table'] = $table;
+ $handler->display['default']->display_options['filters']['schema__name']['field'] = 'schema__name';
+ $handler->display['default']->display_options['filters']['schema__name']['operator'] = 'contains';
+ $handler->display['default']->display_options['filters']['schema__name']['group'] = 1;
+ $handler->display['default']->display_options['filters']['schema__name']['exposed'] = TRUE;
+ $handler->display['default']->display_options['filters']['schema__name']['expose']['operator_id'] = 'schema__name_op';
+ $handler->display['default']->display_options['filters']['schema__name']['expose']['label'] = 'Name';
+ $handler->display['default']->display_options['filters']['schema__name']['expose']['operator'] = 'schema__name_op';
+ $handler->display['default']->display_options['filters']['schema__name']['expose']['identifier'] = 'schema__name';
+ $handler->display['default']->display_options['filters']['schema__name']['expose']['remember_roles'] = array(
+ 2 => '2',
+ 1 => 0,
+ 3 => 0,
+ );
+ /* Filter criterion: Organism */
+ $handler->display['default']->display_options['filters']['obi__organism']['id'] = 'obi__organism';
+ $handler->display['default']->display_options['filters']['obi__organism']['table'] = $table;
+ $handler->display['default']->display_options['filters']['obi__organism']['field'] = 'obi__organism';
+ $handler->display['default']->display_options['filters']['obi__organism']['operator'] = 'contains';
+ $handler->display['default']->display_options['filters']['obi__organism']['group'] = 1;
+ $handler->display['default']->display_options['filters']['obi__organism']['exposed'] = TRUE;
+ $handler->display['default']->display_options['filters']['obi__organism']['expose']['operator_id'] = 'obi__organism_op';
+ $handler->display['default']->display_options['filters']['obi__organism']['expose']['label'] = 'Organism';
+ $handler->display['default']->display_options['filters']['obi__organism']['expose']['operator'] = 'obi__organism_op';
+ $handler->display['default']->display_options['filters']['obi__organism']['expose']['identifier'] = 'obi__organism';
+ $handler->display['default']->display_options['filters']['obi__organism']['expose']['remember_roles'] = array(
+ 2 => '2',
+ 1 => 0,
+ 3 => 0,
+ );
+
+ };
+};
- //Polypeptide
- $handler = $views['Polypeptide_search'];
- //Cleanup
- unset($handler->display['default']->display_options['footer']['tripal_area_collections']);
- unset($handler->display['default']->display_options['fields']['data__accession']);
- unset($handler->display['default']->display_options['fields']['schema__alternate_name']);
- unset($handler->display['default']->display_options['filters']['schema__name']['expose']['use_operator']);
- unset($handler->display['default']->display_options['filters']['data__identifier']['expose']['use_operator']);
- unset($handler->display['default']->display_options['filters']['data__accession']);
- unset($handler->display['default']->display_options['filters']['obi__organism']['expose']['use_operator']);
+function tripal_bipaa_ui_form_alter(&$form, &$form_state, $form_id){
+ switch ($form_id){
+ case 'feature_heatmap_form':
+ // Might be better to fill it with proper value, but it would make sql database calls..
+ unset($form['example_button']);
+ unset($form['heatmap_feature_uniquename']['#attributes']['placeholder']);
+ unset($form['heatmap_feature_uniquename']['#description']);
+ };
+}
- // Set up results without input
- $handler->display['default']->display_options['exposed_form']['type'] = 'basic';
- // Change field name
- $handler->display['default']->display_options['filters']['data__identifier']['expose']['label'] = 'Unique Name';
- $handler->display['default']->display_options['fields']['data__identifier']['label'] = 'Unique Name';
+function tripal_bipaa_ui_js_alter(&$javascript){
+ $scripts = array(
+ 'heatmap-search.js' => 'heatmap-search-fix.js',
+ 'heatmap.js' => 'heatmap-fix.js',
+ 'expression.js' => 'expression-fix.js'
+ );
+ $old_script_path = drupal_get_path('module', 'tripal_analysis_expression') . '/theme/js/';
+ $new_script_path = drupal_get_path('module', 'tripal_bipaa_ui') . '/js/';
-
+ foreach($scripts as $key => $value){
+ if(isset($javascript[$old_script_path . $key])){
+ $javascript[$old_script_path . $key]['data'] = $new_script_path . $value;
+ };
+ }
};
-
-