diff --git a/assets/js/components/Sessions/CostHistoryChart.vue b/assets/js/components/Sessions/CostHistoryChart.vue
index b7586afcc..59dbe09f0 100644
--- a/assets/js/components/Sessions/CostHistoryChart.vue
+++ b/assets/js/components/Sessions/CostHistoryChart.vue
@@ -47,6 +47,7 @@ export default {
period: { type: String, default: PERIODS.TOTAL },
currency: { type: String, default: "EUR" },
colorMappings: { type: Object, default: () => ({ loadpoint: {}, vehicle: {} }) },
+ suggestedMaxAvgCost: { type: Number, default: 0 },
suggestedMaxCost: { type: Number, default: 0 },
},
computed: {
@@ -313,12 +314,13 @@ export default {
color: colors.muted,
maxTicksLimit: 6,
},
+ suggestedMax: this.suggestedMaxCost,
min: 0,
},
y1: {
position: "left",
border: { display: false },
- suggestedMax: this.suggestedMaxCost,
+ suggestedMax: this.suggestedMaxAvgCost,
grid: {
drawOnChartArea: false,
},
diff --git a/assets/js/views/Sessions.vue b/assets/js/views/Sessions.vue
index 6b74a777b..8e07ae841 100644
--- a/assets/js/views/Sessions.vue
+++ b/assets/js/views/Sessions.vue
@@ -96,6 +96,7 @@
:cost-type="activeType"
:currency="currency"
:period="period"
+ :suggested-max-avg-cost="suggestedMaxAvgCost"
:suggested-max-cost="suggestedMaxCost"
/>
@@ -118,7 +119,7 @@
v-else
:sessions="currentTypeSessions"
:color-mappings="colorMappings"
- :suggested-max-price="suggestedMaxCost"
+ :suggested-max-price="suggestedMaxAvgCost"
:group-by="selectedGroup"
:cost-type="activeType"
:currency="currency"
@@ -594,17 +595,42 @@ export default {
return (isGrouped && hasMultipleEntries) || (isSolar && isNotMonth && !isGrouped);
},
- suggestedMaxPrice() {
- // returns the 90th percentile of all prices
+ suggestedMaxAvgPrice() {
+ // returns the 98th percentile of avg prices for all sessions
const sessionsWithPrice = this.sessions.filter((s) => s.pricePerKWh !== null);
const prices = sessionsWithPrice.map((s) => s.pricePerKWh);
- return this.percentile(prices, 90);
+ return this.percentile(prices, 98);
},
- suggestedMaxCo2() {
- // returns the 90th percentile of all co2 emissions
+ suggestedMaxAvgCo2() {
+ // returns the 98th percentile of avg co2 emissions for all sessions
const sessionsWithCo2 = this.sessions.filter((s) => s.co2PerKWh !== null);
const co2 = sessionsWithCo2.map((s) => s.co2PerKWh);
- return this.percentile(co2, 90);
+ return this.percentile(co2, 98);
+ },
+ suggestedMaxAvgCost() {
+ return this.activeType === TYPES.PRICE
+ ? this.suggestedMaxAvgPrice
+ : this.suggestedMaxAvgCo2;
+ },
+ suggestedMaxCo2() {
+ // returns the 98th percentile of total co2 emissions by time period
+ const sessionsWithCo2 = this.sessions.filter((s) => s.co2PerKWh !== null);
+ const co2Map = sessionsWithCo2.reduce((acc, s) => {
+ const key = this.dateToPeriodKey(new Date(s.created));
+ acc[key] = (acc[key] || 0) + s.co2PerKWh * s.chargedEnergy;
+ return acc;
+ }, {});
+ return Math.max(this.percentile(Object.values(co2Map), 98), 5); // 5kg default
+ },
+ suggestedMaxPrice() {
+ // returns the 98th percentile of total price by time period
+ const sessionsWithPrice = this.sessions.filter((s) => s.price !== null);
+ const priceMap = sessionsWithPrice.reduce((acc, s) => {
+ const key = this.dateToPeriodKey(new Date(s.created));
+ acc[key] = (acc[key] || 0) + s.price;
+ return acc;
+ }, {});
+ return Math.max(this.percentile(Object.values(priceMap), 98), 1); // 1 CURRENCY default
},
suggestedMaxCost() {
return this.activeType === TYPES.PRICE ? this.suggestedMaxPrice : this.suggestedMaxCo2;
@@ -636,6 +662,12 @@ export default {
}
this.$router.push({ query: { ...this.$route.query, period, month, year } });
},
+ dateToPeriodKey(date) {
+ const options = { year: "numeric", month: "numeric", day: "numeric" };
+ if (this.period === PERIODS.YEAR) options.day = undefined;
+ if (this.period === PERIODS.TOTAL) options.month = undefined;
+ return date.toLocaleDateString(undefined, options);
+ },
async loadSessions() {
const response = await api.get("sessions");
// ensure sessions are sorted by created date