d3.js绘制聚类热图+分组

本文介绍如何使用D3.js结合jQuery插件绘制热图,并详细解释了热图的各项参数配置方法,包括颜色渐变、标签显示及聚类树等特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

实现如下效果:

聚类热图+分组


一、json数据:
 

{
    
	"data":[
        [-0.0282, 0.0545, 0.2327, 0.2276, 0.1717, -0.1646, -0.1646, -0.1646, -0.1646],
		[-0.0431, -0.0431, -0.0431, -0.0431, -0.0431, 0.0426, 0.1371, 0.0788, -0.0431],
		[-0.0775, -0.2289, -0.2802, -0.2255, 0.2543, -0.0343, -0.0745, 0.196, 0.4706],
        [-0.0775, -0.2289, -0.2802, -0.2255, 0.2543, -0.0343, -0.0745, 0.196, 0.4706],
        [-0.0775, -0.2289, -0.2802, -0.2255, 0.2543, -0.0343, -0.0745, 0.196, 0.4706],
        [-0.0775, -0.2289, -0.2802, -0.2255, 0.2543, -0.0343, -0.0745, 0.196, 0.4706],
        [-0.0775, -0.2289, -0.2802, -0.2255, 0.2543, -0.0343, -0.0745, 0.196, 0.4706]
    ],
    "params":{
        "title": "这个是热图的标题测试",
        "start_color": "#1d953f",
		"middle_color": "#130c0e",
		"end_color": "#ed1941",
        "show_gap":true,
        "show_label":true,
        "show_column_label": true,
        "show_row_label": true,
        "rows": ["ENSMUSG00000092137", "ENSMUSG00000090942", "ENSMUSG00000006574", "ENSMUSG00000006573", "ENSMUSG00000006572", "ENSMUSG00000006571", "ENSMUSG00000006570"],
        "row_tree": "(ENSMUSG00000006574:0.5283035817,(ENSMUSG00000090942:0.3213435808,ENSMUSG00000092137:0.3213435808):0.2069600009);",
        "row_tree_width":50,
        
        "columns": ["C_1fsdds", "B_2weewwrweeewe", "B_1ewewwweweweeweew", "B_3ewrwewewe", "C_3ewerewrwe", "A_3rewreww", "A_1reweew", "A_2ewrweewwwweww", "C_2rewerewwwerwerwee"],
        "column_tree": "(((C_1:0.0005501041254,B_2:0.0005501041254):0.01920472318,(B_1:0.001174629219,B_3:0.001174629219):0.01858019809):0.7830263125,(C_3:0.5975157388,((A_3:0.03500377534,A_1:0.03500377534):0.2755466439,(A_2:0.07162426047,C_2:0.07162426047):0.2389261588):0.2869653195):0.205265401);",
        "column_tree_height":50,

        "row_group":["#FF0000", "#FF0000", "#00FF00", "#00FF00", "#00FF00", "#00FF00", "#00FF00"],
        "row_group_width":30,
        "row_group_location":"right",
        
        "column_group":["#FF0000", "#FF0000", "#00FF00","#FF0000", "#FF0000", "#00FF00","#FF0000", "#FF0000", "#00FF00"],
        "column_group_height":30,
        "column_group_location":"bottom",

        "row_legend_name":["Taxon_1","Taxon_2","Taxon_3"],
        "column_legend_name":["C","N","S"]
    },
    "size" : {
        "width":50,
        "height":50
    }
}
        

参数说明:

  • 用途:热图(聚类)(不需要指定的属性可以去掉)
  • *data,二维数组,一维代表一行
  • title:标题
  • *start_color[初始颜色],end_color[结束颜色],middle_color[中间过度色,非必填]
  • show_gap:是否显示边框,默认false
  • show_label:是否显示数值标签,默认false
  • show_column_label:是否显示列的标签,默认false
  • show_row_label:是否显示行的标签,默认false
  • *columns:列的标签名称,一维数组
  • *rows:行的标签名称,一维数组
  • row_tree:行的聚类树
  • row_tree_width:行聚类树的宽度
  • column_tree:列的聚类树
  • column_tree_width:列聚类树的高度
  • row_group:行的分组
  • row_group_width:行的分组的宽度
  • row_group_location:行的分组的位置,默认left[左],可以调整为right[右]
  • column_group:列的分组
  • column_group_height:列的分组的高度
  • column_group_location:行的分组的位置,默认top[上],可以调整为bottom[下]
  • row_legend_name:行的组的图例名称
  • column_legend_name:列的组的图例名称

