Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate Historic Data, Showing In Simple Table #94

Merged
merged 14 commits into from
May 8, 2024
32 changes: 29 additions & 3 deletions gridsome.server.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const parse = require('csv-parse/sync').parse;
const DataDirectory = './src/data/dist/';

const BuildingEmissionsDataFile = 'building-benchmarks.csv';
const HistoricBenchmarkingDataFile = 'benchmarking-all-years.csv';

// This is an array equivalent of Object.keys(BuildingOwners) but this file can't use Typescript and
// import that file
Expand All @@ -34,6 +35,7 @@ module.exports = function(api) {
// Use the Data Store API here: https://gridsome.org/docs/data-store-api/
api.loadSource(async (actions) => {
loadBuildingBenchmarkData(actions);
loadHistoricBenchmarkDat(actions);
});

// Use the Pages API here: https://gridsome.org/docs/pages-api/
Expand All @@ -56,19 +58,19 @@ module.exports = function(api) {
* @param {unknown} actions The actions class?
*/
function loadBuildingBenchmarkData(actions) {
const input = readFileSync(`${DataDirectory}${BuildingEmissionsDataFile}`, 'utf8');
const latestBenchmarksRaw = readFileSync(`${DataDirectory}${BuildingEmissionsDataFile}`, 'utf8');

/**
* Load in building benchmarks and expose as Buildings collection
*/
const BuildingsData = parse(input, {
const LatestBenchmarksData = parse(latestBenchmarksRaw, {
columns: true,
skip_empty_lines: true,
});

const collection = actions.addCollection({typeName: 'Building'});

for (const building of BuildingsData) {
for (const building of LatestBenchmarksData) {
// Make a slugSource that is the property name or the address as a fallback (skip one letter
// names, e.g. '-)
building.slugSource = building.PropertyName.length > 1 ? building.PropertyName : building.Address;
Expand All @@ -80,3 +82,27 @@ function loadBuildingBenchmarkData(actions) {
collection.addNode(building);
}
}


/**
* Load in the historic benchmark data
*
* @param {unknown} actions The actions class?
*/
function loadHistoricBenchmarkDat(actions) {
const historicBenchmarksRaw = readFileSync(`${DataDirectory}${HistoricBenchmarkingDataFile}`, 'utf8');

/**
* Load in building benchmarks and expose as Buildings collection
*/
const HistoricBenchmarksData = parse(historicBenchmarksRaw, {
columns: true,
skip_empty_lines: true,
});

const collection = actions.addCollection({ typeName: 'Benchmark' });

for (const benchmark of HistoricBenchmarksData) {
collection.addNode(benchmark);
}
}
13 changes: 13 additions & 0 deletions src/common-functions.vue
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,19 @@ export interface IBuilding {
/** How GraphQL passes back a building */
export interface IBuildingNode { node: IBuilding }

export interface IHistoricData {
ID: string;
DataYear: string;
GrossFloorArea: string;
ChicagoEnergyRating: string;
ENERGYSTARScore: string;
SourceEUI: string;
ElectricityUse: string;
GHGIntensity: string;
NaturalGasUse: string;
DistrictSteamUse: string;
}

/**
* A constant for what we use as min and max values for flagged ranks
*/
Expand Down
4 changes: 2 additions & 2 deletions src/components/BuildingsTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export default class BuildingsTable extends Vue {
</script>

<template>
<div class="table-cont">
<div class="buildings-table-cont">
<table :class="{ '-wide': showSquareFootage || showGasUse || showElectricityUse }">
<thead>
<tr>
Expand Down Expand Up @@ -196,7 +196,7 @@ export default class BuildingsTable extends Vue {
<style lang="scss">
// Make the whole table scroll in a constrained container so we can have a sticky header - CSS makes
// that impossible otherwise
.table-cont {
.buildings-table-cont {
width: 100%;
max-height: 80vh;
overflow: auto;
Expand Down
160 changes: 160 additions & 0 deletions src/components/HistoricalBuildingDataTable.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
<template>
<div class="historical-table-cont">
<table class="historical-data">
<thead>
<tr>
<th scope="col">
Year
</th>
<th v-if="renderedColumns.includes('GrossFloorArea')" scope="col">
Fixed Show fixed Hide fixed
Floor Area <span class="unit">sqft</span>
</th>
<th v-if="renderedColumns.includes('ChicagoEnergyRating')" scope="col">
Fixed Show fixed Hide fixed
Chicago Energy<br> Rating
</th>
<th v-if="renderedColumns.includes('ENERGYSTARScore')" scope="col">
Fixed Show fixed Hide fixed
Energy Star<br> Score
</th>
<th scope="col">
GHG Intensity <span class="unit">kg CO<sub>2</sub>e / sqft</span>
</th>
<th scope="col">
Source EUI <span class="unit">kBtu / sqft</span>
</th>

<th scope="col">
Electricity Use <span class="unit">kBtu</span>
</th>
<th scope="col">
Natural Gas Use <span class="unit">kBtu</span>
</th>
<th v-if="renderedColumns.includes('DistrictSteamUse')" scope="col">
Fixed Show fixed Hide fixed
District Steam Use <span class="unit">kBtu</span>
</th>
</tr>
</thead>
<tbody>
<tr
v-for="benchmark in historicBenchmarks"
:key="benchmark.DataYear"
>
<td>{{ benchmark.DataYear }}</td>
<td v-if="renderedColumns.includes('GrossFloorArea')">
Fixed Show fixed Hide fixed
{{ benchmark.GrossFloorArea | optionalInt }}
</td>
<td v-if="renderedColumns.includes('ChicagoEnergyRating')">
{{ benchmark.ChicagoEnergyRating || '-' }}
</td>
<td v-if="renderedColumns.includes('ENERGYSTARScore')">
{{ benchmark.ENERGYSTARScore || '-' }}
</td>
<td>{{ benchmark.GHGIntensity }}</td>
<td>{{ benchmark.SourceEUI }}</td>

<!-- Round big numbers -->
<td>{{ benchmark.ElectricityUse | optionalInt }}</td>
<td>{{ benchmark.NaturalGasUse | optionalInt }}</td>
<td v-if="renderedColumns.includes('DistrictSteamUse')">
{{ benchmark.DistrictSteamUse | optionalInt }}
</td>
</tr>
</tbody>
</table>
</div>
</template>

<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';

import {IHistoricData} from '../common-functions.vue';

/**
* A component that given an array of a building's benchmarking renders
* a table showing columns of data with values (skipping any columns that
* never had a value, like if a building never had an Energy star score)
*/
@Component({
filters: {
/**
* Round and process an optional float to a locale string
*
* Ex: null -> '-', '12345.67' -> '12,345'
*/
optionalInt(value: string) {
if (!value) {
return '-';
}

return parseInt(value).toLocaleString();
},
}
})
Fixed Show fixed Hide fixed
export default class BuildingImage extends Vue {
@Prop({required: true}) historicBenchmarks!: Array<IHistoricData>;

renderedColumns: Array<string> = [];

getRenderedColumns(): Array<string> {
if (this.historicBenchmarks.length === 0) {
return [];
}

const allColKeys: Array<string> = Object.keys(this.historicBenchmarks[0]);
const emptyColKeys = allColKeys.filter((colKey: string) => {
// A column is empty if it's all empty string or '0', so skip it if so. Some columns switch
// between both, like Natural Gas Use on Merch Mart, which we also want to ignore
return !this.historicBenchmarks.every((datum) => {
return (datum as any)[colKey] === '' || (datum as any)[colKey] === '0.0';

Check warning

Code scanning / ESLint

Disallow the `any` type Warning

Unexpected any. Specify a different type.

Check warning

Code scanning / ESLint

Disallow the `any` type Warning

Unexpected any. Specify a different type.
});
});

return emptyColKeys;
}

created(): void {
// const emptyColumns =
console.log('historicBenchmarks', this.historicBenchmarks);
this.renderedColumns = this.getRenderedColumns();
console.log('renderedColumns', this.renderedColumns);
}
}
</script>

<style lang="scss">
.historical-table-cont {
max-width: 100%;
overflow-x: auto;
margin-top: 0.5rem;
margin-bottom: 1rem;
}

table.historical-data {
border: solid 0.125rem $grey;
border-radius: $brd-rad-small;
border-collapse: collapse;
width: 100%;
min-width: 62.5rem; // 1000px

.unit {
display: block;
font-size: 0.75rem;
font-weight: normal;
}

th, td {
padding: 0.5rem 0.75rem;
text-align: left;
}

thead {
tr { background-color: $grey; }

th {
line-height: 1.25;
font-size: 0.825rem;
}
}

tbody tr:nth-of-type(even) { background-color: $grey-light; }
}
</style>
2 changes: 0 additions & 2 deletions src/components/StatTile.vue
Original file line number Diff line number Diff line change
Expand Up @@ -301,8 +301,6 @@ export default class StatTile extends Vue {
const statStdDeviation = this.stats[this.statKey]?.std;
const statMean = this.stats[this.statKey]?.mean;

console.log({ key: this.statKey, statStdDeviation, statMean });

if (this.building[this.statKey] === null || !statStdDeviation) {
return false;
}
Expand Down
Loading
Loading