refactoring; more consistent naming for API endpoint and variables.

main
Giò Diani 2025-01-17 23:46:22 +01:00
parent e0c8b3eb1b
commit e4e05b4788
16 changed files with 325 additions and 238 deletions

View File

@ -5,6 +5,11 @@ namespace App;
use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Http;
/*
* Class contains methods which make calls to the API.
* Successfull calls get cached.
*/
class Api class Api
{ {
@ -14,12 +19,15 @@ class Api
$endpoint = env('FASTAPI_URI'); $endpoint = env('FASTAPI_URI');
$request = $endpoint.$path; $request = $endpoint.$path;
// load from cache if available
if (Cache::has($request)) { if (Cache::has($request)) {
//return Cache::get($request); //return Cache::get($request);
} }
$get = Http::timeout(1600)->get($request); // Set timeout to .5h
$get = Http::timeout(1800)->get($request);
// return result and cache it
if($get->successful()){ if($get->successful()){
$result = $get->json(); $result = $get->json();
Cache::put($request, $result); Cache::put($request, $result);
@ -29,27 +37,22 @@ class Api
return null; return null;
} }
public static function propertiesPerRegion() public static function propertiesGrowth(): mixed
{
return self::get('/region/properties');
}
public static function propertiesGrowth()
{ {
return self::get('/properties/growth'); return self::get('/properties/growth');
} }
public static function propertiesGeo() public static function propertiesGeo(): mixed
{ {
return self::get('/properties/geo'); return self::get('/properties/geo');
} }
public static function propertyExtractions(int $id) public static function propertyExtractions(int $id): mixed
{ {
return self::get("/property/{$id}/extractions"); return self::get("/property/{$id}/extractions");
} }
public static function propertyCapacities(int $id) public static function propertyCapacities(int $id): mixed
{ {
return self::get("/property/{$id}/capacities"); return self::get("/property/{$id}/capacities");
} }
@ -59,6 +62,26 @@ class Api
return self::get("/property/{$id}/base"); return self::get("/property/{$id}/base");
} }
public static function propertyCapacitiesMonthly(int $id, string $date): mixed
{
return self::get("/property/{$id}/capacities/monthly/{$date}");
}
public static function propertyCapacitiesDaily(int $id, string $date): mixed
{
return self::get("/property/{$id}/capacities/daily/{$date}");
}
public static function propertyNeighbours(int $id): mixed
{
return self::get("/property/{$id}/neighbours");
}
public static function regions(): mixed
{
return self::get('/regions');
}
public static function regionBase(int $id): mixed public static function regionBase(int $id): mixed
{ {
return self::get("/region/{$id}/base"); return self::get("/region/{$id}/base");
@ -74,24 +97,9 @@ class Api
return self::get("/region/{$id}/capacities/monthly/{$date}"); return self::get("/region/{$id}/capacities/monthly/{$date}");
} }
public static function propertyCapacitiesMonthly(int $id, string $date): mixed
{
return self::get("/property/{$id}/capacities/monthly/{$date}");
}
public static function regionCapacitiesDaily(int $id, string $date): mixed public static function regionCapacitiesDaily(int $id, string $date): mixed
{ {
return self::get("/region/{$id}/capacities/weekdays/{$date}"); return self::get("/region/{$id}/capacities/daily/{$date}");
}
public static function propertyCapacitiesDaily(int $id, string $date): mixed
{
return self::get("/property/{$id}/capacities/weekdays/{$date}");
}
public static function propertyNeighbours(int $id): mixed
{
return self::get("/property/{$id}/neighbours");
} }
public static function regionCapacities(int $id): mixed public static function regionCapacities(int $id): mixed
@ -104,6 +112,4 @@ class Api
return self::get("/region/{$id}/movingAverage/{$date}"); return self::get("/region/{$id}/movingAverage/{$date}");
} }
} }

View File

