2015-12-23 91 views
3

我正嘗試用d3js創建一個典型的波德圖。用Matlab創建的典型波特圖如下所示:使用次要和主要蜱創建波德圖d3js

Matlab bode plot

現在我已經來了很遠看到:http://plnkr.co/edit/BpWis5uhC8KM2tRbXMk3或嵌入在這個職位的片段。

我有的問題是,我想,如在matlab波特圖,有主要和次要的蜱蟲。主蜱是堅實的,而小蜱點綴。不幸的是,我似乎無法做到這一點。我已經從嘗試了各種解決方案:

Major and minor ticks with different style, whole page covered D3? Major and minor ticks with V3 of D3? d3.js alternative to axis.tickSubdivide? http://bl.ocks.org/vjpgo/4689130 http://bl.ocks.org/mbostock/4349486

<!DOCTYPE html> 
 
<html lang="en"> 
 
<head> 
 
<title>LOG</title> 
 
<meta charset="utf-8"> 
 
<script src="//d3js.org/d3.v3.min.js"></script> 
 
<script src="//code.jquery.com/jquery-1.10.2.js"></script> 
 
<script src="//mathjs.org/js/lib/math.js"></script> 
 
<style type="text/css"> 
 
svg { 
 
    font: 10px sans-serif; 
 
    shape-rendering: crispEdges; 
 
} 
 
    
 
rect { 
 
    fill: transparent; 
 
} 
 
    
 
.axis path, 
 
.axis line { 
 
    fill: none; 
 
    stroke: #000; 
 
    shape-rendering: crispEdges; 
 
} 
 
    
 