以下为toolip的样式:

<style>
.heatmap_tooltip{  
    font-family:simsun;  
    font-size:13px;  
    width:120;  
    height:auto;  
    position:absolute;   
    text-align:left;  
    border-style:solid;  
    border-width:1px;  
    background-color:white;  
    border-radius:5px;    
}  
</style>


二、用到的js插件
#jquery插件

<script src="jquery-1.8.3.min.js"></script>
#d3 v3版本插件

<script src="d3-3.min.js"></script>
#图的实现文件
<script src="heatmap.js"></script>

三、图形的调用
var content = $.parseJSON($('textarea').val()); //从textarea里面取出图的json数据并转化为object
graph.heatmap("container", content);   //把生成的图放在#container里面

四、以下为图的代码实现(D3.js实现)

var graph = {
	heatmap:function(container, content)
	{
        var tooltip = d3.select("body").append("div")  
            .attr("class","heatmap_tooltip") 
            .attr("opacity",0.0); 
		var colors = ["#388E3C", "#F44336", "#0288D1", "#FF9800", "#727272", "#E91E63", "#673AB7", "#8BC34A", "#2196F3", "#D32F2F", "#FFC107", "#BDBDBD", "#F8BBD0", "#3F51B5", "#CDDC39", "#009688", "#C2185B", "#FFEB3B", "#212121", "#FFCCBC", "#BBDEFB", "#0099CC", "#FFcc99"];
		
        var margin = {
            top:100,
            left:30,
            right:170,
            bottom:20,
        };

        if (typeof(content.params.row_tree_width) != 'undefined' && typeof(content.params.row_tree) != 'undefined') {
            margin.left += content.params.row_tree_width;
        }

        /**分组宽度**/
        if (typeof(content.params.row_group) != 'undefined') {
            if (typeof(content.params.row_group_location) != 'undefined' && content.params.row_group_location == 'right' && typeof(content.params.row_group_width) != 'undefined'){
                margin.right += content.params.row_group_width;
            }else if (typeof(content.params.row_group_width) != 'undefined') {
                margin.left += content.params.row_group_width;
            }
        }

        if (typeof(content.params.column_tree_height) != 'undefined' && typeof(content.params.column_tree) != 'undefined') {
            margin.top += content.params.column_tree_height;
        }

        /**分组高度**/
        if (typeof(content.params.column_group_location) != 'undefined' && content.params.column_group_location == 'bottom' && typeof(content.params.column_group_height) != 'undefined'){
            margin.bottom += content.params.column_group_height;
        } else if (typeof(content.params.column_group_height) != 'undefined') {
            margin.top += content.params.column_group_height;
        }



        var max_row_lengths = [];

        for (var i in content.params.rows) {
            max_row_lengths.push(content.params.rows[i].length);
        }

        var max_column_lengths = [];

        for (var i in content.params.columns) {
            max_column_lengths.push(content.params.columns[i].length);
        }

        var row_len = 8;
        var column_len = 9;
        var max_row_length = d3.max(max_row_lengths);

        var max_column_length = d3.max(max_column_lengths);

        var heatmap_width = content.size.width * content.params.columns.length;
        var heatmap_height = content.size.height * content.params.rows.length;

        var width  = heatmap_width + margin.left + margin.right;

        if (typeof(content.params.row_group_width) != 'undefined') {
            width += content.params.row_group_width;
        }
        

        if (typeof(content.params.show_row_label) != 'undefined' && content.params.show_row_label === true) {
            width += max_row_length * row_len;
        }

        var height = heatmap_height + margin.top + margin.bottom + max_column_length * column_len;



		var svg = d3.select('#'+container).append('svg')
            .attr('version', '1.1')
			.attr('style', 'font-family:arial')
			.attr('xmlns', 'http://www.w3.org/2000/svg')
			.attr('width', width)
			.attr('height', height);

        var title = typeof(content.params.title) != 'undefined' ? content.params.title : '';

        if (title) {
            var title_obj = svg.append('text').text(title).attr('y', 25).attr('x', function() {
                var text_length = this.getComputedTextLength();
                return (margin.left + heatmap_width)/2 - text_length/2;
            });
        }

        /**获取value的最大值、最小值**/
        var min_values = [];
        var max_values = [];

        for (var i in content.data) {
            min_values.push(d3.min(content.data[i]));
            max_values.push(d3.max(content.data[i]));
        }

        var min_value = d3.min(min_values);
        var max_value = d3.max(max_values);


        if (typeof(content.params.middle_color) != 'undefined') {
        
            var color_scale = d3.scale.linear()
                .domain([min_value, (min_value+max_value)/2, max_value])
                .range([content.params.start_color, content.params.middle_color, content.params.end_color]);
        } else {
            var color_scale = d3.scale.linear()
                .domain([min_value, (min_value+max_value)/2, max_value])
                .range([content.params.start_color, content.params.end_color]);

        }

        console.log(margin.top);

        var main = svg.append('g').attr('class', 'main').attr('transform',"translate("+margin.left+", "+margin.top+")");

        var xscale = d3.scale.linear()
            .domain([0, content.params.columns.length-1])
            .range([0, heatmap_width]);

        var yscale = d3.scale.linear()
            .domain([0, content.params.rows.length -1])
            .range([heatmap_height, 0]);

        var xaxis = d3.svg.axis()
            .scale(xscale)
            .ticks(content.params.columns.length -1)
            .tickFormat(function(d) {
                return content.params.columns[d];
            })
            .orient('bottom');

        var yaxis = d3.svg.axis()
            .scale(yscale)
            .ticks(content.params.rows.length -1)
            .tickFormat(function(d) {
                return content.params.rows[d];
            })
            .orient('right');

        var xaxis_y = heatmap_height;
        if (typeof(content.params.column_group_location) != 'undefined' && content.params.column_group_location == 'bottom' && typeof(content.params.column_group_height) != 'undefined' && typeof(content.params.column_group) != 'undefined') {
            xaxis_y += content.params.column_group_height;
        }
        var xaxis_obj = main.append('g').attr('class', 'xaxis')
            .attr('font-size', 11)
            .attr('text-anchor', 'start')
            .attr('transform', "translate(0,"+xaxis_y+")")
            .call(xaxis);

        /**显示、隐藏x标签**/
        if (typeof (content.params.show_column_label) != 'undefined' && content.params.show_column_label == true) {
            xaxis_obj.selectAll('line').attr('fill', 'none').attr('stroke', '#000');
            xaxis_obj.select('.domain').attr('fill', 'none').attr('stroke', '#000');

            xaxis_obj.selectAll('.tick').each(function(i) {
                var tick_x = content.size.width * i + content.size.width /2;
                d3.select(this).attr('transform',"translate("+tick_x+",0)");
            });

            xaxis_obj.selectAll('.tick').selectAll('text').each(function(d, i) {
                d3.select(this).attr('transform', function() {
                    var html = d3.select(this).html();
                    d3.select(this).attr('text-anchor', 'start');
                    return "rotate(110, 8,5) translate("+(this.getComputedTextLength()/2+16)+")";
                });
            });
        } else {
            xaxis_obj.attr('opacity', 0);
        }

        var yaxis_x = heatmap_width;
        if (typeof(content.params.row_group_location) != 'undefined' && content.params.row_group_location == 'right' && typeof(content.params.row_group_width) != 'undefined' && typeof(content.params.row_group) != 'undefined') {
            yaxis_x += content.params.row_group_width;
        }
        var yaxis_obj = main.append('g').attr('class', 'yaxis')
            .attr('font-size', 11)
            .attr('text-anchor', 'bottom')
            .attr('transform', "translate("+yaxis_x+",0)")
            .call(yaxis);

        /**显示、隐藏y标签**/
        if (typeof (content.params.show_row_label) != 'undefined' && content.params.show_row_label == true) {
            yaxis_obj.selectAll('line').attr('fill', 'none').attr('stroke', '#000');
            yaxis_obj.select('.domain').attr('fill', 'none').attr('stroke', '#000');

            yaxis_obj.selectAll('.tick').each(function(i) {
                var tick_y = content.size.height * i + content.size.height /2;
                d3.select(this).attr('transform',"translate(0,"+tick_y+")");
            });
        } else {
            yaxis_obj.attr('opacity', 0);
        }

        var sub_main = main.append('g').attr('class','sub_main');
        sub_main.selectAll('.heatmap_groups').data(content.data).enter()
            .append('g').attr('class', function(d, i) {
                return "heatmap_groups heatmap_group_"+i;
            })
            .attr('transform', function(d,i) {
                return "translate(0, "+(i*content.size.height)+")";
            })
            .each(function(d, i) {
                var self = d3.select(this);

                for (var j in d) {
                    var rect_g = self.append('g').attr('class', 'h_d_'+i+'_'+j).attr('transform', "translate("+(j*content.size.width)+",0)")
                        .on('mouseover', function(d) {
                            var page_x     = d3.event.pageX;
					        var page_y     = d3.event.pageY+20;
                            var self  = d3.select(this);
                            var value = d[self.select('rect').attr('index')];
                            var point_x = ingredient_legend_scale(value);
                            legend_pointer.attr('transform', "translate("+point_x+")").attr('fill-opacity', 1);
                            tooltip.html('<strong>column:</strong>'+content.params.rows[i]+'</br> <strong>row:</strong>'+content.params.columns[j]+'<br /><strong>value:</strong>'+value)  
                                .style("left",page_x+"px")  
                                .style("top",page_y+"px")  
                                .style("opacity",0.9)
                                .style('padding', '5px');
                            self.select('rect').attr('fill-opacity', 1);
                        })
                        .on('mouseout', function() {
                            legend_pointer.attr('fill-opacity', 0);

                            tooltip.style('opacity', 0.0);
                            var self  = d3.select(this);
                            self.select('rect').attr('fill-opacity', 0.9);
                        });
                    var rect   = rect_g.append('rect').attr('width', content.size.width).attr('height', content.size.height).attr('fill',color_scale(d[j])).attr('fill-opacity',0.9)
                        .attr('index', j);
                        
                    if (typeof(content.params.show_gap) != 'undefined' && content.params.show_gap === true) {
                        rect.attr('stroke', '#fff');
                    }

                    if (typeof(content.params.show_label) != 'undefined' && content.params.show_label == true) {
                        rect_g.append('text').text(Math.round(d[j]*10000)/10000).attr('x', function () {
                            return content.size.width /2 - this.getComputedTextLength()/3;
                        })
                        .attr('y', function() {
                            return content.size.height /2+5;
                        })
                        .attr('font-size', 11);
                    }
                }
            });

        /** 绘制行分组**/
        if (typeof(content.params.row_group) != 'undefined') {
            if (typeof(content.params.row_group_location) != 'undefined' && content.params.row_group_location == 'right' && typeof(content.params.row_group_width) != 'undefined'){
                var row_group_x = margin.left + heatmap_width;
            } else {
                var row_group_x = margin.left - content.params.row_group_width;
            }
            var row_group = svg.append('g').attr('class', 'row_group').attr('transform', "translate("+row_group_x+","+margin.top+")");

            row_group.selectAll('.cat_rows').data(content.params.row_group).enter()
                .append('g').attr('class', function(d, i) {
                    return "cat_rows rows_"+i;
                })
                .attr('transform', function(d, i) {
                    return "translate(0, "+(content.size.height)*i+")";
                })
                .each(function(d, i) {
                    var self = d3.select(this);
                    var rect = self.append('rect').attr('width', content.params.row_group_width).attr('height', content.size.height).attr('fill',d).attr('fill-opacity',0.9);
                    if (typeof(content.params.show_gap) != 'undefined' && content.params.show_gap === true) {
                        rect.attr('stroke', '#fff');
                    }
                })

        }

        /** 绘制列分组**/
        if (typeof(content.params.column_group) != 'undefined') {
            var column_group_x = margin.left;
            
            if (typeof(content.params.column_group_location) != 'undefined' && content.params.column_group_location == 'bottom' && typeof(content.params.column_group_height) != 'undefined'){
                var column_group_y = margin.top + heatmap_height;
            } else {
                var column_group_y = margin.top-content.params.column_group_height;
            }
            var column_group = svg.append('g').attr('class', 'column_group').attr('transform', "translate("+column_group_x+","+column_group_y+")");

            column_group.selectAll('.cat_columns').data(content.params.column_group).enter()
                .append('g').attr('class', function(d, i) {
                    return "cat_columns columns_"+i;
                })
                .attr('transform', function(d, i) {
                    return "translate("+(content.size.width*i)+", 0)";
                })
                .each(function(d, i) {
                    var self = d3.select(this);
                    var rect = self.append('rect').attr('width', content.size.width).attr('height', content.params.column_group_height).attr('fill',d).attr('fill-opacity',0.9);

                    if (typeof(content.params.show_gap) != 'undefined' && content.params.show_gap === true) {
                        rect.attr('stroke', '#fff');
                    }
                })

        }
            

        /**绘制图例**/

        function sprintf(text, arr) {
            var i = 0;
            return text.replace(/\$S/g, function () {
                return (i < arr.length) ? arr[i++] : "";
            });
        }

        var color_stops = [
          '<stop offset="0%" stop-color="$S"></stop>',
          '<stop offset="50%" stop-color="$S"></stop>',
          '<stop offset="100%" stop-color="$S"></stop>'
          ];
        if(typeof(content.params.middle_color) == 'undefined'){
            color_stops = [color_stops[0], color_stops[2]].join('');
            color_stops = sprintf(color_stops, [content.params.start_color, content.params.end_color]);
        }else{
            color_stops = sprintf(color_stops.join(''), [content.params.start_color, content.params.middle_color, content.params.end_color]);
        };
        console.log(color_stops);

        var defs = svg.append('defs');

        /** 定义滤镜颜色**/
        defs.append('linearGradient')
          .attr({
            id: 'ingredient_legend',
            x1: "0%",
            y1: "0%",
            x2: "100%",
            y2: "0%"
          })
          .html(color_stops);

        /**定义滤镜上移动的箭头**/
        var nonius_scale = 6;
        var pointer = "M0 0 " +
            "L" + nonius_scale    + " " + -nonius_scale     + " " +
            "L" + nonius_scale    + " " + -2 * nonius_scale + " " +
            "L" + (-nonius_scale) + " " + -2 * nonius_scale + " " +
            "L" + (-nonius_scale) + " " + -nonius_scale     + " Z";
        
        var legend_x = width - margin.right;

        if (typeof(content.params.row_group_location) != 'undefined' && content.params.row_group_location == 'right' && typeof(content.params.row_group_width) != 'undefined' && typeof(content.params.row_group) != 'undefined') {
            legend_x += content.params.row_group_width;
        }
        var legend = svg.append('g').attr('class', 'legends').attr('transform', 'translate('+legend_x+',30)');

        var ingredient_legend = legend.append('g').attr('class', 'ingredient_legend');

        var ingredient_legend_width = 150;
        var ingredient_legend_height = 20;
        ingredient_legend.append('rect').attr('width', ingredient_legend_width).attr('height', ingredient_legend_height).attr('fill', "url(#ingredient_legend)")
            .attr('shape-rendering','crispEdges');

        var ingredient_legend_scale = d3.scale.linear()
            .domain([min_value, max_value])
            .range([0, ingredient_legend_width]);


        var ingredient_legend_axis = d3.svg.axis()
            .scale(ingredient_legend_scale)
            .ticks(5)
            .orient('bottom');

        var ingredient_legend_axis_obj = ingredient_legend.append('g').attr('class', 'legend_axis').attr('transform',"translate(0,"+ingredient_legend_height+")")
            .call(ingredient_legend_axis);


        ingredient_legend_axis_obj.selectAll('line').attr('fill', 'none').attr('stroke', '#000');
        ingredient_legend_axis_obj.select('.domain').attr('fill', 'none').attr('stroke', 'none');

        var tick_size = ingredient_legend.select('.legend_axis').selectAll('.tick').size();
        ingredient_legend.select('.legend_axis').selectAll('.tick').each(function(d, i) {
            if (i != 0 && i != tick_size -1) {
                d3.select(this).remove();
            }
            
        });

        var legend_pointer = ingredient_legend.append("path")
        .attr({
            class: "legend-pointer",
            d: pointer,
            fill: "#33a3dc",
            "fill-opacity": 0
        });

        /**绘制行的分组图例**/

        var row_legend_y = 70;

        if (typeof(content.params.row_legend_name) != 'undefined' && typeof(content.params.row_group) != 'undefined') {
            var row_legend = legend.append('g').attr('class', 'row_legend').attr('transform', "translate(0, "+row_legend_y+")").attr('font-size', 11);
        
            row_legend.append('text').text('Taxon group').attr('font-size', 13);
            row_legend.selectAll('.child_row_legend').data(content.params.row_legend_name).enter()
                .append('g').attr('class', function(d, i) {
                    return "child_row_legend child_row_"+i;
                })
                .attr('transform', function(d, i) {
                    return "translate(0, "+(20+i * 20)+")";
                })
                .each(function(d, i) {
                    var self = d3.select(this);
                    self.append('rect').attr('width', 20).attr('height', 10).attr('fill', content.params.row_group[i]);
                    self.append('text').text(d).attr('x', 25).attr('y', 8);
                });
        }
        /**绘制列的分组图例**/

        if (typeof(content.params.column_legend_name) != 'undefined' && typeof(content.params.column_group) != 'undefined') {

            if (typeof(content.params.row_group) != 'undefined' && typeof(content.params.row_legend_name) != 'undefined') {
                var column_legend_y = row_legend_y + content.params.row_legend_name.length * 20 + 20 + 30;
            } else {
                var column_legend_y = row_legend_y;
            }

            var column_legend = legend.append('g').attr('class', 'column_legend').attr('transform', "translate(0, "+column_legend_y+")").attr('font-size', 11);
            column_legend.append('text').text('Sample group').attr('font-size', 13);
            column_legend.selectAll('.child_column_legend').data(content.params.column_legend_name).enter()
                .append('g').attr('class', function(d, i) {
                    return "child_column_legend child_column_"+i;
                })
                .attr('transform', function(d, i) {
                    return "translate(0, "+(20+i * 20)+")";
                })
                .each(function(d, i) {
                    var self = d3.select(this);
                    self.append('rect').attr('width', 20).attr('height', 10).attr('fill', content.params.column_group[i]);
                    self.append('text').text(d).attr('x', 25).attr('y', 8);
                });
        }

        /**树**/

        var leaf = [];
        var max_x = 0;
        var getleaf = function(subtree, x) {
            if ("undefined" == typeof x) {
                x = 0;
            }
            var sub_y = [];
            var length = 0;
            if (subtree.length) {
                length = subtree.length;
            }
            subtree.start_x = x;
            x = x + length;
            subtree.end_x = x;
            if (subtree.end_x > max_x) {
                max_x = subtree.end_x;
            }
            if (subtree.branchset) {
                for (var i in subtree.branchset) {
                    sub_y.push(getleaf(subtree.branchset[i], x));
                }
            } else {
                subtree.y = leaf.length;
                leaf.push(subtree);
                return subtree.y;
            }
            subtree.y = d3.sum(sub_y) / sub_y.length;
            return subtree.y;
        };

        /**绘制行的树**/
        if (typeof(content.params.row_tree) != 'undefined') {
            var tree_1 = graph.newickParse(content.params.row_tree);
            getleaf(tree_1);
            // 定义最左面的树图的宽度的比例尺
            var row_ytree_scale = d3.scale.linear().domain([0, leaf.length - 1]).range([margin.top+content.size.height/2, margin.top+heatmap_height-content.size.height/2]);
            var row_xtree_scale = d3.scale.linear().domain([0, max_x]).range([5, content.params.row_tree_width - 2]);

            var left_x = (margin.left - content.params.row_tree_width);

            if (typeof(content.params.row_group_location) != 'undefined' && content.params.row_group_location == 'right' && typeof(content.params.row_group_width) != 'undefined'){
                
            } else if (typeof(content.params.row_group_width) != 'undefined' && typeof(content.params.row_group) != 'undefined') {
                left_x -= content.params.row_group_width;
            }
            var left_tree_obj = svg.append('g').attr('class', 'left_tree').attr('transform', 'translate('+left_x+')');

            graph.plotTree(tree_1, left_tree_obj, row_xtree_scale, row_ytree_scale);
        }

        max_x = 0;
        leaf = [];
        if (typeof(content.params.column_tree) != 'undefined') {
            var tree_1 = graph.newickParse(content.params.column_tree);
            getleaf(tree_1);

            //定义最上面的树的高度的比例尺
            var row_xtree_scale    = d3.scale.linear().domain([0, leaf.length - 1]).range([margin.left+content.params.row_tree_width/2,heatmap_width+margin.left-content.params.row_tree_width/2]);
            
            var columny_end   = margin.top;
            var columny_start = margin.top - content.params.column_tree_height;
            if (typeof(content.params.column_group_location) != 'undefined' && content.params.column_group_location == 'bottom' && typeof(content.params.column_group_height) != 'undefined'){
                
            } else if (typeof(content.params.column_group_height) != 'undefined') {
                columny_start -= content.params.column_group_height;
                columny_end   -= content.params.column_group_height;
            }

            var column_ytree_scale = d3.scale.linear().domain([0, max_x]).range([columny_start, columny_end]);

            var top_tree_obj = svg.append('g').attr('class', 'top_tree').attr("transform", "translate(0, 0)");

            graph.plotTree(tree_1, top_tree_obj, row_xtree_scale, column_ytree_scale, 'column');
        }

        


        
	},
    newickParse:function(string)
    {
        var ancestors = [];
        var tree = {};
        var tokens = string.split(/\s*(;|\(|\)|,|:)\s*/);
        for (var i = 0; i < tokens.length; i++) {
            var token = tokens[i];
            switch (token) {
            case "(":
                var subtree = {};
                tree.branchset = [subtree];
                ancestors.push(tree);
                tree = subtree;
                break;
            case ",":
                var subtree = {};
                ancestors[ancestors.length - 1].branchset.push(subtree);
                tree = subtree;
                break;
            case ")":
                tree = ancestors.pop();
                break;
            case ":":
                break;
            default:
                var x = tokens[i - 1];
                if (x == ")" || x == "(" || x == ",") {
                    tree.name = token;
                } else if (x == ":") {
                    tree.length = parseFloat(token);
                }
            }
        }
        return tree;
    },
    plotTree:function(tree, obj,linear_width_scale, linear_height_scale, type) {
        if (typeof(type) == 'undefined' || type == 'row') {
            graph.plotRow(tree, obj,linear_width_scale, linear_height_scale);
        } else {
            graph.plotColumn(tree, obj,linear_width_scale, linear_height_scale);
        }
        
        if (tree.branchset) {
            for (var i in tree.branchset) {
                graph.plotTree(tree.branchset[i], obj,linear_width_scale, linear_height_scale, type);
            }
        }
    },
    plotRow:function(tree, obj, linear_width_scale, linear_height_scale) {
        obj.append("line").attr("x1", linear_width_scale(tree.start_x)).attr("y1", linear_height_scale(tree.y)).attr("x2", linear_width_scale(tree.end_x)).attr("y2", linear_height_scale(tree.y)).attr("stroke-width", 0.8).attr("stroke", '#000');
        if (tree.branchset) {
            var list_y = [];
            for (var i in tree.branchset) {
                list_y.push(tree.branchset[i].y);
            }
            var max_min_y = [d3.min(list_y), d3.max(list_y)];
            obj.append("line").attr("x1", linear_width_scale(tree.end_x)).attr("y1", linear_height_scale(max_min_y[1])).attr("x2", linear_width_scale(tree.end_x)).attr("y2", linear_height_scale(max_min_y[0])).attr("stroke-width", 0.8).attr("stroke", '#000');
        }
    },

    plotColumn:function(tree, obj, linear_width_scale, linear_height_scale) {
        obj.append("line").attr("x1", linear_width_scale(tree.y)).attr("y1", linear_height_scale(tree.start_x)).attr("x2", linear_width_scale(tree.y)).attr("y2", linear_height_scale(tree.end_x)).attr("stroke-width", 0.8).attr("stroke", '#000');
        if (tree.branchset) {
            var list_y = [];
            for (var i in tree.branchset) {
                list_y.push(tree.branchset[i].y);
            }
            var max_min_y = [d3.min(list_y), d3.max(list_y)];
            obj.append("line").attr("x1", linear_width_scale(max_min_y[0])).attr("y1", linear_height_scale(tree.end_x)).attr("x2", linear_width_scale(max_min_y[1])).attr("y2", linear_height_scale(tree.end_x)).attr("stroke-width", 0.8).attr("stroke", '#000');
        }
    }
};

以上就是图的全部实现,如果有不清楚的地方可以留言,欢迎交流

 

 

 

 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值