@ -5,7 +5,7 @@
<strong>Start</strong> <strong>Start</strong>
<ul> <ul>
@foreach($regions as $r) @foreach($regions as $r)
<li><a href="/region/{{ $r['region_id'] }}">{{ $r['region_name'] }}</a></li> <li><a href="/region/{{ $r['id'] }}">{{ $r['name'] }}</a></li>
@endforeach @endforeach
</ul> </ul>
</nav> </nav>
@ -82,7 +82,7 @@
<script type="module"> <script type="module">
const sharedOptions = { const sharedOptions = {
basic: { basic: {
color: {!! $chartOptions['colors'] !!}, color: {!! $diagramsOptions['shared']['colors'] !!},
grid: { grid: {
top: 30, top: 30,
left: 70, left: 70,
@ -101,7 +101,7 @@ const sharedOptions = {
} }
} }
} }
const extractionDates = {!! json_encode($regionPropertiesCapacities['scrapeDates']) !!}; const extractionDates = {!! $diagramsOptions['shared']['extractionDates'] !!};
const chartHeatmap = document.getElementById('chart-heatmap'); const chartHeatmap = document.getElementById('chart-heatmap');
const cHeatmap = echarts.init(chartHeatmap); const cHeatmap = echarts.init(chartHeatmap);
@ -156,7 +156,7 @@ const cHeatmapOptions = {
yAxis: { yAxis: {
show: true, show: true,
type: 'category', type: 'category',
data: {!! json_encode($regionPropertiesCapacities['property_ids']) !!}, data: {!! $diagramsOptions['heatmap']['yAxis']['data'] !!},
splitArea: { splitArea: {
show: false show: false
}, },
@ -196,7 +196,7 @@ const cHeatmapOptions = {
name: 'Verfügbarkeit', name: 'Verfügbarkeit',
type: 'heatmap', type: 'heatmap',
blurSize: 0, blurSize: 0,
data: {!! json_encode($regionPropertiesCapacities['values']) !!}, data: {!! $diagramsOptions['heatmap']['series']['data'] !!},
label: { label: {
show: false show: false
}, },
@ -230,7 +230,7 @@ const cPropsPerRegionOptions = {
fontWeight: 'bold', fontWeight: 'bold',
}, },
type: 'category', type: 'category',
data: {!! $propsPerRegion[1] !!} data: {!! $diagramsOptions['propertiesPerRegion']['xAxis']['data'] !!}
}, },
yAxis: { yAxis: {
type: 'value', type: 'value',
@ -243,7 +243,7 @@ const cPropsPerRegionOptions = {
}, },
series: [ series: [
{ {
data: {!! $propsPerRegion[2] !!}, data: {!! $diagramsOptions['propertiesPerRegion']['yAxis']['data'] !!},
type: 'bar', type: 'bar',
itemStyle: { itemStyle: {
color: (e) => { color: (e) => {
@ -259,17 +259,13 @@ cPropsPerRegion.setOption(cPropsPerRegionOptions);
const chartExtractions = document.getElementById('extractions'); const chartExtractions = document.getElementById('extractions');
const cExtractions = echarts.init(chartExtractions); const cExtractions = echarts.init(chartExtractions);
const filters = {
regions: ["Alle", "Davos", "Engadin", "Heidiland", "St. Moritz"]
}
const cExtractionsOptions = { const cExtractionsOptions = {
color: sharedOptions.basic.color, color: sharedOptions.basic.color,
tooltip: { tooltip: {
trigger: 'axis' trigger: 'axis'
}, },
legend: { legend: {
data: filters.regions show: true
}, },
grid: sharedOptions.basic.grid, grid: sharedOptions.basic.grid,
xAxis: { xAxis: {
@ -297,31 +293,31 @@ const cExtractionsOptions = {
name: 'Alle', name: 'Alle',
type: 'line', type: 'line',
stack: 'Total', stack: 'Total',
data: {!! json_encode($growth['total_all']) !!}, data: {!! json_encode($diagramsOptions['extractions']['series']['total_all']) !!},
}, },
{ {
connectNulls: true, connectNulls: true,
name: 'Davos', name: 'Davos',
type: 'line', type: 'line',
data: {!! json_encode($growth['total_davos']) !!} data: {!! json_encode($diagramsOptions['extractions']['series']['total_davos']) !!}
}, },
{ {
connectNulls: true, connectNulls: true,
name: 'Engadin', name: 'Engadin',
type: 'line', type: 'line',
data: {!! json_encode($growth['total_engadin']) !!} data: {!! json_encode($diagramsOptions['extractions']['series']['total_engadin']) !!}
}, },
{ {
connectNulls: true, connectNulls: true,
name: 'Heidiland', name: 'Heidiland',
type: 'line', type: 'line',
data: {!! json_encode($growth['total_heidiland']) !!} data: {!! json_encode($diagramsOptions['extractions']['series']['total_heidiland']) !!}
}, },
{ {
connectNulls: true, connectNulls: true,
name: 'St. Moritz', name: 'St. Moritz',
type: 'line', type: 'line',
data: {!! json_encode($growth['total_stmoritz']) !!} data: {!! json_encode($diagramsOptions['extractions']['series']['total_stmoritz']) !!}
}, },
] ]
}; };

View File

@ -0,0 +1,27 @@
@extends('base')
@section('body-class', 'property')
@section('header')
<nav>
<strong>Property: {{ $base['check_data'] }} ({{ $base['region_name'] }})</strong>
<ul>
<li><a href="/">Start</a></li>
@foreach($regions as $r)
<li><a href="/region/{{ $r['id'] }}">{{ $r['name'] }}</a></li>
@endforeach
</ul>
</nav>
<button popovertarget="prop-details"></button>
<div popover id="prop-details">
<dl>
<dt>Region</dt>
<dd>{{ $base['region_name'] }}</dd>
<dt>Zum ersten mal gefunden</dt>
<dd>{{ $base['first_found'] }}</dd>
<dt>Zum letzten mal gefunden</dt>
<dd>{{ $base['last_found'] }}</dd>
</dl>
</div>
@endsection
@section('main')
<p>Für dieses Mietobjekt sind keine Daten vorhanden.</p>
@endsection

View File

@ -2,11 +2,11 @@
@section('body-class', 'property') @section('body-class', 'property')
@section('header') @section('header')
<nav> <nav>
<strong>Property: {{ $base['check_data'] }} ({{ $base['region_name'] }})</strong> <strong>Property: {{ $base['latlng'] }} ({{ $base['region_name'] }})</strong>
<ul> <ul>
<li><a href="/">Start</a></li> <li><a href="/">Start</a></li>
@foreach($regions as $r) @foreach($regions as $r)
<li><a href="/region/{{ $r['region_id'] }}">{{ $r['region_name'] }}</a></li> <li><a href="/region/{{ $r['id'] }}">{{ $r['name'] }}</a></li>
@endforeach @endforeach
</ul> </ul>
</nav> </nav>
@ -24,11 +24,6 @@
@endsection @endsection
@section('main') @section('main')
@if(!isset($propertyCapacities['capacities']))
<div style="position: absolute;">
Für dieses Mietobjekt sind keine Daten vorhanden.
</div>
@else
<article style="grid-area: timeline;"> <article style="grid-area: timeline;">
<div id="timeline"></div> <div id="timeline"></div>
</article> </article>
@ -86,8 +81,9 @@
<script type="module"> <script type="module">
const sharedOptions = { const sharedOptions = {
extractiondates: {!! $diagramsOptions['shared']['extractiondates']!!},
basic: { basic: {
color: {!! $chartOptions['colors'] !!}, color: {!!$diagramsOptions['shared']['colors']!!},
grid: { grid: {
top: 20, top: 20,
left: 60, left: 60,
@ -106,7 +102,7 @@ const sharedOptions = {
nameGap: 24, nameGap: 24,
nameTextStyle: { nameTextStyle: {
fontWeight: 'bold', fontWeight: 'bold',
}, }
} }
} }
} }
@ -114,13 +110,12 @@ const sharedOptions = {
const chartTimeline = document.getElementById('timeline'); const chartTimeline = document.getElementById('timeline');
const cTimeline = echarts.init(chartTimeline); const cTimeline = echarts.init(chartTimeline);
const cTimelineOptions = { const cTimelineOptions = {
grid: { grid: {
show: false, show: false,
}, },
timeline: { timeline: {
data: {!! $extractiondates !!}, data: sharedOptions.extractiondates,
playInterval: 1000, playInterval: 1000,
axisType: 'time', axisType: 'time',
left: 8, left: 8,
@ -141,7 +136,7 @@ const cCapacityMonthlyOptions = {
tooltip: sharedOptions.basic.tooltip, tooltip: sharedOptions.basic.tooltip,
timeline: { timeline: {
show: false, show: false,
data: {!! $extractiondates !!}, data: sharedOptions.extractiondates,
axisType: 'time', axisType: 'time',
}, },
grid: { grid: {
@ -164,7 +159,7 @@ const cCapacityMonthlyOptions = {
type: 'category', type: 'category',
}, },
options: [ options: [
@foreach ($capacitiesMonthly as $cM) @foreach ($diagramsOptions['capacityMonthly']['options'] as $cM)
{ {
yAxis: { yAxis: {
data: {!! json_encode($cM['months']) !!} data: {!! json_encode($cM['months']) !!}
@ -190,7 +185,7 @@ const cCapacityDailyOptions = {
tooltip: sharedOptions.basic.tooltip, tooltip: sharedOptions.basic.tooltip,
timeline: { timeline: {
show: false, show: false,
data: {!! $extractiondates !!}, data: sharedOptions.extractiondates,
axisType: 'time', axisType: 'time',
}, },
grid: { grid: {
@ -213,7 +208,7 @@ const cCapacityDailyOptions = {
type: 'category', type: 'category',
}, },
options: [ options: [
@foreach ($capacitiesDaily as $cD) @foreach ($diagramsOptions['capacityDaily']['options'] as $cD)
{ {
yAxis: { yAxis: {
data: {!! json_encode($cD['weekdays']) !!} data: {!! json_encode($cD['weekdays']) !!}
@ -254,7 +249,7 @@ const cCapacityOptions = {
xAxis: { xAxis: {
type: 'category', type: 'category',
boundaryGap: false, boundaryGap: false,
data: {!! json_encode($propertyCapacities['dates']) !!}, data: {!! $diagramsOptions['capacities']['xAxis']['data'] !!},
name: 'Zeitpunkt Scraping', name: 'Zeitpunkt Scraping',
nameLocation: 'center', nameLocation: 'center',
nameGap: 24, nameGap: 24,
@ -278,19 +273,19 @@ const cCapacityOptions = {
name: 'Verfügbarkeit Mietobjekt', name: 'Verfügbarkeit Mietobjekt',
type: 'line', type: 'line',
symbolSize: 7, symbolSize: 7,
data: {!! json_encode($propertyCapacities['capacities']) !!} data: {!! $diagramsOptions['capacities']["series"][0]["data"] !!}
}, },
{ {
name: 'Verfügbarkeit {{ $base['region_name'] }}', name: 'Verfügbarkeit {{ $base['region_name'] }}',
type: 'line', type: 'line',
symbolSize: 7, symbolSize: 7,
data: {!! json_encode($regionCapacities[0]) !!} data: {!! $diagramsOptions['capacities']["series"][1]["data"] !!}
}, },
{ {
name: 'Verfügbarkeit alle Regionen', name: 'Verfügbarkeit alle Regionen',
type: 'line', type: 'line',
symbolSize: 7, symbolSize: 7,
data: {!! json_encode($regionCapacities[1]) !!} data: {!! $diagramsOptions['capacities']["series"][2]["data"] !!}
} }
] ]
}; };
@ -304,7 +299,7 @@ const h2Belegung = document.getElementById('belegung-title');
const cCalendarOptions = { const cCalendarOptions = {
timeline: { timeline: {
show: false, show: false,
data: {!! json_encode($propertyCapacities['dates']) !!}, data: sharedOptions.extractiondates,
axisType: 'time', axisType: 'time',
}, },
visualMap: { visualMap: {
@ -363,7 +358,7 @@ const cCalendarOptions = {
} }
], ],
options: [ options: [
@foreach ($calendar as $c) @foreach ($diagramsOptions['calendar']['series'] as $c)
{ {
series: [{ series: [{
type: 'heatmap', type: 'heatmap',
@ -445,7 +440,7 @@ function icon(id = 0){
} }
const markers = L.featureGroup([ const markers = L.featureGroup([
L.marker([{{ $base['check_data'] }}], {icon: icon(1)}), L.marker([{{ $base['latlng'] }}], {icon: icon(1)}),
@foreach($neighbours as $n) @foreach($neighbours as $n)
L.marker([{{ $n['lat'] }}, {{ $n['lon'] }}], {icon: icon()}).bindPopup('<a href="/property/{{ $n['id'] }}">{{ $n['lat'] }}, {{ $n['lon'] }}</a>'), L.marker([{{ $n['lat'] }}, {{ $n['lon'] }}], {icon: icon()}).bindPopup('<a href="/property/{{ $n['id'] }}">{{ $n['lat'] }}, {{ $n['lon'] }}</a>'),
@endforeach @endforeach
@ -465,5 +460,4 @@ cCapacity.on('click', 'series', (e) => {
</script> </script>
@endif
@endsection @endsection

View File

@ -2,12 +2,12 @@
@section('body-class', 'region') @section('body-class', 'region')
@section('header') @section('header')
<nav> <nav>
<strong>{{ $region[0]['region_name'] }}</strong> <strong>{{ $region[0]['name'] }}</strong>
<ul> <ul>
<li><a href="/">Start</a></li> <li><a href="/">Start</a></li>
@foreach($regions as $r) @foreach($regions as $r)
@if($r['region_id'] != $region_id) @if($r['id'] != $regionId)
<li><a href="/region/{{ $r['region_id'] }}">{{ $r['region_name'] }}</a></li> <li><a href="/region/{{ $r['id'] }}">{{ $r['name'] }}</a></li>
@endif @endif
@endforeach @endforeach
</ul> </ul>
@ -64,7 +64,7 @@
const sharedOptions = { const sharedOptions = {
basic: { basic: {
color: {!! $chartOptions['colors'] !!}, color: {!! $diagramsOptions['shared']['colors'] !!},
grid: { grid: {
top: 20, top: 20,
left: 60, left: 60,
@ -108,7 +108,7 @@ const cCapacityOptions = {
xAxis: { xAxis: {
type: 'category', type: 'category',
boundaryGap: false, boundaryGap: false,
data: {!! json_encode($regionCapacities['region']['dates']) !!}, data: {!! $diagramsOptions['capacity']['xAxis']['data'] !!},
name: 'Zeitpunkt Scraping', name: 'Zeitpunkt Scraping',
nameLocation: 'center', nameLocation: 'center',
nameGap: 24, nameGap: 24,
@ -131,13 +131,13 @@ const cCapacityOptions = {
name: 'Verfügbarkeit alle Regionen', name: 'Verfügbarkeit alle Regionen',
type: 'line', type: 'line',
symbolSize: 7, symbolSize: 7,
data: {!! json_encode($regionCapacities['all']['capacities']) !!} data: {!! $diagramsOptions['capacity']['series']['all']['data'] !!}
}, },
{ {
name: 'Verfügbarkeit Region', name: 'Verfügbarkeit Region',
type: 'line', type: 'line',
symbolSize: 7, symbolSize: 7,
data: {!! json_encode($regionCapacities['region']['capacities']) !!} data: {!! $diagramsOptions['capacity']['series']['region']['data'] !!}
}] }]
}; };
@ -149,7 +149,7 @@ const cCapacityMonthly = echarts.init(chartCapacityMonthly);
const cCapacityMonthlyOptions = { const cCapacityMonthlyOptions = {
timeline: { timeline: {
show: false, show: false,
data: {!! json_encode($regionCapacities['region']['dates']) !!}, data: {!! $diagramsOptions['capacity']['xAxis']['data'] !!},
axisType: 'time', axisType: 'time',
}, },
grid: { grid: {
@ -173,7 +173,7 @@ const cCapacityMonthlyOptions = {
}, },
tooltip: sharedOptions.basic.tooltip, tooltip: sharedOptions.basic.tooltip,
options: [ options: [
@foreach ($regionCapacities['region_monthly'] as $m) @foreach ($diagramsOptions['capacityMonthly']['options'] as $m)
{ {
yAxis: { yAxis: {
data: {!! json_encode($m['months']) !!} data: {!! json_encode($m['months']) !!}
@ -198,7 +198,7 @@ const cCapacityDaily = echarts.init(chartCapacityDaily);
const cCapacityDailyOptions = { const cCapacityDailyOptions = {
timeline: { timeline: {
show: false, show: false,
data: {!! json_encode($regionCapacities['region']['dates']) !!}, data: {!! $diagramsOptions['capacity']['xAxis']['data'] !!},
axisType: 'time', axisType: 'time',
}, },
tooltip: sharedOptions.basic.tooltip, tooltip: sharedOptions.basic.tooltip,
@ -222,7 +222,7 @@ const cCapacityDailyOptions = {
type: 'category', type: 'category',
}, },
options: [ options: [
@foreach ($regionCapacities['region_daily'] as $d) @foreach ($diagramsOptions['capacityDaily']['options'] as $d)
{ {
yAxis: { yAxis: {
data: {!! json_encode($d['weekdays']) !!} data: {!! json_encode($d['weekdays']) !!}
@ -248,7 +248,7 @@ const cPredictionOptions = {
color: sharedOptions.basic.color, color: sharedOptions.basic.color,
timeline: { timeline: {
show: false, show: false,
data: {!! json_encode($regionCapacities['region']['dates']) !!}, data: {!! $diagramsOptions['capacity']['xAxis']['data'] !!},
axisType: 'time', axisType: 'time',
replaceMerge: ['graphic', 'series'] replaceMerge: ['graphic', 'series']
}, },
@ -285,7 +285,7 @@ const cPredictionOptions = {
} }
}, },
options: [ options: [
@foreach ($predictions as $p) @foreach ($diagramsOptions['predictions']['options'] as $p)
@if($p === null) @if($p === null)
{ {
graphic: { graphic: {
@ -368,7 +368,7 @@ const cHeatmapOptions = {
show: true, show: true,
name: 'Zeitpunkt Scraping', name: 'Zeitpunkt Scraping',
type: 'category', type: 'category',
data: {!! json_encode($regionPropertiesCapacities['scrapeDates']) !!}, data: {!! $diagramsOptions['heatmap']['xAxis']['data'] !!},
splitArea: { splitArea: {
show: false show: false
}, },
@ -393,7 +393,7 @@ const cHeatmapOptions = {
yAxis: { yAxis: {
show: true, show: true,
type: 'category', type: 'category',
data: {!! json_encode($regionPropertiesCapacities['property_ids']) !!}, data: {!! $diagramsOptions['heatmap']['yAxis']['data'] !!},
splitArea: { splitArea: {
show: false show: false
}, },
@ -462,7 +462,7 @@ const cTimelineOptions = {
show: false, show: false,
}, },
timeline: { timeline: {
data: {!! json_encode($regionCapacities['region']['dates']) !!}, data: {!! $diagramsOptions['capacity']['xAxis']['data'] !!},
playInterval: 2000, playInterval: 2000,
axisType: 'time', axisType: 'time',
left: 8, left: 8,

View File

@ -1,8 +0,0 @@
<?php
use Illuminate\Foundation\Inspiring;
use Illuminate\Support\Facades\Artisan;
Artisan::command('inspire', function () {
$this->comment(Inspiring::quote());
})->purpose('Display an inspiring quote')->hourly();

View File

@ -8,44 +8,56 @@ Route::get('/', function () {
$regionBase = Api::regionBase(-1); $regionBase = Api::regionBase(-1);
$regionBase[] = ['region_name' => 'Alle Regionen', 'region_id' => -1]; $regionBase[] = ['region_name' => 'Alle Regionen', 'region_id' => -1];
$regionPropertyCapacities = Api::regionPropertiesCapacities(-1); $regionPropertiesCapacities = Api::regionPropertiesCapacities(-1);
$propertiesGrowth = Api::propertiesGrowth(); $propertiesGrowth = Api::propertiesGrowth();
$propsPerRegion = Api::propertiesPerRegion();
$propsPerRegionName = [];
$propsPerRegionCounts = [];
$propsPerRegionId = [];
foreach ($propsPerRegion as $el) { $regions = Api::regions();
$propsPerRegionName[] = $el['name'];
$propsPerRegionId[] = $el['id'];
$propsPerRegionCounts[] = $el['count_properties'];
}
$chartOptions = [
'colors' => Chart::colors()
];
$propertiesGeo = Api::propertiesGeo(); $propertiesGeo = Api::propertiesGeo();
$diagramsOptions = [
"shared" => [
"extractionDates" => json_encode($regionPropertiesCapacities['dates']),
"colors" => Chart::colors()
],
"heatmap" => [
"yAxis" => [
"data" => json_encode($regionPropertiesCapacities['property_ids'])
],
"series" => [
"data" => json_encode($regionPropertiesCapacities['values'])
]
],
"propertiesPerRegion" => [
"yAxis" => [
"data" => json_encode(array_column($regions, 'count_properties'))
],
"xAxis" => [
"data" => json_encode(array_column($regions, 'name'))
]
],
"extractions" => [
"series" => $propertiesGrowth,
]
];
return view('overview', [ return view('overview', [
"regions" => $regionBase, "regions" => $regions,
"regionPropertiesCapacities" => $regionPropertyCapacities, "region" => $regionBase,
"diagramsOptions" => $diagramsOptions,
"geo" => $propertiesGeo, "geo" => $propertiesGeo,
"growth" => $propertiesGrowth,
"chartOptions" => $chartOptions, ]);
"propsPerRegion" => [json_encode($propsPerRegionId), json_encode($propsPerRegionName), json_encode($propsPerRegionCounts)]]);
}); });
Route::get('/region/{id}', function (int $id) { Route::get('/region/{id}', function (int $id) {
$regionBaseAll = Api::regionBase(-1); $regions = Api::regions();
$regionBaseAll[] = ['region_name' => 'Alle Regionen', 'region_id' => -1]; $regions[] = ['name' => 'Alle Regionen', 'id' => -1];
$regionBaseRegion = $id >= 0 ? Api::regionBase($id) : [['region_name' => 'Alle Regionen']]; $region = $id >= 0 ? Api::regionBase($id) : [['name' => 'Alle Regionen']];
$regionPropertiesCapacities = Api::regionPropertiesCapacities($id); $regionPropertiesCapacities = Api::regionPropertiesCapacities($id);
$regionCapacitiesRegion = Api::regionCapacities($id); $regionCapacitiesRegion = Api::regionCapacities($id);
$regionCapacitiesAll = Api::regionCapacities(-1); $regionCapacitiesAll = Api::regionCapacities(-1);
$regionCapacitiesMonthly = []; $regionCapacitiesMonthly = [];
$regionCapacitiesDaily = []; $regionCapacitiesDaily = [];
$regionPredictions = []; $regionPredictions = [];
@ -56,25 +68,52 @@ Route::get('/region/{id}', function (int $id) {
$regionPredictions[] = Api::regionMovingAverage($id, $date); $regionPredictions[] = Api::regionMovingAverage($id, $date);
} }
$chartOptions = [ $diagramsOptions = [
'colors' => Chart::colors() "shared" => [
]; "extractionDates" => json_encode($regionPropertiesCapacities['dates']),
"colors" => Chart::colors()
$regionCapacities = [ ],
'all' => $regionCapacitiesAll, "heatmap" => [
'region' => $regionCapacitiesRegion, "xAxis" => [
'region_monthly' => $regionCapacitiesMonthly, "data" => json_encode($regionPropertiesCapacities['dates'])
'region_daily' => $regionCapacitiesDaily ],
"yAxis" => [
"data" => json_encode($regionPropertiesCapacities['property_ids'])
],
"series" => [
"data" => json_encode($regionPropertiesCapacities['values'])
]
],
"predictions" => [
"options" => $regionPredictions,
],
"capacityMonthly" => [
"options" => $regionCapacitiesMonthly,
],
"capacityDaily" => [
"options" => $regionCapacitiesDaily,
],
"capacity" => [
"xAxis" => [
"data" => json_encode($regionCapacitiesRegion['dates'])
],
"series" => [
"all" => [
"data" => json_encode($regionCapacitiesAll['capacities'])
],
"region" => [
"data" => json_encode($regionCapacitiesRegion['capacities'])
]
]
]
]; ];
return view('region', [ return view('region', [
'chartOptions' => $chartOptions, 'diagramsOptions' => $diagramsOptions,
'startDate' => $regionCapacitiesRegion['dates'][0], 'startDate' => $regionCapacitiesRegion['dates'][0],
'regions' => $regionBaseAll, 'regions' => $regions,
'region' => $regionBaseRegion, 'region' => $region,
'region_id' => $id, 'regionId' => $id,
'regionCapacities' => $regionCapacities,
'regionPropertiesCapacities' => $regionPropertiesCapacities, 'regionPropertiesCapacities' => $regionPropertiesCapacities,
'predictions' => $regionPredictions]); 'predictions' => $regionPredictions]);
@ -83,16 +122,16 @@ Route::get('/region/{id}', function (int $id) {
Route::get('/property/{id}', function (int $id) { Route::get('/property/{id}', function (int $id) {
$chartOptions = [
'colors' => Chart::colors() $regions = Api::regions();
]; $regions[] = ['name' => 'Alle Regionen', 'id' => -1];
$regionBaseAll = Api::regionBase(-1);
$regionBaseAll[] = ['region_name' => 'Alle Regionen', 'region_id' => -1]; $base = Api::propertyBase($id);
$propertyBase = Api::propertyBase($id);
$calendars = Api::propertyExtractions($id); $calendars = Api::propertyExtractions($id);
$propertyCapacities = Api::propertyCapacities($id); $propertyCapacities = Api::propertyCapacities($id);
$propertyNeighbours = Api::propertyNeighbours($id); $propertyNeighbours = Api::propertyNeighbours($id);
$regionCapacitiesRegion = Api::regionCapacities($propertyBase[0]['region_id']);
$regionCapacitiesRegion = Api::regionCapacities($base[0]['region_id']);
$regionCapacitiesAll = Api::regionCapacities(-1); $regionCapacitiesAll = Api::regionCapacities(-1);
$regionCapacities = [[],[]]; $regionCapacities = [[],[]];
@ -118,13 +157,14 @@ Route::get('/property/{id}', function (int $id) {
} }
} }
}else{ }else{
$propertyCapacities = ['dates' => [null]]; return view('property-nodata', [
'base' => $base[0],
'regions' => $regions,
]);
} }
// prepare data for calendar chart // prepare data for calendar chart
$data = []; $calendarData = [];
$dates = [];
foreach ($calendars as $el) { foreach ($calendars as $el) {
$series = []; $series = [];
@ -134,21 +174,41 @@ Route::get('/property/{id}', function (int $id) {
$series[] = [$date, $status]; $series[] = [$date, $status];
} }
$data[] = $series; $calendarData[] = $series;
} }
$diagramsOptions = [
"shared" => [
"colors" => Chart::colors(),
"extractiondates" => json_encode($propertyCapacities['dates'])
],
"calendar" => [
"series" => $calendarData
],
"capacities" => [
"xAxis" => [
"data" => json_encode($propertyCapacities['dates'])
],
"series" => [
["data" => json_encode($propertyCapacities['capacities'])],
["data" => json_encode($regionCapacities[0])],
["data" => json_encode($regionCapacities[1])],
]
],
"capacityMonthly" => [
"options" => $propertyCapacitiesMonthly,
],
"capacityDaily" => [
"options" => $propertyCapacitiesDaily,
],
];
return view('property', [ return view('property', [
'chartOptions' => $chartOptions, 'diagramsOptions' => $diagramsOptions,
'startDate' => $propertyCapacities['dates'][0], 'startDate' => $propertyCapacities['dates'][0],
'base' => $propertyBase[0], 'base' => $base[0],
'regions' => $regionBaseAll, 'regions' => $regions,
'extractiondates' => json_encode($propertyCapacities['dates']),
'calendar' => $data,
'propertyCapacities' => $propertyCapacities,
'capacitiesMonthly' => $propertyCapacitiesMonthly,
'capacitiesDaily' => $propertyCapacitiesDaily,
'regionCapacities' => $regionCapacities,
'neighbours' => $propertyNeighbours 'neighbours' => $propertyNeighbours
]); ]);

View File

@ -1,13 +1,13 @@
import data import data
import polars as pl import polars as pl
from data import etl_property_capacities as etl_pc from data import etl_property_capacities as etl_pc
from data import etl_property_capacities_daily as etl_pcd
from data import etl_property_capacities_monthly as etl_pcm from data import etl_property_capacities_monthly as etl_pcm
from data import etl_property_capacities_weekdays as etl_pcw
from data import etl_property_neighbours as etl_pn from data import etl_property_neighbours as etl_pn
from data import etl_region_capacities as etl_rc from data import etl_region_capacities as etl_rc
from data import etl_region_capacities_comparison as etl_rcc from data import etl_region_capacities_comparison as etl_rcc
from data import etl_region_capacities_daily as etl_rcd
from data import etl_region_capacities_monthly as etl_rcm from data import etl_region_capacities_monthly as etl_rcm
from data import etl_region_capacities_weekdays as etl_rcw
from data import etl_region_movAverage as etl_rmA from data import etl_region_movAverage as etl_rmA
from data import etl_region_properties_capacities as etl_rpc from data import etl_region_properties_capacities as etl_rpc
from fastapi import FastAPI, Response from fastapi import FastAPI, Response
@ -20,85 +20,96 @@ app = FastAPI()
def read_root(): def read_root():
return {"Hi there!"} return {"Hi there!"}
@app.get("/items/{item_id}") # regions overview: contains names, ids, and count of properties of regions
def read_item(item_id: int): @app.get("/regions")
ext = d.extractions_for(item_id).pl()
out = ext.with_columns(pl.col("calendar").str.extract_all(r"([0-9]{4}-[0-9]{2}-[0-9]{2})|[0-2]").alias("calendar_data"))
out = out.drop(['calendar', 'property_id'])
return Response(content=out.write_json(), media_type="application/json")
@app.get("/region/properties")
def properties_region(): def properties_region():
return d.properties_per_region().pl().to_dicts() return d.properties_per_region().pl().to_dicts()
@app.get("/properties/growth") # get capacities of properties, for every scraping, filterd by region; -1 = all regions
def properties_growth():
options = {"dates" : d.properties_growth().pl()['date'].to_list(), "total_all" : d.properties_growth().pl()['total_all'].to_list(), "total_heidiland" : d.properties_growth().pl()['total_heidiland'].to_list(), "total_engadin" : d.properties_growth().pl()['total_engadin'].to_list(), "total_davos" : d.properties_growth().pl()['total_davos'].to_list(), "total_stmoritz" : d.properties_growth().pl()['total_stmoritz'].to_list()}
return options
@app.get("/properties/geo")
def properties_geo():
return d.properties_geo().pl().to_dicts()
@app.get("/property/{id}/neighbours")
def property_neighbours(id: int):
capacities = etl_pn.property_neighbours(id)
return capacities
@app.get("/property/{id}/extractions")
def property_extractions(id: int):
return d.extractions_for(property_id = id).pl().to_dicts()
@app.get("/property/{id}/capacities")
def property_capacities_data(id: int):
capacities = etl_pc.property_capacities(id)
return capacities
@app.get("/property/{id}/capacities/monthly/{scrapeDate}")
def property_capacities_data(id: int, scrapeDate: str):
capacities = etl_pcm.property_capacities_monthly(id, scrapeDate)
return capacities
@app.get("/property/{id}/capacities/weekdays/{scrapeDate}")
def property_capacities_data(id: int, scrapeDate: str):
capacities = etl_pcw.property_capacities_weekdays(id, scrapeDate)
return capacities
@app.get("/property/{id}/base")
def property_base_data(id: int):
return d.property_base_data(id).pl().to_dicts()
@app.get("/region/{id}/properties/capacities") @app.get("/region/{id}/properties/capacities")
def region_property_capacities_data(id: int): def region_property_capacities_data(id: int):
capacities = etl_rpc.region_properties_capacities(id) capacities = etl_rpc.region_properties_capacities(id)
return capacities return capacities
# get the capacity of a region for every scraping; -1 = all regions
@app.get("/region/{id}/capacities") @app.get("/region/{id}/capacities")
def region_capacities_data(id: int): def region_capacities_data(id: int):
capacities = etl_rc.region_capacities(id) capacities = etl_rc.region_capacities(id)
return capacities return capacities
# get the capacity of a region for desired scraping date by months; -1 = all regions
@app.get("/region/{id}/capacities/monthly/{scrapeDate}") @app.get("/region/{id}/capacities/monthly/{scrapeDate}")
def region_capacities_data(id: int, scrapeDate: str): def region_capacities_data(id: int, scrapeDate: str):
capacities = etl_rcm.region_capacities_monthly(id, scrapeDate) capacities = etl_rcm.region_capacities_monthly(id, scrapeDate)
return capacities return capacities
@app.get("/region/{id}/capacities/weekdays/{scrapeDate}") # get the capacity of a region for desired scraping date by days; -1 = all regions
@app.get("/region/{id}/capacities/daily/{scrapeDate}")
def region_capacities_data(id: int, scrapeDate: str): def region_capacities_data(id: int, scrapeDate: str):
capacities = etl_rcw.region_capacities_weekdays(id, scrapeDate) capacities = etl_rcd.region_capacities_daily(id, scrapeDate)
return capacities return capacities
# compare the capacities of two regions
@app.get("/region/capacities/comparison/{id_1}/{id_2}") @app.get("/region/capacities/comparison/{id_1}/{id_2}")
def region_capacities_data(id_1: int, id_2: int): def region_capacities_data(id_1: int, id_2: int):
capacities = etl_rcc.region_capacities_comparison(id_1, id_2) capacities = etl_rcc.region_capacities_comparison(id_1, id_2)
return capacities return capacities
# get the moving average for a region beginning from desired date
@app.get("/region/{id}/movingAverage/{startDate}") @app.get("/region/{id}/movingAverage/{startDate}")
def region_capacities_data(id: int, startDate: str): def region_capacities_data(id: int, startDate: str):
result = etl_rmA.region_movingAverage(id, startDate) result = etl_rmA.region_movingAverage(id, startDate)
return result return result
# get id and name of a region
@app.get("/region/{id}/base") @app.get("/region/{id}/base")
def region_base_data(id: int): def region_base_data(id: int):
return d.region_base_data(id).pl().to_dicts() return d.region_base_data(id).pl().to_dicts()
# get growth of properties categorized by regions
@app.get("/properties/growth")
def properties_growth():
options = {"dates" : d.properties_growth().pl()['date'].to_list(), "total_all" : d.properties_growth().pl()['total_all'].to_list(), "total_heidiland" : d.properties_growth().pl()['total_heidiland'].to_list(), "total_engadin" : d.properties_growth().pl()['total_engadin'].to_list(), "total_davos" : d.properties_growth().pl()['total_davos'].to_list(), "total_stmoritz" : d.properties_growth().pl()['total_stmoritz'].to_list()}
return options
# get the geo coordinates for all properties
@app.get("/properties/geo")
def properties_geo():
return d.properties_geo().pl().to_dicts()
# get the 10 nearest properties from desired property
@app.get("/property/{id}/neighbours")
def property_neighbours(id: int):
capacities = etl_pn.property_neighbours(id)
return capacities
# get scraped data for all scrapings from desired property
@app.get("/property/{id}/extractions")
def property_extractions(id: int):
return d.extractions_for(property_id = id).pl().to_dicts()
# get scraped data for all scrapings from desired property
@app.get("/property/{id}/capacities")
def property_capacities_data(id: int):
capacities = etl_pc.property_capacities(id)
return capacities
# get the capacity of a property for desired scraping date by months
@app.get("/property/{id}/capacities/monthly/{scrapeDate}")
def property_capacities_data(id: int, scrapeDate: str):
capacities = etl_pcm.property_capacities_monthly(id, scrapeDate)
return capacities
# get the capacity of a property for desired scraping date by days
@app.get("/property/{id}/capacities/daily/{scrapeDate}")
def property_capacities_data(id: int, scrapeDate: str):
capacities = etl_pcd.property_capacities_daily(id, scrapeDate)
return capacities
# get first / last time a property was fond, region id and name in which the property is located and the coordinates
@app.get("/property/{id}/base")
def property_base_data(id: int):
return d.property_base_data(id).pl().to_dicts()

View File

@ -328,7 +328,7 @@ class Database:
return self.connection.sql(f""" return self.connection.sql(f"""
SELECT SELECT
JSON_EXTRACT(body, '$.content.days') as calendar, JSON_EXTRACT(body, '$.content.days') as calendar,
created_at created_at as date
FROM FROM
consultancy_d.extractions consultancy_d.extractions
WHERE WHERE
@ -405,7 +405,7 @@ class Database:
p.property_platform_id, p.property_platform_id,
p.created_at as first_found, p.created_at as first_found,
p.last_found, p.last_found,
p.check_data, p.check_data as latlng,
r.id as region_id, r.id as region_id,
r.name as region_name r.name as region_name
FROM FROM
@ -423,8 +423,8 @@ class Database:
where = f"WHERE r.id = {id}" where = f"WHERE r.id = {id}"
return self.connection.sql(f""" return self.connection.sql(f"""
SELECT SELECT
r.id as region_id, r.id as id,
r.name as region_name r.name as name
FROM FROM
consultancy_d.regions r consultancy_d.regions r
{where} {where}

View File

@ -34,7 +34,7 @@ def property_capacities(id: int):
count_days.append(len(liste)) count_days.append(len(liste))
counts = pl.DataFrame({"count_days" : count_days, "sum" : sum_hor}) counts = pl.DataFrame({"count_days" : count_days, "sum" : sum_hor})
result = {"capacities": [], "dates": extractions['created_at'].cast(pl.Date).to_list() } result = {"capacities": [], "dates": extractions['date'].cast(pl.Date).to_list() }
for row in counts.rows(named=True): for row in counts.rows(named=True):
max_capacity = row['count_days'] * 2 max_capacity = row['count_days'] * 2

View File

@ -7,7 +7,7 @@ from data import etl_cache
d = data.load() d = data.load()
def property_capacities_weekdays(id: int, scrapeDate: str): def property_capacities_daily(id: int, scrapeDate: str):
file = f"etl_property_capacities_weekdays_{id}_{scrapeDate}.obj" file = f"etl_property_capacities_weekdays_{id}_{scrapeDate}.obj"
obj = etl_cache.openObj(file) obj = etl_cache.openObj(file)
@ -36,6 +36,6 @@ def property_capacities_weekdays(id: int, scrapeDate: str):
df_calendar = df_calendar.sort('weekday_num') df_calendar = df_calendar.sort('weekday_num')
df_calendar = df_calendar.drop('weekday_num') df_calendar = df_calendar.drop('weekday_num')
result = {"scraping-date": scrapeDate, "weekdays": df_calendar['weekday'].to_list(), 'capacities': df_calendar['column_0'].to_list()} result = {"date": scrapeDate, "weekdays": df_calendar['weekday'].to_list(), 'capacities': df_calendar['column_0'].to_list()}
etl_cache.saveObj(file, result) etl_cache.saveObj(file, result)
return result return result

View File

@ -33,6 +33,6 @@ def property_capacities_monthly(id: int, scrapeDate: str):
df_calendar = df_calendar.group_by(['dates', 'date_short', 'numDays']).agg(pl.col("column_0").sum()) df_calendar = df_calendar.group_by(['dates', 'date_short', 'numDays']).agg(pl.col("column_0").sum())
df_calendar = df_calendar.with_columns((pl.col("column_0") / pl.col("numDays") / 2 * 100).alias("column_0")) df_calendar = df_calendar.with_columns((pl.col("column_0") / pl.col("numDays") / 2 * 100).alias("column_0"))
df_calendar = df_calendar.sort('dates') df_calendar = df_calendar.sort('dates')
result = {"scraping-date": scrapeDate, "months": df_calendar['date_short'].to_list(), 'capacities': df_calendar['column_0'].to_list()} result = {"date": scrapeDate, "months": df_calendar['date_short'].to_list(), 'capacities': df_calendar['column_0'].to_list()}
etl_cache.saveObj(file, result) etl_cache.saveObj(file, result)
return result return result

View File

@ -1,8 +1,9 @@
import data
import polars as pl
from io import StringIO from io import StringIO
import numpy as np
import numpy as np
import polars as pl
import data
d = data.load() d = data.load()
@ -58,7 +59,7 @@ def region_capacities_comparison(id_1: int, id_2: int):
listOfPropertyIDs = listOfPropertyIDs.to_list() listOfPropertyIDs = listOfPropertyIDs.to_list()
# Create JSON # Create JSON
tempDict = {'scrapeDates': listOfDates, 'property_ids': listOfPropertyIDs, 'values': gridData} tempDict = {'dates': listOfDates, 'property_ids': listOfPropertyIDs, 'values': gridData}
outDictList.append(tempDict) outDictList.append(tempDict)
outDict = {'region1': outDictList[0], 'region2': outDictList[1],} outDict = {'region1': outDictList[0], 'region2': outDictList[1],}

View File

@ -8,7 +8,7 @@ from data import etl_cache
d = data.load() d = data.load()
def region_capacities_weekdays(id: int, scrapeDate_start: str): def region_capacities_daily(id: int, scrapeDate_start: str):
file = f"etl_region_capacities_weekdays_{id}_{scrapeDate_start}.obj" file = f"etl_region_capacities_weekdays_{id}_{scrapeDate_start}.obj"
obj = etl_cache.openObj(file) obj = etl_cache.openObj(file)
@ -62,6 +62,6 @@ def region_capacities_weekdays(id: int, scrapeDate_start: str):
outDf = outDf.insert_column(1, means) outDf = outDf.insert_column(1, means)
outDf = outDf[['weekday', 'mean']] outDf = outDf[['weekday', 'mean']]
result = {"scraping-date": scrapeDate, "weekdays": outDf['weekday'].to_list(),'capacities': outDf['mean'].to_list()} result = {"date": scrapeDate, "weekdays": outDf['weekday'].to_list(),'capacities': outDf['mean'].to_list()}
etl_cache.saveObj(file, result) etl_cache.saveObj(file, result)
return result return result

View File

@ -63,6 +63,6 @@ def region_capacities_monthly(id: int, scrapeDate_start: str):
outDf = outDf.insert_column(1, means) outDf = outDf.insert_column(1, means)
outDf = outDf[['date_short', 'mean']] outDf = outDf[['date_short', 'mean']]
result = {"scraping-date": scrapeDate, "months": outDf['date_short'].to_list(),'capacities': outDf['mean'].to_list()} result = {"date": scrapeDate, "months": outDf['date_short'].to_list(),'capacities': outDf['mean'].to_list()}
etl_cache.saveObj(file, result) etl_cache.saveObj(file, result)
return result return result

View File

@ -59,6 +59,6 @@ def region_properties_capacities(id: int):
listOfPropertyIDs = listOfPropertyIDs.cast(pl.String).to_list() listOfPropertyIDs = listOfPropertyIDs.cast(pl.String).to_list()
# Create JSON # Create JSON
outDict = {'scrapeDates': listOfDates, 'property_ids': listOfPropertyIDs, 'values': values} outDict = {'dates': listOfDates, 'property_ids': listOfPropertyIDs, 'values': values}
etl_cache.saveObj(file, outDict) etl_cache.saveObj(file, outDict)
return outDict return outDict