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

Update aggregation table with pivot functionality #4878

Merged
merged 2 commits into from
Nov 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 72 additions & 22 deletions seed/static/seed/partials/inventory_reports.html
Original file line number Diff line number Diff line change
Expand Up @@ -236,28 +236,78 @@ <h4 class="chartTitle">{$ chart2Title | translate $}&nbsp;</h4>
<!-- ./ col-md-6 -->
</div>
<div class="col-md-12">
<table class="table table-striped">
<thead>
<tr>
<th translate>Axis</th>
<th translate>Access Level Instance</th>
<th translate>Sum</th>
<th translate>Min</th>
<th translate>5th Percentile</th>
<th translate>25th Percentile</th>
<th translate>Mean</th>
<th translate>Median</th>
<th translate>75 Percentile</th>
<th translate>95th Percentile</th>
<th translate>Max</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in axisData track by $index">
<td ng-repeat="item in row track by $index">{$ item $}</td>
</tr>
</tbody>
</table>
<h4 class="chartTitle">Statistics</h4>

<div ng-repeat="(cycle, vals) in axisData track by $index" ng-init="parentIndex = $index" class="pad-bottom-10">
<button
id="collapse-button-{$ $index $}"
type="button"
class="accordion-header"
data-toggle="collapse"
aria-expanded="true"
aria-controls="cycles-{$ $index $}"
data-target="#cycle-{$ $index $}"
>
{$ cycle $} &nbsp; <i class="fa-solid fa-chevron-right"></i>
</button>
<div id="cycle-{$ $index $}" class="collapse in">
<table class="table table-striped">
<thead>
<tr>
<th translate width="20%">Axis</th>
<th translate width="20%">Access Level Instance</th>
<th translate width="5%">Sum</th>
<th translate width="5%">Min</th>
<th translate width="5%">5th Percentile</th>
<th translate width="5%">25th Percentile</th>
<th translate width="5%">Mean</th>
<th translate width="5%">Median</th>
<th translate width="5%">75 Percentile</th>
<th translate width="5%">95th Percentile</th>
<th translate width="5%">Max</th>
</tr>
</thead>
<tbody ng-repeat="(key, values) in vals track by $index" ng-init="childIndex = $index">
<tr>
<td style="font-weight: bold">{$ key $}</td>
<td style="font-weight: bold" ng-repeat="item in values['values'] track by $index" ngInit="colIndex = $index">
<span ng-if="key === 'Year Built'"> {$ item $} </span>
<span ng-if="key != 'Year Built'"> {$ item | tolerantNumber:2 $} </span>
<span ng-if="$index === 0">
<!-- && values['children'].length > 0 -->
<button
id="collapse-{$ parentIndex $}-{$ $index $}"
type="button"
class="accordion-header"
data-toggle="collapse"
aria-expanded="false"
aria-description="toggle children elements"
aria-controls="children{$ parentIndex $}-{$ childIndex $}"
data-target="#children-{$ parentIndex $}-{$ childIndex $}"
>
<i class="fa-solid fa-chevron-right"></i>
</button>
</span>
</td>
</tr>
<tr *ngIf="'children' in values && values['children']" id="children-{$ parentIndex $}-{$ childIndex $}" class="collapse">
<td colspan="11" class="no-lr-pad">
<table class="table table-striped">
<tr ng-repeat="(key2, values2) in values['children']">
<td width="20%">&nbsp;</td>
<td width="20%">{$ key2 $}</td>
<td width="5%" ng-repeat="item in values2 track by $index" ng-if="$index > 0">
<span ng-if="key === 'Year Built'"> {$ item $} </span>
<span ng-if="key != 'Year Built'"> {$ item | tolerantNumber:2 $} </span>
</td>
</tr>
</table>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- ./ content_block row -->
</div>
Expand Down
6 changes: 6 additions & 0 deletions seed/static/seed/scss/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5683,3 +5683,9 @@ tags-input .tags .tag-item {
white-space: normal;
min-width: 350px;
}

.no-lr-pad {
padding-left: 0 !important;
padding-right: 0 !important;
padding-top: 0 !important;
}
35 changes: 25 additions & 10 deletions seed/views/v3/organizations.py
Original file line number Diff line number Diff line change
Expand Up @@ -1024,6 +1024,12 @@ def report_aggregated(self, request, pk=None):
ys = [building["y"] for datum in data for building in datum["chart_data"] if building["y"] is not None]
if ys and isinstance(ys[0], Number):
bins = np.histogram_bin_edges(ys, bins=5)

# special case for year built: make bins integers
# year built is in x axis, but it shows up in y_var variable
if params["y_var"] == "year_built":
bins = bins.astype(int)

aggregate_data = self.continuous_aggregate_data
else:
bins = list(set(ys))
Expand Down Expand Up @@ -1243,15 +1249,19 @@ def get_axis_stats(self, organization, cycle, axis, axis_var, views, ali):
return [axis_var, ali.name, 0, 0, 0, 0, 0, 0, 0, 0, 0]

def get_axis_data(self, organization_id, access_level_instance, cycles, x_var, y_var, all_property_views, fields):
axis_data = []
axis_data = {}
axes = {"x": x_var, "y": y_var}
organization = Organization.objects.get(pk=organization_id)

# initialize
for cycle in cycles:
axis_data[cycle.name] = {}

for axis in axes:
if axes[axis] != "Count":
columns = Column.objects.filter(organization_id=organization_id, column_name=axes[axis])
if not columns:
return []
return {}

column = columns[0]
if not column.data_type or column.data_type == "None":
Expand All @@ -1266,19 +1276,24 @@ def get_axis_data(self, organization_id, access_level_instance, cycles, x_var, y
name_to_display = (
serialized_column["display_name"] if serialized_column["display_name"] != "" else serialized_column["column_name"]
)
axis_name = name_to_display + f" ({cycle.name})"
axis_data[cycle.name][name_to_display] = {}
stats = self.get_axis_stats(organization, cycle, axis, axes[axis], all_property_views, access_level_instance)
axis_data.append(self.clean_axis_data(axis_name, data_type, stats))
for child_ali in access_level_instance.get_children():
stats = self.get_axis_stats(organization, cycle, axis, axes[axis], all_property_views, child_ali)
axis_data.append(self.clean_axis_data(axis_name, data_type, stats))
axis_data[cycle.name][name_to_display]["values"] = self.clean_axis_data(data_type, stats)

children = access_level_instance.get_children()
if len(children):
axis_data[cycle.name][name_to_display]["children"] = {}
for child_ali in children:
stats = self.get_axis_stats(organization, cycle, axis, axes[axis], all_property_views, child_ali)
axis_data[cycle.name][name_to_display]["children"][child_ali.name] = self.clean_axis_data(data_type, stats)

return axis_data

def clean_axis_data(self, column_name, data_type, data):
def clean_axis_data(self, data_type, data):
if data_type == "float":
return [column_name] + data[1:3] + np.round(data[3:], decimals=2).tolist()
return data[1:3] + np.round(data[3:], decimals=2).tolist()
elif data_type == "integer":
return [column_name] + data[1:3] + np.round(data[3:]).tolist()
return data[1:3] + np.round(data[3:]).tolist()

@has_perm_class("requires_member")
@ajax_request_class
Expand Down
Loading