| 45 | |
| 46 | === UKESM AMIP (u-bh142) === |
| 47 | |
| 48 | {{{ |
| 49 | #!html |
| 50 | <html> |
| 51 | <meta charset="utf-8"> |
| 52 | |
| 53 | <!-- Example based on http://bl.ocks.org/mbostock/3887118 --> |
| 54 | <!-- Tooltip example from http://www.d3noob.org/2013/01/adding-tooltips-to-d3js-graph.html --> |
| 55 | <!-- Coding style based on http://gist.github.com/mbostock/5977197 --> |
| 56 | |
| 57 | <style> |
| 58 | body { |
| 59 | font: 11px sans-serif; |
| 60 | } |
| 61 | |
| 62 | .axis path, |
| 63 | .axis line { |
| 64 | fill: none; |
| 65 | stroke: #000; |
| 66 | shape-rendering: crispEdges; |
| 67 | } |
| 68 | |
| 69 | .dot { |
| 70 | stroke: #000; |
| 71 | } |
| 72 | |
| 73 | .tooltip { |
| 74 | position: absolute; |
| 75 | width: 200px; |
| 76 | height: 28px; |
| 77 | pointer-events: none; |
| 78 | } |
| 79 | </style> |
| 80 | <body> |
| 81 | <script src="https://d3js.org/d3.v3.min.js"></script> |
| 82 | |
| 83 | <!-- Add 2 buttons --> |
| 84 | <button onclick="update_x_axis(data, 'ncpus')">Years/Day vs nCPUs</button> |
| 85 | <button onclick="update_x_axis(data, 'CostPerYear')">Years/Day vs Cost/Year</button> |
| 86 | |
| 87 | <script> |
| 88 | |
| 89 | function update_x_axis(d, key){ |
| 90 | for (var i = 0; i < d.length; i++){ |
| 91 | d[i].x_value = d[i][key]; |
| 92 | // console.log(d[i]['x_value']); |
| 93 | } |
| 94 | |
| 95 | refresh_graph(key); |
| 96 | } |
| 97 | |
| 98 | |
| 99 | var base_width = 760; |
| 100 | |
| 101 | |
| 102 | |
| 103 | var base_height = 280; |
| 104 | |
| 105 | |
| 106 | |
| 107 | var margin = {top: 20, right: 20, bottom: 30, left: 40}, |
| 108 | width = base_width - margin.left - margin.right, |
| 109 | height = base_height - margin.top - margin.bottom; |
| 110 | /* |
| 111 | * value accessor - returns the value to encode for a given data object. |
| 112 | * scale - maps value to a visual display encoding, such as a pixel position. |
| 113 | * map function - maps from data value to display value |
| 114 | * axis - sets up axis |
| 115 | */ |
| 116 | |
| 117 | |
| 118 | // setup x |
| 119 | var xValue = function(d) { return d.x_value;}, // data -> value |
| 120 | xScale = d3.scale.linear().range([0, width]), // value -> display |
| 121 | xMap = function(d) { return xScale(xValue(d));}, // data -> display |
| 122 | xAxis = d3.svg.axis().scale(xScale).orient("bottom"); |
| 123 | |
| 124 | // setup y |
| 125 | var yValue = function(d) { return d.YearsPerDay;}, // data -> value |
| 126 | yScale = d3.scale.linear().range([height, 0]), // value -> display |
| 127 | yMap = function(d) { return yScale(yValue(d));}, // data -> display |
| 128 | yAxis = d3.svg.axis().scale(yScale).orient("left"); |
| 129 | |
| 130 | // setup fill color |
| 131 | var cValue = function(d) { return d.nOMP;}, |
| 132 | color = d3.scale.category10(); |
| 133 | |
| 134 | |
| 135 | // add the graph canvas to the body of the webpage |
| 136 | var svg = d3.select("body").append("svg") |
| 137 | .attr("width", width + margin.left + margin.right) |
| 138 | .attr("height", height + margin.top + margin.bottom) |
| 139 | .append("g") |
| 140 | .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); |
| 141 | |
| 142 | |
| 143 | // add the tooltip area to the webpage |
| 144 | var tooltip = d3.select("body").append("div") |
| 145 | .attr("class", "tooltip") |
| 146 | .style("opacity", 0); |
| 147 | |
| 148 | var data = [{"EW": 24, "NS": 21, "nOMP": 2, "walltime": 7176.0, "ncpus": 1008, "YearsPerDay": 3.0100334448160537, "CostPerYear": 120.5568}, {"EW": 30, "NS": 28, "nOMP": 1, "walltime": 9100.0, "ncpus": 840, "YearsPerDay": 2.3736263736263736, "CostPerYear": 127.39999999999999}, {"EW": 24, "NS": 25, "nOMP": 2, "walltime": 6985.0, "ncpus": 1200, "YearsPerDay": 3.0923407301360055, "CostPerYear": 139.7}, {"EW": 26, "NS": 18, "nOMP": 1, "walltime": 11375.0, "ncpus": 480, "YearsPerDay": 1.898901098901099, "CostPerYear": 91.0}, {"EW": 26, "NS": 24, "nOMP": 2, "walltime": 6833.0, "ncpus": 1248, "YearsPerDay": 3.161129811210303, "CostPerYear": 142.1264}, {"EW": 36, "NS": 28, "nOMP": 1, "walltime": 8064.0, "ncpus": 1008, "YearsPerDay": 2.6785714285714284, "CostPerYear": 135.4752}, {"EW": 14, "NS": 18, "nOMP": 2, "walltime": 11729.0, "ncpus": 504, "YearsPerDay": 1.8415892232926934, "CostPerYear": 98.52359999999999}, {"EW": 18, "NS": 20, "nOMP": 2, "walltime": 9468.0, "ncpus": 720, "YearsPerDay": 2.2813688212927756, "CostPerYear": 113.61599999999999}, {"EW": 24, "NS": 21, "nOMP": 2, "walltime": 6546.0, "ncpus": 1008, "YearsPerDay": 3.2997250229147568, "CostPerYear": 109.97279999999999}, {"EW": 26, "NS": 24, "nOMP": 1, "walltime": 9334.0, "ncpus": 624, "YearsPerDay": 2.3141204199700023, "CostPerYear": 97.07359999999998}, {"EW": 18, "NS": 20, "nOMP": 2, "walltime": 9792.0, "ncpus": 720, "YearsPerDay": 2.2058823529411766, "CostPerYear": 117.50399999999999}, {"EW": 14, "NS": 18, "nOMP": 2, "walltime": 11814.0, "ncpus": 504, "YearsPerDay": 1.8283392585068563, "CostPerYear": 99.2376}]; |
| 149 | var graph_labels = { |
| 150 | "x_axis" : { |
| 151 | "ncpus" : "CPUs", |
| 152 | "CostPerYear": "kAU per Model Year" |
| 153 | }, |
| 154 | "y_axis" : "Model Years Per Day" |
| 155 | } |
| 156 | |
| 157 | function refresh_graph(label_code){ |
| 158 | |
| 159 | // don't want dots overlapping axis, so add in buffer to data domain |
| 160 | xScale.domain([d3.min(data, xValue)-1, d3.max(data, xValue)+1]); |
| 161 | yScale.domain([d3.min(data, yValue)-0.1, d3.max(data, yValue)+0.1]); |
| 162 | |
| 163 | // x-axis (remove (both???) axes first?? |
| 164 | d3.select("svg").selectAll(".axis").remove(); |
| 165 | svg.append("g") |
| 166 | .attr("class", "x axis") |
| 167 | .attr("transform", "translate(0," + height + ")") |
| 168 | .call(xAxis) |
| 169 | .append("text") |
| 170 | .attr("class", "label") |
| 171 | .attr("x", width) |
| 172 | .attr("y", -6) |
| 173 | .style("text-anchor", "end") |
| 174 | .text(graph_labels["x_axis"][label_code]); |
| 175 | |
| 176 | // y-axis |
| 177 | svg.append("g") |
| 178 | .attr("class", "y axis") |
| 179 | .call(yAxis) |
| 180 | .append("text") |
| 181 | .attr("class", "label") |
| 182 | .attr("transform", "rotate(-90)") |
| 183 | .attr("y", 6) |
| 184 | .attr("dy", ".71em") |
| 185 | .style("text-anchor", "end") |
| 186 | .text(graph_labels["y_axis"]); |
| 187 | // draw dots |
| 188 | d3.select("svg").selectAll(".dot").remove(); |
| 189 | svg.selectAll(".dot") |
| 190 | .data(data) |
| 191 | .enter().append("circle") |
| 192 | .attr("class", "dot") |
| 193 | .attr("r", 3.5) |
| 194 | .attr("cx", xMap) |
| 195 | .attr("cy", yMap) |
| 196 | .style("fill", function(d) { return color(cValue(d));}) |
| 197 | .on("mouseover", function(d) { |
| 198 | tooltip.transition() |
| 199 | .duration(200) |
| 200 | .style("opacity", .9); |
| 201 | tooltip.html("nOMP = " + d.nOMP + "<br/> (NS, EW) = (" + d.NS |
| 202 | + ", " + d.EW + ")") |
| 203 | .style("left", (d3.event.pageX + 5) + "px") |
| 204 | .style("top", (d3.event.pageY - 28) + "px"); |
| 205 | }) |
| 206 | .on("mouseout", function(d) { |
| 207 | tooltip.transition() |
| 208 | .duration(500) |
| 209 | .style("opacity", 0); |
| 210 | }); |
| 211 | |
| 212 | // draw legend |
| 213 | var legend = svg.selectAll(".legend") |
| 214 | .data(color.domain()) |
| 215 | .enter().append("g") |
| 216 | .attr("class", "legend") |
| 217 | .attr("transform", function(d, i) { return "translate(-10," + i * 20 + ")"; }); |
| 218 | |
| 219 | // draw legend colored rectangles |
| 220 | legend.append("rect") |
| 221 | .attr("x", width - 18) |
| 222 | .attr("width", 18) |
| 223 | .attr("height", 18) |
| 224 | .style("fill", color); |
| 225 | |
| 226 | // draw legend text |
| 227 | legend.append("text") |
| 228 | .attr("x", width - 24) |
| 229 | .attr("y", 9) |
| 230 | .attr("dy", ".35em") |
| 231 | .style("text-anchor", "end") |
| 232 | .text(function(d) { return d;}); |
| 233 | //}); |
| 234 | }; |
| 235 | // initially choose ncpus |
| 236 | update_x_axis(data, 'ncpus') |
| 237 | |
| 238 | </script> |
| 239 | </body> |
| 240 | </html> |
| 241 | |
| 242 | }}} |