openstudio-workflow 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ # Packaged Measure Folder
2
+
3
+ This folder is used to ship packaged measures with the AMIs.
4
+
5
+ Current the only packaged measure is the StandardReports because it is run every simulation. This folder will be copied into each data_point folder for now, but will eventually be part of the standard upload of the project and live in the scripts
@@ -0,0 +1,212 @@
1
+ require 'erb'
2
+
3
+ #start the measure
4
+ class StandardReports < OpenStudio::Ruleset::ReportingUserScript
5
+
6
+ #define the name that a user will see, this method may be deprecated as
7
+ #the display name in PAT comes from the name field in measure.xml
8
+ def name
9
+ return "Standard Reports"
10
+ end
11
+
12
+ #define the arguments that the user will input
13
+ def arguments()
14
+ args = OpenStudio::Ruleset::OSArgumentVector.new
15
+
16
+ return args
17
+ end #end the arguments method
18
+
19
+ #sql_query method
20
+ def sql_query(sql, report_name, query)
21
+ val = 10e9
22
+ result = sql.execAndReturnFirstDouble("SELECT Value FROM TabularDataWithStrings WHERE ReportName='#{report_name}' AND #{query}")
23
+ if not result.empty?
24
+ val = result.get
25
+ end
26
+ return val
27
+ end
28
+
29
+ #define what happens when the measure is run
30
+ def run(runner, user_arguments)
31
+ super(runner, user_arguments)
32
+
33
+ #use the built-in error checking
34
+ if not runner.validateUserArguments(arguments(), user_arguments)
35
+ return false
36
+ end
37
+
38
+ os_version = OpenStudio::VersionString.new(OpenStudio::openStudioVersion())
39
+ min_version_feature1 = OpenStudio::VersionString.new("1.2.3")
40
+
41
+ # get the last model and sql file
42
+
43
+ model = runner.lastOpenStudioModel
44
+ if model.empty?
45
+ runner.registerError("Cannot find last model.")
46
+ return false
47
+ end
48
+ model = model.get
49
+
50
+ sqlFile = runner.lastEnergyPlusSqlFile
51
+ if sqlFile.empty?
52
+ runner.registerError("Cannot find last sql file.")
53
+ return false
54
+ end
55
+ sqlFile = sqlFile.get
56
+ model.setSqlFile(sqlFile)
57
+
58
+ # put data into variables, these are available in the local scope binding
59
+ #building_name = model.getBuilding.name.get
60
+
61
+ web_asset_path = OpenStudio::getSharedResourcesPath() / OpenStudio::Path.new("web_assets")
62
+
63
+ energy = "var consumption = {\n"
64
+ fuel_type = ""
65
+ units = ""
66
+
67
+ site_energy_use = 0.0
68
+ OpenStudio::EndUseFuelType::getValues.each do |fuel_type|
69
+ energy << "\t\""
70
+ fuel_type = OpenStudio::EndUseFuelType.new(fuel_type).valueDescription
71
+ energy << OpenStudio::EndUseFuelType.new(fuel_type).valueDescription # append this to remove whitespace between words ".delete(' ')"
72
+ energy << " Consumption\":{\n\t\t\"units\":"
73
+ if fuel_type == "Electricity"
74
+ units = "\"kWh\""
75
+ unit_str = "kWh"
76
+ else
77
+ units = "\"Million Btu\""
78
+ unit_str = "MBtu"
79
+ end
80
+ fuel_type_aggregation = 0.0
81
+ energy << units
82
+ energy << ",\n\t\t\"data\":{\n\t\t\t\""
83
+ OpenStudio::EndUseCategoryType::getValues.each do |category_type|
84
+ fuel_and_category_aggregation = 0.0
85
+ category_str = OpenStudio::EndUseCategoryType.new(category_type).valueDescription
86
+ energy << category_str # append this to remove whitespace between words ".delete(' ')"
87
+ energy << "\":["
88
+ OpenStudio::MonthOfYear::getValues.each do |month|
89
+ if month >= 1 and month <= 12
90
+ if not sqlFile.energyConsumptionByMonth(OpenStudio::EndUseFuelType.new(fuel_type),
91
+ OpenStudio::EndUseCategoryType.new(category_type),
92
+ OpenStudio::MonthOfYear.new(month)).empty?
93
+ valInJ = sqlFile.energyConsumptionByMonth(OpenStudio::EndUseFuelType.new(fuel_type),
94
+ OpenStudio::EndUseCategoryType.new(category_type),
95
+ OpenStudio::MonthOfYear.new(month)).get
96
+ fuel_and_category_aggregation += valInJ
97
+ valInUnits = OpenStudio::convert(valInJ,"J",unit_str).get()
98
+ temp = sprintf "%.3f", valInUnits
99
+ energy << temp.to_s
100
+ energy << ","
101
+ if os_version >= min_version_feature1
102
+ month_str = OpenStudio::MonthOfYear.new(month).valueDescription
103
+ prefix_str = OpenStudio::toUnderscoreCase("#{fuel_type}_#{category_str}_#{month_str}")
104
+ runner.registerValue("#{prefix_str}_si",valInJ,"J")
105
+ runner.registerValue("#{prefix_str}_ip",valInUnits,unit_str)
106
+ end
107
+ else
108
+ energy << "0,"
109
+ end
110
+ end
111
+ end
112
+ energy = energy[0..-2]
113
+ energy << "],\n\t\t\t\""
114
+ if (os_version >= min_version_feature1)
115
+ prefix_str = OpenStudio::toUnderscoreCase("#{fuel_type}_#{category_str}")
116
+ runner.registerValue("#{prefix_str}_si",fuel_and_category_aggregation,"J")
117
+ runner.registerValue("#{prefix_str}_ip",OpenStudio::convert(fuel_and_category_aggregation,"J",unit_str).get,unit_str)
118
+ end
119
+ fuel_type_aggregation += fuel_and_category_aggregation
120
+ end
121
+ energy = energy[0..-7]
122
+ energy << "\n\t\t}\n\t},\n"
123
+ if (os_version >= min_version_feature1)
124
+ runner.registerValue(OpenStudio::toUnderscoreCase("#{fuel_type}_si"),fuel_type_aggregation,"J")
125
+ runner.registerValue(OpenStudio::toUnderscoreCase("#{fuel_type}_ip"),
126
+ OpenStudio::convert(fuel_type_aggregation,"J",unit_str).get,
127
+ unit_str)
128
+ end
129
+ site_energy_use += fuel_type_aggregation
130
+ end
131
+ energy = energy[0..-3]
132
+ energy << "\n};\n"
133
+ if (os_version >= min_version_feature1)
134
+ runner.registerValue("site_energy_use_si",OpenStudio::convert(site_energy_use,"J","GJ").get,"GJ")
135
+ runner.registerValue("site_energy_use_ip",OpenStudio::convert(site_energy_use,"J","MBtu").get,"MBtu")
136
+
137
+ # queries that don't have API methods yet
138
+ total_building_area = sql_query(sqlFile, 'AnnualBuildingUtilityPerformanceSummary', "TableName='Building Area' AND RowName='Total Building Area' AND ColumnName='Area'")
139
+ runner.registerValue("total_building_area",total_building_area,"m2")
140
+
141
+ net_conditioned_building_area = sql_query(sqlFile, 'AnnualBuildingUtilityPerformanceSummary', "TableName='Building Area' AND RowName='Net Conditioned Building Area' AND ColumnName='Area'")
142
+ runner.registerValue("net_conditioned_building_area",net_conditioned_building_area,"m2")
143
+
144
+ unconditioned_building_area = sql_query(sqlFile, 'AnnualBuildingUtilityPerformanceSummary', "TableName='Building Area' AND RowName='Unconditioned Building Area' AND ColumnName='Area'")
145
+ runner.registerValue("unconditioned_building_area",unconditioned_building_area,"m2")
146
+
147
+ total_site_energy_eui = sql_query(sqlFile, 'AnnualBuildingUtilityPerformanceSummary', "TableName='Site and Source Energy' AND RowName='Total Site Energy' AND ColumnName='Energy Per Conditioned Building Area'")
148
+ runner.registerValue("total_site_energy_eui",total_site_energy_eui,"MJ/m2")
149
+
150
+ total_source_energy_eui = sql_query(sqlFile, 'AnnualBuildingUtilityPerformanceSummary', "TableName='Site and Source Energy' AND RowName='Total Source Energy' AND ColumnName='Energy Per Conditioned Building Area'")
151
+ runner.registerValue("total_source_energy_eui",total_source_energy_eui,"MJ/m2")
152
+
153
+ time_setpoint_not_met_during_occupied_heating = sql_query(sqlFile, 'AnnualBuildingUtilityPerformanceSummary', "TableName='Comfort and Setpoint Not Met Summary' AND RowName='Time Setpoint Not Met During Occupied Heating' AND ColumnName='Facility'")
154
+ runner.registerValue("time_setpoint_not_met_during_occupied_heating",time_setpoint_not_met_during_occupied_heating,"hr")
155
+
156
+ time_setpoint_not_met_during_occupied_cooling = sql_query(sqlFile, 'AnnualBuildingUtilityPerformanceSummary', "TableName='Comfort and Setpoint Not Met Summary' AND RowName='Time Setpoint Not Met During Occupied Cooling' AND ColumnName='Facility'")
157
+ runner.registerValue("time_setpoint_not_met_during_occupied_cooling",time_setpoint_not_met_during_occupied_cooling,"hr")
158
+
159
+ time_setpoint_not_met_during_occupied_hours = time_setpoint_not_met_during_occupied_heating + time_setpoint_not_met_during_occupied_cooling
160
+ runner.registerValue("time_setpoint_not_met_during_occupied_hours",time_setpoint_not_met_during_occupied_hours,"hr")
161
+
162
+ total_life_cycle_cost = sql_query(sqlFile, 'Life-Cycle Cost Report', "TableName='Present Value by Category' AND RowName='Grand Total' AND ColumnName='Present Value'")
163
+ runner.registerValue("total_life_cycle_cost",total_life_cycle_cost,"$")
164
+
165
+ end
166
+
167
+ # echo out our values
168
+ #runner.registerInfo("This building is named #{building_name}.")
169
+
170
+ # read in template
171
+ html_in_path = "#{File.dirname(__FILE__)}/resources/report.html.in"
172
+ if File.exist?(html_in_path)
173
+ html_in_path = html_in_path
174
+ else
175
+ html_in_path = "#{File.dirname(__FILE__)}/report.html.in"
176
+ end
177
+ html_in = ""
178
+ File.open(html_in_path, 'r') do |file|
179
+ html_in = file.read
180
+ end
181
+
182
+ # configure template with variable values
183
+ renderer = ERB.new(html_in)
184
+ html_out = renderer.result(binding)
185
+
186
+ # write html file
187
+ html_out_path = 'report.html'
188
+ File.open(html_out_path, 'w') do |file|
189
+ file << html_out
190
+
191
+ # make sure data is written to the disk one way or the other
192
+ begin
193
+ file.fsync
194
+ rescue
195
+ file.flush
196
+ end
197
+ end
198
+
199
+ #closing the sql file
200
+ sqlFile.close
201
+
202
+ #reporting final condition
203
+ runner.registerFinalCondition("Standard Report generated successfully.")
204
+
205
+ return true
206
+
207
+ end #end the run method
208
+
209
+ end #end the measure
210
+
211
+ #this allows the measure to be use by the application
212
+ StandardReports.new.registerWithApplication
@@ -0,0 +1,53 @@
1
+ <measure>
2
+ <name>Standard Reports</name>
3
+ <uid>fc337100-8634-404e-8966-01243d292a79</uid>
4
+ <version_id>4f1230e3-0954-43ab-a772-c345030ab14b</version_id>
5
+ <description>Change me</description>
6
+ <modeler_description>Change me</modeler_description>
7
+ <provenances/>
8
+ <tags>
9
+ <tag>Reporting.QAQC</tag>
10
+ </tags>
11
+ <attributes>
12
+ <attribute>
13
+ <name>Measure Type</name>
14
+ <value>ReportingMeasure</value>
15
+ <datatype>string</datatype>
16
+ </attribute>
17
+ <attribute>
18
+ <name>Uses SketchUp API</name>
19
+ <value>false</value>
20
+ <datatype>boolean</datatype>
21
+ </attribute>
22
+ </attributes>
23
+ <files>
24
+ <file>
25
+ <filename>ExampleModel.osm</filename>
26
+ <filetype>osm</filetype>
27
+ <usage_type>test</usage_type>
28
+ <checksum>0D4162D2</checksum>
29
+ </file>
30
+ <file>
31
+ <filename>report.html.in</filename>
32
+ <filetype>in</filetype>
33
+ <usage_type>resource</usage_type>
34
+ <checksum>093FE760</checksum>
35
+ </file>
36
+ <file>
37
+ <filename>StandardReports_Test.rb</filename>
38
+ <filetype>rb</filetype>
39
+ <usage_type>test</usage_type>
40
+ <checksum>6790E2F5</checksum>
41
+ </file>
42
+ <file>
43
+ <version>
44
+ <software_program>OpenStudio</software_program>
45
+ <identifier>1.1.2</identifier>
46
+ </version>
47
+ <filename>measure.rb</filename>
48
+ <filetype>rb</filetype>
49
+ <usage_type>script</usage_type>
50
+ <checksum>4263B498</checksum>
51
+ </file>
52
+ </files>
53
+ </measure>
@@ -0,0 +1,298 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>Results | OpenStudio</title>
6
+ <link href="http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.2/css/bootstrap.min.css" rel="stylesheet">
7
+ <link href="file:///<%= web_asset_path %>/bootstrap.min.css" rel="stylesheet">
8
+ <style type="text/css">
9
+ body {
10
+ font: 10px sans-serif;
11
+ min-width: 1280px;
12
+ }
13
+ table {
14
+ max-width:800px;
15
+ }
16
+ .axis path, .axis line {
17
+ fill: none;
18
+ stroke: #000;
19
+ shape-rendering: crispEdges;
20
+ }
21
+ .bar {
22
+ fill: steelblue;
23
+ }
24
+ .x.axis path {
25
+ display: none;
26
+ }
27
+ .d3-tip {
28
+ line-height: 1;
29
+ font-weight: bold;
30
+ padding: 12px;
31
+ background: rgba(0, 0, 0, 0.8);
32
+ color: #fff;
33
+ border-radius: 2px;
34
+ }
35
+ /* Creates a small triangle extender for the tooltip */
36
+ .d3-tip:after {
37
+ box-sizing: border-box;
38
+ display: inline;
39
+ font-size: 10px;
40
+ width: 100%;
41
+ line-height: 1;
42
+ color: rgba(0, 0, 0, 0.8);
43
+ content:"\25BC";
44
+ position: absolute;
45
+ text-align: center;
46
+ }
47
+ /* Style northward tooltips differently */
48
+ .d3-tip.n:after {
49
+ margin: -1px 0 0 0;
50
+ top: 100%;
51
+ left: 0;
52
+ }
53
+ </style>
54
+ <script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
55
+ <script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/d3/3.3.9/d3.min.js"></script>
56
+ <script type="text/javascript" src="file:///<%= web_asset_path %>/jquery.min.js"></script>
57
+ <script type="text/javascript" src="file:///<%= web_asset_path %>/d3.min.js"></script>
58
+ <script type="text/javascript">
59
+ // http://labratrevenge.com/d3-tip/javascripts/d3.tip.min.js
60
+ d3.tip=function(){function t(t){v=m(t),w=v.createSVGPoint(),document.body.appendChild(x)}function e(){return"n"}function n(){return[0,0]}function r(){return" "}function o(){var t=p();return{top:t.n.y-x.offsetHeight,left:t.n.x-x.offsetWidth/2}}function s(){var t=p();return{top:t.s.y,left:t.s.x-x.offsetWidth/2}}function l(){var t=p();return{top:t.e.y-x.offsetHeight/2,left:t.e.x}}function u(){var t=p();return{top:t.w.y-x.offsetHeight/2,left:t.w.x-x.offsetWidth}}function f(){var t=p();return{top:t.nw.y-x.offsetHeight,left:t.nw.x-x.offsetWidth}}function i(){var t=p();return{top:t.ne.y-x.offsetHeight,left:t.ne.x}}function a(){var t=p();return{top:t.sw.y,left:t.sw.x-x.offsetWidth}}function c(){var t=p();return{top:t.se.y,left:t.e.x}}function d(){var t=d3.select(document.createElement("div"));return t.style({position:"absolute",opacity:0,pointerEvents:"none",boxSizing:"border-box"}),t.node()}function m(t){return t=t.node(),"svg"==t.tagName.toLowerCase()?t:t.ownerSVGElement}function p(){var t=d3.event.target,e={},n=t.getScreenCTM(),r=t.getBBox(),o=r.width,s=r.height,l=r.x,u=r.y,f=document.body.scrollTop,i=document.body.scrollLeft;return document.documentElement&&document.documentElement.scrollTop&&(f=document.documentElement.scrollTop,i=document.documentElement.scrollLeft),w.x=l+i,w.y=u+f,e.nw=w.matrixTransform(n),w.x+=o,e.ne=w.matrixTransform(n),w.y+=s,e.se=w.matrixTransform(n),w.x-=o,e.sw=w.matrixTransform(n),w.y-=s/2,e.w=w.matrixTransform(n),w.x+=o,e.e=w.matrixTransform(n),w.x-=o/2,w.y-=s/2,e.n=w.matrixTransform(n),w.y+=s,e.s=w.matrixTransform(n),e}var y=e,g=n,h=r,x=d(),v=null,w=null;t.show=function(){var e,n=h.apply(this,arguments),r=g.apply(this,arguments),o=y.apply(this,arguments),s=d3.select(x),l=0;for(s.html(n).style({opacity:1,pointerEvents:"all"});l--;)s.classed(E[l],!1);return e=T.get(o).apply(this),s.classed(o,!0).style({top:e.top+r[0]+"px",left:e.left+r[1]+"px"}),t},t.hide=function(){return nodel=d3.select(x),nodel.style({opacity:0,pointerEvents:"none"}),t},t.attr=function(e){if(2>arguments.length&&"string"==typeof e)return d3.select(x).attr(e);var n=Array.prototype.slice.call(arguments);return d3.selection.prototype.attr.apply(d3.select(x),n),t},t.style=function(e){if(2>arguments.length&&"string"==typeof e)return d3.select(x).style(e);var n=Array.prototype.slice.call(arguments);return d3.selection.prototype.style.apply(d3.select(x),n),t},t.direction=function(e){return arguments.length?(y=null==e?e:d3.functor(e),t):y},t.offset=function(e){return arguments.length?(g=null==e?e:d3.functor(e),t):g},t.html=function(e){return arguments.length?(h=null==e?e:d3.functor(e),t):h};var T=d3.map({n:o,s:s,e:l,w:u,nw:f,ne:i,sw:a,se:c}),E=T.keys();return t};
61
+ </script>
62
+ </head>
63
+ <body>
64
+ <div class="row-fluid">
65
+ <div class="span5">
66
+ <h4 id="title-0"></h4>
67
+ <div id="chart-0"></div>
68
+ </div>
69
+ <div class="span7">
70
+ <h4 id="title-1"></h4>
71
+ <div id="chart-1"></div>
72
+ </div>
73
+ </div>
74
+ <script type="text/javascript">
75
+ function numFormat(n) {
76
+ var parts = n.toString().split(".");
77
+ return parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",") + (parts[1] ? "." + parts[1] : "");
78
+ }
79
+
80
+ var months = [
81
+ "Jan",
82
+ "Feb",
83
+ "Mar",
84
+ "Apr",
85
+ "May",
86
+ "Jun",
87
+ "Jul",
88
+ "Aug",
89
+ "Sep",
90
+ "Oct",
91
+ "Nov",
92
+ "Dec"];
93
+
94
+ <%= energy %>
95
+
96
+ function outputTable(name, units, obj) {
97
+ if (name == "Electricity Consumption" | name == "Natural Gas Consumption" | name == "District Cooling Consumption" | name == "District Heating Consumption") {
98
+ $('<h4>').text(name + " (" + units + ")").appendTo('body');
99
+ var $table = $('<table id="' + name.toLowerCase().replace(/ /g, '-') + '">').addClass("table table-striped table-bordered table-condensed");
100
+ $table.append('<thead>').children('thead').append('<tr />').children('tr').append('<th>&nbsp;</th><th>Jan</th><th>Feb</th><th>Mar</th><th>Apr</th><th>May</th><th>Jun</th><th>Jul</th><th>Aug</th><th>Sep</th><th>Oct</th><th>Nov</th><th>Dec</th><th>Total</th>');
101
+ var $tbody = $table.append('<tbody />').children('tbody');
102
+ var key;
103
+ var totalTotal = 0;
104
+ var columnTotal = [];
105
+ for (key in obj) {
106
+ if (obj.hasOwnProperty(key)) {
107
+ var $row = $tbody.append('<tr />').children('tr:last');
108
+ $row.append("<td>" + key + "</td>");
109
+ var total = 0;
110
+ for (i = 0; i < obj[key].length; i++) {
111
+ if (columnTotal[i] === undefined) columnTotal[i] = 0;
112
+ $row.append("<td>" + (obj[key][i] === 0 ? "&mdash;" : numFormat(obj[key][i])) + "</td>");
113
+ total += obj[key][i];
114
+ columnTotal[i] += obj[key][i];
115
+ }
116
+ totalTotal += total;
117
+ $row.append("<td>" + (total === 0 ? "&mdash;" : numFormat(total.toFixed(3))) + "</td>");
118
+ }
119
+ }
120
+ // Append column totals as new, last row of table
121
+ if (columnTotal[columnTotal.length] === undefined) columnTotal[columnTotal.length] = 0;
122
+ columnTotal[columnTotal.length - 1] = totalTotal;
123
+ var $row = $tbody.append('<tr />').children('tr:last');
124
+ $row.append("<td>Total</td>");
125
+ for (i = 0; i < columnTotal.length; i++) {
126
+ $row.append("<td>" + (columnTotal[i] === 0 ? "&mdash;" : numFormat(columnTotal[i].toFixed(3))) + "</td>");
127
+ }
128
+ $table.appendTo('body');
129
+ }
130
+ }
131
+
132
+ $.each(consumption, function (key, obj) {
133
+ outputTable(key, obj.units, obj.data);
134
+ });
135
+
136
+ var margin = {
137
+ top: 20.5,
138
+ right: 20,
139
+ bottom: 30,
140
+ left: 40.5
141
+ },
142
+ width = 560 - margin.left - margin.right,
143
+ height = 300 - margin.top - margin.bottom;
144
+
145
+ var x = d3.scale.ordinal()
146
+ .rangeRoundBands([0, width], 0.1);
147
+
148
+ var y = d3.scale.linear()
149
+ .rangeRound([height, 0]);
150
+
151
+ var color = d3.scale.ordinal()
152
+ .range(["#EF1C21", "#0071BD", "#F7DF10", "#DEC310", "#4A4D4A", "#B5B2B5", "#FF79AD", "#632C94", "#F75921", "#293094", "#CE5921", "#FFB239", "#29AAE7", "#8CC739"]);
153
+
154
+ var xAxis = d3.svg.axis()
155
+ .scale(x)
156
+ .orient("bottom");
157
+
158
+ var yAxis = d3.svg.axis()
159
+ .scale(y)
160
+ .orient("left")
161
+ .tickFormat(d3.format(".2s"));
162
+
163
+ var tip = d3.tip()
164
+ .attr('class', 'd3-tip')
165
+ .offset([-10, 0])
166
+ .html(function (d) {
167
+ return "<strong>" + d.name + ":</strong> <span style='color:red'>" + (d.y1 - d.y0).toFixed(2) + "</span>";
168
+ });
169
+
170
+ var charts = ["Electricity Consumption", "Natural Gas Consumption"];
171
+
172
+ for (var c in charts) {
173
+
174
+ if (c == charts.length - 1) {
175
+ margin.right = 125;
176
+ }
177
+
178
+ $('#title-' + c).text(charts[c]);
179
+
180
+ var svg = d3.select("#chart-" + c).append("svg")
181
+ .attr("width", width + margin.left + margin.right)
182
+ .attr("height", height + margin.top + margin.bottom)
183
+ .append("g")
184
+ .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
185
+ svg.call(tip);
186
+
187
+ data = [];
188
+ for (var enduse in consumption[charts[c]].data) {
189
+ var enduse_data = consumption[charts[c]].data[enduse];
190
+ for (var month = 0; month < months.length; month++) {
191
+ if (data.length < months.length) {
192
+ var temp = {
193
+ "Month": months[month]
194
+ };
195
+ temp[enduse] = enduse_data[month];
196
+ data.push(temp);
197
+ } else {
198
+ data[month][enduse] = enduse_data[month];
199
+ }
200
+ }
201
+ }
202
+ color.domain(d3.keys(data[0]).filter(function (key) {
203
+ return key !== "Month";
204
+ }));
205
+
206
+ data.forEach(function (d) {
207
+ var y0 = 0;
208
+ d.consumption = color.domain().map(function (name) {
209
+ return {
210
+ name: name,
211
+ y0: y0,
212
+ y1: y0 += +d[name]
213
+ };
214
+ });
215
+ d.total = d.consumption[d.consumption.length - 1].y1;
216
+ });
217
+
218
+ //data.sort(function(a, b) { return b.total - a.total; });
219
+
220
+ x.domain(data.map(function (d) {
221
+ return d.Month;
222
+ }));
223
+ y.domain([0, d3.max(data, function (d) {
224
+ return d.total;
225
+ })]);
226
+
227
+ svg.append("g")
228
+ .attr("class", "x axis")
229
+ .attr("transform", "translate(0," + height + ")")
230
+ .call(xAxis);
231
+
232
+ svg.append("g")
233
+ .attr("class", "y axis")
234
+ .call(yAxis)
235
+ .append("text")
236
+ .attr("transform", "rotate(-90)")
237
+ .attr("y", -36)
238
+ .attr("dy", ".71em")
239
+ .style("text-anchor", "end")
240
+ .text(consumption[charts[c]].units);
241
+
242
+ var month = svg.selectAll(".month")
243
+ .data(data)
244
+ .enter().append("g")
245
+ .attr("class", "g")
246
+ .attr("transform", function (d) {
247
+ return "translate(" + x(d.Month) + ",0)";
248
+ });
249
+
250
+ month.selectAll("rect")
251
+ .data(function (d) {
252
+ return d.consumption;
253
+ })
254
+ .enter().append("rect")
255
+ .attr("width", x.rangeBand())
256
+ .attr("y", function (d) {
257
+ return y(d.y1);
258
+ })
259
+ .attr("height", function (d) {
260
+ return y(d.y0) - y(d.y1);
261
+ })
262
+ .style("fill", function (d) {
263
+ return color(d.name);
264
+ })
265
+ .on('mouseover', tip.show)
266
+ .on('mouseout', tip.hide);
267
+
268
+ if (c == charts.length - 1) {
269
+ var legend = svg.selectAll(".legend")
270
+ .data(color.domain().slice())
271
+ .enter().append("g")
272
+ .attr("class", "legend")
273
+ .attr("transform", function (d, i) {
274
+ return "translate(0," + i * 20 + ")";
275
+ });
276
+
277
+ legend.append("rect")
278
+ .attr("x", width + 105)
279
+ .attr("width", 18)
280
+ .attr("height", 18)
281
+ .style("fill", color);
282
+
283
+ legend.append("text")
284
+ .attr("x", width + 105 - 3)
285
+ .attr("y", 9)
286
+ .attr("dy", ".35em")
287
+ .style("text-anchor", "end")
288
+ .text(function (d) {
289
+ return d;
290
+ });
291
+ }
292
+
293
+ svg.selectAll(".g").attr("stroke", "black")
294
+ .attr("stroke-width", "1");
295
+ }
296
+ </script>
297
+ </body>
298
+ </html>