.line { 
 
    fill: none; 
 
    stroke: steelblue; 
 
    stroke-width: 1.5px; 
 
    clip-path: url(#clip); 
 
} 
 
    
 
.grid .tick { 
 
    stroke: lightgrey; 
 
    opacity: 0.7; 
 
} 
 
    
 
.grid path { 
 
    stroke-width: 0; 
 
} 
 
</style> 
 
<script type="text/javascript"> 
 
\t function linspace(a,b,n) { 
 
\t \t var every = (b-a)/(n-1), 
 
\t \t \t range = []; 
 
\t \t for (i = a; i < b; i += every) 
 
\t \t \t range.push(i); 
 
\t \t return range.length == n ? range : range.concat(b); 
 
\t } 
 
\t 
 
\t function logspace(a,b,n) { 
 
\t \t return linspace(a,b,n).map(function(x) { return Math.pow(10,x); }); 
 
\t } 
 
\t 
 
\t function isInteger(value) { 
 
\t \t return typeof value === "number" && 
 
\t \t \t isFinite(value) && 
 
\t \t \t Math.floor(value) === value; 
 
\t }; 
 
\t 
 
\t function leadlag(f) { 
 
\t \t w = 2*math.pi*f; 
 
\t \t s = math.complex(0,w); 
 

 
\t \t K = 1; 
 
\t \t fz = 20; 
 
\t \t fp = 40; 
 

 
\t \t wz = 2*math.pi*fz; 
 
\t \t wp = 2*math.pi*fp; 
 

 
\t \t return math.multiply(K,math.multiply(math.divide(wp,wz),math.divide(math.add(s,wz),(math.add(s,wp))))); 
 
\t }; 
 
\t 
 
\t function angle(f) { 
 
\t \t return math.atan2(f.im,f.re); 
 
\t }; 
 
\t 
 
\t function deg2rad(deg) { 
 
    \t \t return deg * math.pi/180; 
 
\t }; 
 
    
 
\t function rad2deg(rad) { 
 
    \t \t return rad * 180/math.pi; 
 
\t }; 
 
\t 
 
\t function mag2db(mag) { 
 
\t \t return 20 * Math.log10(mag); 
 
\t } 
 
\t 
 
\t function db2mag(db) { 
 
\t \t return math.pow(10,db/20); 
 
\t } 
 
</script> 
 
</head> 
 
<body> 
 
<div id="plotmagnitude"></div> 
 
<div id="plotphase"></div> 
 
<script type="text/javascript"> 
 
\t var margin = { 
 
     top: 20, 
 
     right: 20, 
 
     bottom: 35, 
 
     left: 50 
 
    }; 
 
\t 
 
\t var width = 450 - margin.left - margin.right; 
 
\t var height = 250 - margin.top - margin.bottom; 
 
\t 
 
\t var range = logspace(0,3,1000); 
 

 
    var x = d3.scale.log() 
 
\t \t .domain([1, range[range.length-1].toFixed()]) 
 
\t \t .range([0, width]); 
 

 
    var y = d3.scale.linear() 
 
\t \t .domain([-10, 2]) 
 
\t \t .range([height, 0]); 
 

 
    var xAxis1 = d3.svg.axis() 
 
\t \t .scale(x) 
 
\t \t .orient("bottom") 
 
\t \t .ticks(1,"0.1s") 
 
\t \t .innerTickSize(-6) 
 
\t \t .outerTickSize(0) 
 
\t \t .tickPadding(7); 
 

 
    var yAxis1 = d3.svg.axis() 
 
\t \t .scale(y) 
 
\t \t .orient("left") 
 
\t \t .ticks(5) 
 
\t \t .innerTickSize(-6) 
 
\t \t .outerTickSize(0) 
 
\t \t .tickPadding(7); 
 

 
    var xAxis2 = d3.svg.axis() 
 
\t \t .scale(x) 
 
\t \t .orient("top") 
 
\t \t .ticks(5) 
 
\t \t .innerTickSize(-6) 
 
\t \t .tickPadding(-20) 
 
\t \t .outerTickSize(0) 
 
\t \t .tickFormat(""); 
 

 
    var yAxis2 = d3.svg.axis() 
 
\t \t .scale(y) 
 
\t \t .orient("left") 
 
\t \t .ticks(5) 
 
\t \t .innerTickSize(6) 
 
\t \t .tickPadding(-20) 
 
\t \t .outerTickSize(0) 
 
\t \t .tickFormat(""); 
 

 
    var xGrid = d3.svg.axis() 
 
\t \t .scale(x) 
 
\t \t .orient("bottom") 
 
\t \t .ticks(5) 
 
\t \t .tickSize(-height, -height, 0) 
 
\t \t .tickFormat(""); 
 

 
    var yGrid = d3.svg.axis() 
 
\t \t .scale(y) 
 
\t \t .orient("left") 
 
\t \t .ticks(5) 
 
\t \t .tickSize(-width, -width, 0) 
 
\t \t .tickFormat(""); 
 
\t 
 
    var line = d3.svg.line() 
 
\t \t .x(function(d) { 
 
\t \t \t return x(d.x); 
 
\t \t }) 
 
\t \t .y(function(d) { 
 
\t \t \t return y(d.y); 
 
\t \t }) 
 
\t \t .interpolate("linear"); 
 
\t 
 
    var zoom = d3.behavior.zoom() 
 
\t \t .x(x) 
 
\t \t .y(y) 
 
\t \t .scaleExtent([1, 1]) 
 
\t \t .on("zoom",redraw); 
 
     
 
    var plotMagnitude = d3.select("#plotmagnitude").append("svg") 
 
\t \t .attr("width",width + margin.left + margin.right) 
 
\t \t .attr("height",height + margin.top + margin.bottom) 
 
\t \t .append("g") 
 
\t \t .attr("transform","translate(" + margin.left + "," + margin.top + ")") 
 
\t \t .call(zoom); 
 
\t 
 
    // Add x grid 
 
    plotMagnitude.append("g") 
 
\t \t .attr("class","x grid") 
 
\t \t .attr("transform","translate(0," + height + ")") 
 
\t \t .call(xGrid); 
 
\t \t 
 

 
    // Add y grid 
 
    plotMagnitude.append("g") 
 
\t \t .attr("class","y grid") 
 
\t \t .call(yGrid); 
 

 
    plotMagnitude.append("g") 
 
\t \t .attr("class","x1 axis") 
 
\t \t .attr("transform","translate(0," + height + ")") 
 
\t \t .call(xAxis1); 
 

 
    plotMagnitude.append("g") 
 
\t \t .attr("class","y1 axis") 
 
\t \t .call(yAxis1); 
 

 
    /* append additional X axis */ 
 
    plotMagnitude.append("g") 
 
\t \t .attr("class","x2 axis") 
 
\t \t .attr("transform","translate(" + [0, 0] + ")") 
 
\t \t .call(xAxis2); 
 

 
    /* append additional y axis */ 
 
    plotMagnitude.append("g") 
 
\t \t .attr("class","y2 axis") 
 
\t \t .attr("transform","translate(" + [width, 0] + ")") 
 
\t \t .call(yAxis2); 
 

 
    // Add x axis label 
 
    plotMagnitude.append("text") 
 
     .attr("transform","translate(" + (width/2) + "," + (height + margin.bottom) + ")") 
 
     .style("font-size","15") 
 
     .style("text-anchor","middle") 
 
     .text("x axis"); 
 

 
    // Add y axis label 
 
    plotMagnitude.append("text") 
 
     .attr("transform", "rotate(-90)") 
 
     .attr("y",0 - margin.left) 
 
     .attr("x",0 - (height/2)) 
 
     .attr("dy", "1em") 
 
     .style("font-size","15") 
 
     .style("text-anchor", "middle") 
 
     .text("y axis"); 
 

 
    plotMagnitude.append("defs").append("clipPath") 
 
\t \t .attr("id", "clip") 
 
\t \t .append("rect") 
 
\t \t .attr("width", width) 
 
\t \t .attr("height", height); 
 
     
 
    plotMagnitude.append("rect") 
 
\t \t .attr("width", width) 
 
\t \t .attr("height", height); 
 

 
    function redraw() { 
 
\t \t plotMagnitude.select(".x1.axis").call(xAxis1); 
 
\t \t plotMagnitude.select(".y1.axis").call(yAxis1); 
 
\t \t plotMagnitude.select(".x2.axis").call(xAxis2); 
 
\t \t plotMagnitude.select(".y2.axis").call(yAxis2); 
 
\t \t plotMagnitude.select(".x.grid").call(xGrid); 
 
\t \t plotMagnitude.select(".y.grid").call(yGrid); 
 
\t \t 
 
\t \t var series = []; 
 
\t \t var data1 = []; 
 
\t \t var data2 = []; 
 
\t \t var data3 = []; 
 

 
\t \t for (var i = 0; i < range.length; i++) { 
 
\t \t \t data1.push({ 
 
\t \t \t \t x: range[i], 
 
\t \t \t \t y: leadlag(range[i]) 
 
\t \t \t }); 
 

 
\t \t \t data2.push({ 
 
\t \t \t \t x: range[i], 
 
\t \t \t \t y: mag2db(math.abs(leadlag(range[i]))) 
 
\t \t \t }); 
 
\t \t \t 
 
\t \t \t data3.push({ 
 
\t \t \t \t x: range[i], 
 
\t \t \t \t y: rad2deg(angle(leadlag(range[i]))) 
 
\t \t \t }); 
 
\t \t } 
 

 
\t \t series.push({data: data2, width: 1, color: 'blue', stroke: "0,0", legend: "MAG" }); 
 

 
\t \t var series = plotMagnitude.selectAll(".line").data(series); 
 

 
\t \t series.enter().append('path'); 
 

 
\t \t series.attr("class","line") 
 
\t \t \t .attr("d",function(d) { return line(d.data); }) 
 
\t \t \t .attr("stroke-width", function(d) { return d.width; }) 
 
\t \t \t .style("stroke", function(d) { return d.color; }) 
 
\t \t \t .style("stroke-dasharray", function(d) { return d.stroke; }); 
 
\t } 
 

 
\t $(function() { 
 
\t \t redraw(); 
 
\t }); 
 
</script> 
 
</body> 
 
</html>

回答

1

看來你的 「主要」 蜱是指那些與標籤,所以難以找到它們,然後找到相應的網格線。

如何:

d3.selectAll('.x1.axis>.tick') // find all the x axis ticks and loop 
    .each(function(d,i){ 
    if (d3.select(this).select('text').text() === ""){ // if they have no label 
     d3.select('.x.grid>.tick:nth-child(' + (i + 1) + ')') // get the corresponding grid line 
     .style("stroke-dasharray", "3,3"); // and make it dashed 
     } 
    }); 

全碼:

<!DOCTYPE html> 
 
<html lang="en"> 
 
<head> 
 
<title>LOG</title> 
 
<meta charset="utf-8"> 
 
<script src="//d3js.org/d3.v3.min.js"></script> 
 
<script src="//code.jquery.com/jquery-1.10.2.js"></script> 
 
<script src="//mathjs.org/js/lib/math.js"></script> 
 
<style type="text/css"> 
 
svg { 
 
    font: 10px sans-serif; 
 
    shape-rendering: crispEdges; 
 
} 
 
    
 
rect { 
 
    fill: transparent; 
 
} 
 
    
 
.axis path, 
 
.axis line { 
 
    fill: none; 
 
    stroke: #000; 
 
    shape-rendering: crispEdges; 
 
} 
 
    
 
.line { 
 
    fill: none; 
 
    stroke: steelblue; 
 
    stroke-width: 1.5px; 
 
    clip-path: url(#clip); 
 
} 
 
    
 
.grid .tick { 
 
    stroke: lightgrey; 
 
    opacity: 0.7; 
 
} 
 
    
 
.grid path { 
 
    stroke-width: 0; 
 
} 
 
</style> 
 
<script type="text/javascript"> 
 
\t function linspace(a,b,n) { 
 
\t \t var every = (b-a)/(n-1), 
 
\t \t \t range = []; 
 
\t \t for (i = a; i < b; i += every) 
 
\t \t \t range.push(i); 
 
\t \t return range.length == n ? range : range.concat(b); 
 
\t } 
 
\t 
 
\t function logspace(a,b,n) { 
 
\t \t return linspace(a,b,n).map(function(x) { return Math.pow(10,x); }); 
 
\t } 
 
\t 
 
\t function isInteger(value) { 
 
\t \t return typeof value === "number" && 
 
\t \t \t isFinite(value) && 
 
\t \t \t Math.floor(value) === value; 
 
\t }; 
 
\t 
 
\t function leadlag(f) { 
 
\t \t w = 2*math.pi*f; 
 
\t \t s = math.complex(0,w); 
 

 
\t \t K = 1; 
 
\t \t fz = 20; 
 
\t \t fp = 40; 
 

 
\t \t wz = 2*math.pi*fz; 
 
\t \t wp = 2*math.pi*fp; 
 

 
\t \t return math.multiply(K,math.multiply(math.divide(wp,wz),math.divide(math.add(s,wz),(math.add(s,wp))))); 
 
\t }; 
 
\t 
 
\t function angle(f) { 
 
\t \t return math.atan2(f.im,f.re); 
 
\t }; 
 
\t 
 
\t function deg2rad(deg) { 
 
    \t \t return deg * math.pi/180; 
 
\t }; 
 
    
 
\t function rad2deg(rad) { 
 
    \t \t return rad * 180/math.pi; 
 
\t }; 
 
\t 
 
\t function mag2db(mag) { 
 
\t \t return 20 * Math.log10(mag); 
 
\t } 
 
\t 
 
\t function db2mag(db) { 
 
\t \t return math.pow(10,db/20); 
 
\t } 
 
</script> 
 
</head> 
 
<body> 
 
<div id="plotmagnitude"></div> 
 
<div id="plotphase"></div> 
 
<script type="text/javascript"> 
 
\t var margin = { 
 
     top: 20, 
 
     right: 20, 
 
     bottom: 35, 
 
     left: 50 
 
    }; 
 
\t 
 
\t var width = 450 - margin.left - margin.right; 
 
\t var height = 250 - margin.top - margin.bottom; 
 
\t 
 
\t var range = logspace(0,3,1000); 
 

 
    var x = d3.scale.log() 
 
\t \t .domain([1, range[range.length-1].toFixed()]) 
 
\t \t .range([0, width]); 
 

 
    var y = d3.scale.linear() 
 
\t \t .domain([-10, 2]) 
 
\t \t .range([height, 0]); 
 

 
    var xAxis1 = d3.svg.axis() 
 
\t \t .scale(x) 
 
\t \t .orient("bottom") 
 
\t \t .ticks(1,"0.1s") 
 
\t \t .innerTickSize(-6) 
 
\t \t .outerTickSize(0) 
 
\t \t .tickPadding(7); 
 

 
    var yAxis1 = d3.svg.axis() 
 
\t \t .scale(y) 
 
\t \t .orient("left") 
 
\t \t .ticks(5) 
 
\t \t .innerTickSize(-6) 
 
\t \t .outerTickSize(0) 
 
\t \t .tickPadding(7); 
 

 
    var xAxis2 = d3.svg.axis() 
 
\t \t .scale(x) 
 
\t \t .orient("top") 
 
\t \t .ticks(5) 
 
\t \t .innerTickSize(-6) 
 
\t \t .tickPadding(-20) 
 
\t \t .outerTickSize(0) 
 
\t \t .tickFormat(""); 
 

 
    var yAxis2 = d3.svg.axis() 
 
\t \t .scale(y) 
 
\t \t .orient("left") 
 
\t \t .ticks(5) 
 
\t \t .innerTickSize(6) 
 
\t \t .tickPadding(-20) 
 
\t \t .outerTickSize(0) 
 
\t \t .tickFormat(""); 
 

 
    var xGrid = d3.svg.axis() 
 
\t \t .scale(x) 
 
\t \t .orient("bottom") 
 
\t \t .ticks(5) 
 
\t \t .tickSize(-height, -height, 0) 
 
\t \t .tickFormat(""); 
 

 
    var yGrid = d3.svg.axis() 
 
\t \t .scale(y) 
 
\t \t .orient("left") 
 
\t \t .ticks(5) 
 
\t \t .tickSize(-width, -width, 0) 
 
\t \t .tickFormat(""); 
 
\t 
 
    var line = d3.svg.line() 
 
\t \t .x(function(d) { 
 
\t \t \t return x(d.x); 
 
\t \t }) 
 
\t \t .y(function(d) { 
 
\t \t \t return y(d.y); 
 
\t \t }) 
 
\t \t .interpolate("linear"); 
 
\t 
 
    var zoom = d3.behavior.zoom() 
 
\t \t .x(x) 
 
\t \t .y(y) 
 
\t \t .scaleExtent([1, 1]) 
 
\t \t .on("zoom",redraw); 
 
     
 
    var plotMagnitude = d3.select("#plotmagnitude").append("svg") 
 
\t \t .attr("width",width + margin.left + margin.right) 
 
\t \t .attr("height",height + margin.top + margin.bottom) 
 
\t \t .append("g") 
 
\t \t .attr("transform","translate(" + margin.left + "," + margin.top + ")") 
 
\t \t .call(zoom); 
 
\t 
 
    // Add x grid 
 
    plotMagnitude.append("g") 
 
\t \t .attr("class","x grid") 
 
\t \t .attr("transform","translate(0," + height + ")") 
 
\t \t .call(xGrid); 
 

 
    // Add y grid 
 
    plotMagnitude.append("g") 
 
\t \t .attr("class","y grid") 
 
\t \t .call(yGrid); 
 

 
    plotMagnitude.append("g") 
 
\t \t .attr("class","x1 axis") 
 
\t \t .attr("transform","translate(0," + height + ")") 
 
\t \t .call(xAxis1); 
 

 
    plotMagnitude.append("g") 
 
\t \t .attr("class","y1 axis") 
 
\t \t .call(yAxis1); 
 

 
    /* append additional X axis */ 
 
    plotMagnitude.append("g") 
 
\t \t .attr("class","x2 axis") 
 
\t \t .attr("transform","translate(" + [0, 0] + ")") 
 
\t \t .call(xAxis2); 
 

 
    /* append additional y axis */ 
 
    plotMagnitude.append("g") 
 
\t \t .attr("class","y2 axis") 
 
\t \t .attr("transform","translate(" + [width, 0] + ")") 
 
\t \t .call(yAxis2); 
 

 
    // Add x axis label 
 
    plotMagnitude.append("text") 
 
     .attr("transform","translate(" + (width/2) + "," + (height + margin.bottom) + ")") 
 
     .style("font-size","15") 
 
     .style("text-anchor","middle") 
 
     .text("x axis"); 
 

 
    // Add y axis label 
 
    plotMagnitude.append("text") 
 
     .attr("transform", "rotate(-90)") 
 
     .attr("y",0 - margin.left) 
 
     .attr("x",0 - (height/2)) 
 
     .attr("dy", "1em") 
 
     .style("font-size","15") 
 
     .style("text-anchor", "middle") 
 
     .text("y axis"); 
 

 
    plotMagnitude.append("defs").append("clipPath") 
 
\t \t .attr("id", "clip") 
 
\t \t .append("rect") 
 
\t \t .attr("width", width) 
 
\t \t .attr("height", height); 
 
     
 
    plotMagnitude.append("rect") 
 
\t \t .attr("width", width) 
 
\t \t .attr("height", height); 
 

 
    function redraw() { 
 
\t \t plotMagnitude.select(".x1.axis").call(xAxis1); 
 
\t \t plotMagnitude.select(".y1.axis").call(yAxis1); 
 
\t \t plotMagnitude.select(".x2.axis").call(xAxis2); 
 
\t \t plotMagnitude.select(".y2.axis").call(yAxis2); 
 
\t \t plotMagnitude.select(".x.grid").call(xGrid); 
 
\t \t plotMagnitude.select(".y.grid").call(yGrid); 
 
\t \t 
 
\t \t var series = []; 
 
\t \t var data1 = []; 
 
\t \t var data2 = []; 
 
\t \t var data3 = []; 
 

 
\t \t for (var i = 0; i < range.length; i++) { 
 
\t \t \t data1.push({ 
 
\t \t \t \t x: range[i], 
 
\t \t \t \t y: leadlag(range[i]) 
 
\t \t \t }); 
 

 
\t \t \t data2.push({ 
 
\t \t \t \t x: range[i], 
 
\t \t \t \t y: mag2db(math.abs(leadlag(range[i]))) 
 
\t \t \t }); 
 
\t \t \t 
 
\t \t \t data3.push({ 
 
\t \t \t \t x: range[i], 
 
\t \t \t \t y: rad2deg(angle(leadlag(range[i]))) 
 
\t \t \t }); 
 
\t \t } 
 

 
\t \t series.push({data: data2, width: 1, color: 'blue', stroke: "0,0", legend: "MAG" }); 
 

 
\t \t var series = plotMagnitude.selectAll(".line").data(series); 
 

 
\t \t series.enter().append('path'); 
 

 
\t \t series.attr("class","line") 
 
\t \t \t .attr("d",function(d) { return line(d.data); }) 
 
\t \t \t .attr("stroke-width", function(d) { return d.width; }) 
 
\t \t \t .style("stroke", function(d) { return d.color; }) 
 
\t \t \t .style("stroke-dasharray", function(d) { return d.stroke; }); 
 
\t \t \t 
 
\t \t d3.selectAll('.x1.axis>.tick') 
 
\t \t .each(function(d,i){ 
 
    \t \t if (d3.select(this).select('text').text() === ""){ 
 
    \t \t  d3.select('.x.grid>.tick:nth-child(' + (i + 1) + ')') 
 
    \t \t  .style("stroke-dasharray", "3,3"); 
 
    \t \t } 
 
\t \t }); 
 
\t \t 
 
\t } 
 

 
\t $(function() { 
 
\t \t redraw(); 
 
\t }); 
 
</script> 
 
</body> 
 
</html>

+0

謝謝您的回覆!起初,我對這個答案很滿意。但是,我正在創造一個預兆。這包括兩個在彼此之下的地塊。幅度圖,即上圖,通常沒有X軸標籤來節省空間,因爲它是重複的w.r.t對下面的圖,相圖。在這個解決方案之後,我會做的下一步是創建兩個圖,一個沒有x標籤,一個沒有x標籤。我願意提出改進代碼的建議,因爲我感覺它有點臃腫? –

+0

@ WG-,如果兩個圖上的x軸均匹配,則此解決方案仍然有效。循環使用標籤的軸並從**兩個**圖中選擇相應的網格線。 – Mark

+0

我剛試過你的解決方案,當我有兩個情節工作; http://plnkr.co/edit/HE2f7JLZOjXV0JLf7iGY?p=preview,但它似乎不工作?它不會選擇其他x軸刻度? –