Merge branch 'main' of https://gitea.fhgr.ch/stoffelmauro/ConsultancyProject_2_ETL
commit
4487932f1b
|
@ -23,7 +23,7 @@ class Api
|
|||
return Cache::get($request);
|
||||
}
|
||||
|
||||
$get = Http::timeout(800)->get($request);
|
||||
$get = Http::timeout(1600)->get($request);
|
||||
|
||||
if($get->successful()){
|
||||
$result = $get->json();
|
||||
|
@ -94,6 +94,11 @@ class Api
|
|||
return self::get("/region/{$id}/capacities");
|
||||
}
|
||||
|
||||
public static function regionMovingAverage(int $id, string $date): mixed
|
||||
{
|
||||
return self::get("/region/{$id}/movingAverage/{$date}");
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -178,10 +178,10 @@ body.property main{
|
|||
grid-template-columns: repeat(4, minmax(10%, 50%));
|
||||
grid-template-rows: repeat(3, 1fr) 4em;
|
||||
grid-template-areas:
|
||||
"chart2 chart2 chart5 chart5"
|
||||
"chart1 chart1 chart3 chart4"
|
||||
"chart1 chart1 chart3 chart4"
|
||||
"timeline timeline timeline timeline";
|
||||
"chart2 chart2 chart1 chart1"
|
||||
"chart5 chart5 chart1 chart1"
|
||||
"chart5 chart5 chart3 chart4"
|
||||
"chart5 chart5 timeline timeline";
|
||||
}
|
||||
|
||||
body.region main{
|
||||
|
@ -190,8 +190,8 @@ body.region main{
|
|||
grid-template-areas:
|
||||
"chart1 chart1 chart2 chart2"
|
||||
"chart1 chart1 chart3 chart4"
|
||||
"chart1 chart1 chart3 chart4"
|
||||
"chart1 chart1 timeline timeline";
|
||||
"chart6 chart6 chart3 chart4"
|
||||
"chart6 chart6 timeline timeline";
|
||||
}
|
||||
|
||||
article{
|
||||
|
@ -204,7 +204,15 @@ article{
|
|||
|
||||
article.header{
|
||||
grid-template-columns: 100%;
|
||||
grid-template-rows: minmax(1%, 10%) 1fr;
|
||||
grid-template-rows: minmax(1%, 2.5em) 1fr;
|
||||
padding: .5em 1em 1em .5em;
|
||||
}
|
||||
|
||||
article.map{
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
article.map>header{
|
||||
padding: .5em 1em 1em .5em;
|
||||
}
|
||||
|
||||
|
@ -231,3 +239,33 @@ article>header>h2{
|
|||
grid-template-rows: repeat(4, minmax(20em, 25em));
|
||||
}
|
||||
}
|
||||
|
||||
.leaflet-marker-icon span{
|
||||
background: blue;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
display: block;
|
||||
left: -1rem;
|
||||
top: -1rem;
|
||||
position: relative;
|
||||
border-radius: 50% 50% 0;
|
||||
transform: rotate(45deg);
|
||||
border: 2px solid #fff
|
||||
}
|
||||
|
||||
/*['#9ecae1','#6baed6','#4292c6','#2171b5','#084594'*/
|
||||
.leaflet-marker-icon.region1 span{
|
||||
background: #9ecae1;
|
||||
}
|
||||
|
||||
.leaflet-marker-icon.region2 span{
|
||||
background: #6baed6;
|
||||
}
|
||||
|
||||
.leaflet-marker-icon.region3 span{
|
||||
background: #4292c6;
|
||||
}
|
||||
|
||||
.leaflet-marker-icon.region4 span{
|
||||
background: #2171b5;
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
|
||||
const sharedOptions = {
|
||||
basic: {
|
||||
color: ['#f1eef6','#bdc9e1','#74a9cf','#2b8cbe','#045a8d'],
|
||||
color: ['#9ecae1','#6baed6','#4292c6','#2171b5','#08519c','#08306b'],
|
||||
grid: {
|
||||
top: 20,
|
||||
left: 60,
|
||||
|
@ -156,6 +156,7 @@ const chartPropsPerRegion = document.getElementById('chart-props-per-region');
|
|||
const cPropsPerRegion = echarts.init(chartPropsPerRegion);
|
||||
const cPropsPerRegionOptions = {
|
||||
grid: sharedOptions.basic.grid,
|
||||
color: sharedOptions.basic.color,
|
||||
xAxis: {
|
||||
name: 'Region',
|
||||
nameLocation: 'center',
|
||||
|
@ -178,8 +179,13 @@ const cPropsPerRegionOptions = {
|
|||
series: [
|
||||
{
|
||||
data: {!! $propsPerRegion[1] !!},
|
||||
type: 'bar'
|
||||
type: 'bar',
|
||||
itemStyle: {
|
||||
color: (e) => {
|
||||
return sharedOptions.basic.color[e.dataIndex];
|
||||
}
|
||||
}
|
||||
},
|
||||
]
|
||||
};
|
||||
|
||||
|
@ -193,13 +199,13 @@ const filters = {
|
|||
}
|
||||
|
||||
const cExtractionsOptions = {
|
||||
color: sharedOptions.basic.color,
|
||||
tooltip: {
|
||||
trigger: 'axis'
|
||||
},
|
||||
legend: {
|
||||
data: filters.regions
|
||||
},
|
||||
color: sharedOptions.basic.color,
|
||||
grid: sharedOptions.basic.grid,
|
||||
xAxis: {
|
||||
name: 'Zeitpunkt Scraping',
|
||||
|
@ -226,30 +232,26 @@ const cExtractionsOptions = {
|
|||
name: 'Alle',
|
||||
type: 'line',
|
||||
stack: 'Total',
|
||||
data: {!! json_encode($growth['total_all']) !!}
|
||||
},
|
||||
{
|
||||
name: 'Heidiland',
|
||||
type: 'line',
|
||||
stack: 'Heidiland',
|
||||
data: {!! json_encode($growth['total_heidiland']) !!}
|
||||
data: {!! json_encode($growth['total_all']) !!},
|
||||
},
|
||||
{
|
||||
name: 'Davos',
|
||||
type: 'line',
|
||||
stack: 'Davos',
|
||||
data: {!! json_encode($growth['total_davos']) !!}
|
||||
},
|
||||
{
|
||||
name: 'Engadin',
|
||||
type: 'line',
|
||||
stack: 'Engadin',
|
||||
data: {!! json_encode($growth['total_engadin']) !!}
|
||||
},
|
||||
{
|
||||
name: 'Heidiland',
|
||||
type: 'line',
|
||||
data: {!! json_encode($growth['total_heidiland']) !!}
|
||||
},
|
||||
{
|
||||
name: 'St. Moritz',
|
||||
type: 'line',
|
||||
stack: 'St. Moritz',
|
||||
data: {!! json_encode($growth['total_stmoritz']) !!}
|
||||
},
|
||||
]
|
||||
|
@ -257,18 +259,37 @@ const cExtractionsOptions = {
|
|||
|
||||
cExtractions.setOption(cExtractionsOptions);
|
||||
|
||||
const map = L.map('leaflet').setView([46.862962, 9.535296], 9);
|
||||
const map = L.map('leaflet');
|
||||
|
||||
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
maxZoom: 19,
|
||||
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
|
||||
}).addTo(map);
|
||||
|
||||
const properties = {!! json_encode($geo) !!}
|
||||
properties.forEach( prop => {
|
||||
let coords = prop.coordinates.split(',');
|
||||
L.marker(coords).addTo(map).bindPopup('<a href="/prop/'+prop.id+'">'+prop.coordinates+'</a>');
|
||||
function icon(id){
|
||||
return L.divIcon({
|
||||
className: "region"+id,
|
||||
html: '<span></span>'
|
||||
})
|
||||
}
|
||||
|
||||
const markers = L.featureGroup([
|
||||
@foreach($geo as $g)
|
||||
L.marker([{{ $g['latlng'] }}], {icon: icon({{ $g['region_id'] }})}).bindPopup('<a href="/property/{{ $g['property_id'] }}">{{ $g['latlng'] }}</a>'),
|
||||
@endforeach
|
||||
]).addTo(map);
|
||||
|
||||
map.fitBounds(markers.getBounds(), {padding: [20,20]})
|
||||
|
||||
cHeatmap.on('click', 'series', (e) => {
|
||||
window.open(`/property/${e.value[1]}?date=${e.value[0]}`, '_self');
|
||||
})
|
||||
|
||||
cPropsPerRegion.on('click', 'series', (e) => {
|
||||
console.log(e.dataIndex);
|
||||
//window.open(`/property/${e.value[1]}?date=${e.value[0]}`, '_self');
|
||||
})
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
|
|
@ -32,6 +32,14 @@
|
|||
</header>
|
||||
<div id="chart-calendar"></div>
|
||||
</article>
|
||||
<article class="header map" style="grid-area: chart5;">
|
||||
<header>
|
||||
<h2 id="belegung-title">
|
||||
Kurzzeitmietobjekte in der Nähe
|
||||
</h2>
|
||||
</header>
|
||||
<div id="chart-map"></div>
|
||||
</article>
|
||||
<article class="header" style="grid-area: chart3;">
|
||||
<header>
|
||||
<h2>
|
||||
|
@ -80,7 +88,7 @@ const cTimelineOptions = {
|
|||
label: {
|
||||
show: false
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
cTimeline.setOption(cTimelineOptions);
|
||||
|
@ -168,6 +176,7 @@ const chartCapacity = document.getElementById('chart-capacity');
|
|||
const cCapacity = echarts.init(chartCapacity);
|
||||
|
||||
const cCapacityOptions = {
|
||||
color: ['#9ecae1','#6baed6','#4292c6','#2171b5','#084594'],
|
||||
legend: {
|
||||
data: ['Auslastung Property', 'Auslastung {{ $base['region_name'] }}', 'Auslastung alle Regionen']
|
||||
},
|
||||
|
@ -176,7 +185,7 @@ const cCapacityOptions = {
|
|||
valueFormatter: (value) => value.toFixed(2)+' %'
|
||||
},
|
||||
grid: {
|
||||
top: 20,
|
||||
top: 40,
|
||||
left: 25,
|
||||
right: 10,
|
||||
bottom: 20,
|
||||
|
@ -348,6 +357,29 @@ cTimeline.on('timelinechanged', (e) => {
|
|||
|
||||
})
|
||||
|
||||
/* Map w/ neighbours*/
|
||||
const map = L.map('chart-map');
|
||||
|
||||
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
maxZoom: 19,
|
||||
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
|
||||
}).addTo(map);
|
||||
|
||||
function icon(id = 0){
|
||||
return L.divIcon({
|
||||
className: "region"+id,
|
||||
html: '<span></span>'
|
||||
})
|
||||
}
|
||||
|
||||
const markers = L.featureGroup([
|
||||
@foreach($neighbours as $n)
|
||||
L.marker([{{ $n['lat'] }}, {{ $n['lon'] }}], {icon: icon()}).bindPopup('<a href="/property/{{ $n['id'] }}">{{ $n['lat'] }}, {{ $n['lon'] }}</a>'),
|
||||
@endforeach
|
||||
]).addTo(map);
|
||||
|
||||
map.fitBounds(markers.getBounds(), {padding: [20,20]})
|
||||
|
||||
cCapacity.on('click', 'series', (e) => {
|
||||
|
||||
// Switch to correct calendar in the timeline
|
||||
|
@ -356,7 +388,6 @@ cCapacity.on('click', 'series', (e) => {
|
|||
currentIndex: e.dataIndex
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -17,9 +17,15 @@
|
|||
<article style="grid-area: timeline;">
|
||||
<div id="timeline"></div>
|
||||
</article>
|
||||
<article class="header" style="grid-area: chart6;">
|
||||
<header>
|
||||
<h2 id="prediction-title">Auslastung Vorhersage</h2>
|
||||
</header>
|
||||
<div id="chart-prediction"></div>
|
||||
</article>
|
||||
<article class="header" style="grid-area: chart1;">
|
||||
<header>
|
||||
<h2 id="belegung-title"></h2>
|
||||
<h2 id="belegung-title">Gesamtauslastung</h2>
|
||||
</header>
|
||||
<div id="chart-heatmap"></div>
|
||||
</article>
|
||||
|
@ -58,7 +64,7 @@
|
|||
|
||||
const sharedOptions = {
|
||||
basic: {
|
||||
color: ['#f1eef6','#bdc9e1','#74a9cf','#2b8cbe','#045a8d'],
|
||||
color: ['#9ecae1','#6baed6','#4292c6','#2171b5','#084594'],
|
||||
grid: {
|
||||
top: 20,
|
||||
left: 60,
|
||||
|
@ -134,22 +140,90 @@ const cCapacityOptions = {
|
|||
|
||||
cCapacity.setOption(cCapacityOptions);
|
||||
|
||||
const chartPrediction = document.getElementById('chart-prediction');
|
||||
const cPrediction = echarts.init(chartPrediction);
|
||||
|
||||
const cPredictionOptions = {
|
||||
legend: {
|
||||
data: ['Moving Average', 'Earlier', 'Later']
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
valueFormatter: (value) => value.toFixed(2)+' %'
|
||||
},
|
||||
grid: {
|
||||
top: 20,
|
||||
left: 25,
|
||||
right: 10,
|
||||
bottom: 20,
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: {!! json_encode($prediction['dates']) !!},
|
||||
name: 'Zeitpunkt Scraping',
|
||||
nameLocation: 'center',
|
||||
nameGap: 24,
|
||||
nameTextStyle: {
|
||||
fontWeight: 'bold',
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
min: 0,
|
||||
max: 1,
|
||||
name: 'Auslastung in Prozent',
|
||||
nameLocation: 'center',
|
||||
nameGap: 38,
|
||||
nameTextStyle: {
|
||||
fontWeight: 'bold',
|
||||
}
|
||||
},
|
||||
series: [{
|
||||
name: 'Moving Average',
|
||||
type: 'line',
|
||||
symbolSize: 7,
|
||||
data: {!! json_encode($prediction['movAvg']) !!}
|
||||
},
|
||||
{
|
||||
name: 'Earlier',
|
||||
type: 'line',
|
||||
symbolSize: 7,
|
||||
data: {!! json_encode($prediction['cap_earlierTimeframe']) !!}
|
||||
},
|
||||
{
|
||||
name: 'Later',
|
||||
type: 'line',
|
||||
symbolSize: 7,
|
||||
data: {!! json_encode($prediction['cap_laterTimeframe']) !!}
|
||||
}]
|
||||
};
|
||||
|
||||
cPrediction.setOption(cPredictionOptions);
|
||||
|
||||
|
||||
const chartHeatmap = document.getElementById('chart-heatmap');
|
||||
const cHeatmap = echarts.init(chartHeatmap);
|
||||
const cHeatmapOptions = {
|
||||
animation: false,
|
||||
tooltip: {
|
||||
position: 'top'
|
||||
},
|
||||
grid: {
|
||||
top: 30,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
left: 0
|
||||
right: 45,
|
||||
bottom: 50,
|
||||
left: 5
|
||||
},
|
||||
dataZoom: [{
|
||||
type: 'inside'
|
||||
}
|
||||
],
|
||||
type: 'slider'
|
||||
},
|
||||
{
|
||||
type: 'slider',
|
||||
show: true,
|
||||
yAxisIndex: 0,
|
||||
}],
|
||||
xAxis: {
|
||||
show: false,
|
||||
name: 'Kurzzeitmietobjekt',
|
||||
|
@ -196,8 +270,7 @@ const cHeatmapOptions = {
|
|||
},
|
||||
tooltip: {
|
||||
formatter: (data) => {
|
||||
let v = data.value
|
||||
return `Kurzzeitmietobjekte-ID: ${data.name}<br />Datum Scraping: ${extractionDates[v[1]]}<br/>Auslastung: ${v[2]} %`
|
||||
return `Kurzzeitmietobjekte-ID: ${data.data[1]}<br />Datum Scraping: ${data.data[0]}<br/>Auslastung: ${data.data[2].toFixed(2)} %`
|
||||
},
|
||||
},
|
||||
emphasis: {
|
||||
|
|
|
@ -12,18 +12,20 @@ Route::get('/', function () {
|
|||
$propsPerRegion = Api::propertiesPerRegion();
|
||||
$propsPerRegionName = [];
|
||||
$propsPerRegionCounts = [];
|
||||
$propsPerRegionId = [];
|
||||
|
||||
foreach ($propsPerRegion as $el) {
|
||||
$propsPerRegionName[] = $el['name'];
|
||||
$propsPerRegionId[] = $el['id'];
|
||||
$propsPerRegionCounts[] = $el['count_properties'];
|
||||
}
|
||||
|
||||
$propertiesGeo = Api::propertiesGeo();
|
||||
|
||||
return view('overview', ["regions" => $regionBase, "regionPropertiesCapacities" => $regionPropertyCapacities, "geo" => $propertiesGeo, "growth" => $propertiesGrowth, "propsPerRegion" => [json_encode($propsPerRegionName), json_encode($propsPerRegionCounts)]]);
|
||||
return view('overview', ["regions" => $regionBase, "regionPropertiesCapacities" => $regionPropertyCapacities, "geo" => $propertiesGeo, "growth" => $propertiesGrowth, "propsPerRegion" => [json_encode($propsPerRegionId), json_encode($propsPerRegionName), json_encode($propsPerRegionCounts)]]);
|
||||
});
|
||||
|
||||
Route::get('/prop/{id}', function (int $id) {
|
||||
Route::get('/property/{id}', function (int $id) {
|
||||
|
||||
$propertyBase = Api::propertyBase($id);
|
||||
$calendars = Api::propertyExtractions($id);
|
||||
|
@ -90,13 +92,14 @@ Route::get('/region/{id}', function (int $id) {
|
|||
$regionBaseAll = Api::regionBase(-1);
|
||||
$regionBaseAll[] = ['region_name' => 'Alle Regionen', 'region_id' => -1];
|
||||
$regionBaseRegion = $id >= 0 ? Api::regionBase($id) : [['region_name' => 'Alle Regionen']];
|
||||
$regionMovingAverage = Api::regionMovingAverage($id, '2024-04-25');
|
||||
|
||||
$regionPropertiesCapacities = Api::regionPropertiesCapacities($id);
|
||||
$regionCapacitiesRegion = Api::regionCapacities($id);
|
||||
$regionCapacitiesAll = Api::regionCapacities(-1);
|
||||
$regionCapacities = [$regionCapacitiesAll, $regionCapacitiesRegion];
|
||||
|
||||
return view('region', ['regions' => $regionBaseAll, 'region' => $regionBaseRegion, 'region_id' => $id, 'regionCapacities' => $regionCapacities, 'regionPropertiesCapacities' => $regionPropertiesCapacities]);
|
||||
return view('region', ['regions' => $regionBaseAll, 'region' => $regionBaseRegion, 'region_id' => $id, 'regionCapacities' => $regionCapacities, 'regionPropertiesCapacities' => $regionPropertiesCapacities, 'prediction' => $regionMovingAverage]);
|
||||
|
||||
|
||||
});
|
||||
|
|
|
@ -1,30 +1,92 @@
|
|||
<mxfile host="app.diagrams.net" agent="Mozilla/5.0 (X11; Linux x86_64; rv:133.0) Gecko/20100101 Firefox/133.0" version="25.0.3">
|
||||
<diagram name="Seite-1" id="5abS_fUiar5VuBZXZINZ">
|
||||
<mxGraphModel dx="1195" dy="1534" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||
<mxfile host="app.diagrams.net" agent="Mozilla/5.0 (X11; Linux x86_64; rv:134.0) Gecko/20100101 Firefox/134.0" version="26.0.5">
|
||||
<diagram name="Seite-1" id="chpUGVRRn7alPJZ1I-il">
|
||||
<mxGraphModel dx="819" dy="1052" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<object placeholders="1" c4Name="REST-API" c4Type="Python (FastAPI)" c4Description="REST Schnittstelle" label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%]</div><br><div><font style="font-size: 11px"><font color="#cccccc">%c4Description%</font></div>" id="DRD_0cKAZXVdgcTgqyKr-1">
|
||||
<mxCell style="rounded=1;whiteSpace=wrap;html=1;labelBackgroundColor=none;fillColor=#1061B0;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0D5091;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
|
||||
<mxGeometry x="360" y="40" width="240" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
</object>
|
||||
<mxCell id="DRD_0cKAZXVdgcTgqyKr-5" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="DRD_0cKAZXVdgcTgqyKr-2" target="DRD_0cKAZXVdgcTgqyKr-1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<object placeholders="1" c4Name="Data" c4Type="Python (Polars)" c4Description="Eigenes Python Package. Enthält Programmcode für das ETL" label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%]</div><br><div><font style="font-size: 11px"><font color="#cccccc">%c4Description%</font></div>" id="DRD_0cKAZXVdgcTgqyKr-2">
|
||||
<mxCell style="rounded=1;whiteSpace=wrap;html=1;labelBackgroundColor=none;fillColor=#1061B0;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0D5091;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
|
||||
<mxGeometry x="40" y="40" width="240" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
</object>
|
||||
<object placeholders="1" c4Name="Datenbank" c4Type="Container" c4Technology="DuckDB" c4Description="Datenbank, welches die aggregierten Daten enthält." label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%:&nbsp;%c4Technology%]</div><br><div><font style="font-size: 11px"><font color="#E6E6E6">%c4Description%</font></div>" id="DRD_0cKAZXVdgcTgqyKr-3">
|
||||
<object placeholders="1" c4Name="RDBMS" c4Type="Container" c4Technology="DuckDB" c4Description="Aggregierte Daten." label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%:&nbsp;%c4Technology%]</div><br><div><font style="font-size: 11px"><font color="#E6E6E6">%c4Description%</font></div>" id="_wAeSdXpbb6KPP4DEc36-2">
|
||||
<mxCell style="shape=cylinder3;size=15;whiteSpace=wrap;html=1;boundedLbl=1;rounded=0;labelBackgroundColor=none;fillColor=#23A2D9;fontSize=12;fontColor=#ffffff;align=center;strokeColor=#0E7DAD;metaEdit=1;points=[[0.5,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.5,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];resizable=0;" vertex="1" parent="1">
|
||||
<mxGeometry x="40" y="240" width="240" height="120" as="geometry" />
|
||||
<mxGeometry x="50" y="60" width="240" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
</object>
|
||||
<mxCell id="DRD_0cKAZXVdgcTgqyKr-4" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="DRD_0cKAZXVdgcTgqyKr-2" target="DRD_0cKAZXVdgcTgqyKr-3">
|
||||
<object placeholders="1" c4Name="ETL" c4Type="SQL, Python (Polars)" c4Description="Bereitet Daten mittels algorithmischer<br> Verfahren auf." label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%]</div><br><div><font style="font-size: 11px"><font color="#cccccc">%c4Description%</font></div>" id="_wAeSdXpbb6KPP4DEc36-3">
|
||||
<mxCell style="rounded=1;whiteSpace=wrap;html=1;labelBackgroundColor=none;fillColor=#1061B0;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0D5091;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
|
||||
<mxGeometry x="480" y="60" width="240" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
</object>
|
||||
<mxCell id="_wAeSdXpbb6KPP4DEc36-4" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;dashed=1;dashPattern=8 8;" edge="1" parent="1" source="_wAeSdXpbb6KPP4DEc36-3" target="_wAeSdXpbb6KPP4DEc36-2">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_wAeSdXpbb6KPP4DEc36-5" value="Liest Datenbank" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="_wAeSdXpbb6KPP4DEc36-4">
|
||||
<mxGeometry x="0.0412" y="1" relative="1" as="geometry">
|
||||
<mxPoint x="-1" y="-1" as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_wAeSdXpbb6KPP4DEc36-15" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;dashed=1;dashPattern=8 8;entryX=0;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="_wAeSdXpbb6KPP4DEc36-6" target="_wAeSdXpbb6KPP4DEc36-13">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_wAeSdXpbb6KPP4DEc36-21" value="<div>Führt Abfragen aus</div><div>[JSON/HTTPS]<br></div>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="_wAeSdXpbb6KPP4DEc36-15">
|
||||
<mxGeometry x="-0.0541" y="-1" relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<object placeholders="1" c4Name="Webapplikation" c4Type="PHP (Laravel)" c4Description="Verarbeitet Anfragen von Benutzer:innen" label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%]</div><br><div><font style="font-size: 11px"><font color="#cccccc">%c4Description%</font></div>" id="_wAeSdXpbb6KPP4DEc36-6">
|
||||
<mxCell style="rounded=1;whiteSpace=wrap;html=1;labelBackgroundColor=none;fillColor=#1061B0;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0D5091;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
|
||||
<mxGeometry x="50" y="230" width="240" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
</object>
|
||||
<object placeholders="1" c4Name="Dashboard" c4Type="Container" c4Technology="Apache Echarts" c4Description="Stellt Benutzer:innen Auswertungs-<br>möglichkeiten zur Verfügbarkeit von Kurzzeitmietobjekten." label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%:&nbsp;%c4Technology%]</div><br><div><font style="font-size: 11px"><font color="#E6E6E6">%c4Description%</font></div>" id="_wAeSdXpbb6KPP4DEc36-8">
|
||||
<mxCell style="shape=mxgraph.c4.webBrowserContainer2;whiteSpace=wrap;html=1;boundedLbl=1;rounded=0;labelBackgroundColor=none;strokeColor=#118ACD;fillColor=#23A2D9;strokeColor=#118ACD;strokeColor2=#0E7DAD;fontSize=12;fontColor=#ffffff;align=center;metaEdit=1;points=[[0.5,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.5,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];resizable=0;" vertex="1" parent="1">
|
||||
<mxGeometry x="480" y="370" width="240" height="160" as="geometry" />
|
||||
</mxCell>
|
||||
</object>
|
||||
<mxCell id="_wAeSdXpbb6KPP4DEc36-10" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;exitPerimeter=0;dashed=1;dashPattern=8 8;" edge="1" parent="1" source="_wAeSdXpbb6KPP4DEc36-9" target="_wAeSdXpbb6KPP4DEc36-6">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_wAeSdXpbb6KPP4DEc36-16" value="<div>Besucht Webapplikation</div><div>[HTTPS]<br></div>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="_wAeSdXpbb6KPP4DEc36-10">
|
||||
<mxGeometry x="0.1247" y="-2" relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_wAeSdXpbb6KPP4DEc36-11" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;exitPerimeter=0;dashed=1;dashPattern=8 8;" edge="1" parent="1" source="_wAeSdXpbb6KPP4DEc36-9" target="_wAeSdXpbb6KPP4DEc36-8">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_wAeSdXpbb6KPP4DEc36-17" value="Betrachtet Auswertungen" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="_wAeSdXpbb6KPP4DEc36-11">
|
||||
<mxGeometry x="0.2151" y="-1" relative="1" as="geometry">
|
||||
<mxPoint x="2" as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<object placeholders="1" c4Name="Benutzer:in" c4Type="Person" c4Description="Person welche Auswertungen zur Verfügbarkeit von Kurzzeitmietobjekten in Ferienregionen durchführt." label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%]</div><br><div><font style="font-size: 11px"><font color="#cccccc">%c4Description%</font></div>" id="_wAeSdXpbb6KPP4DEc36-9">
|
||||
<mxCell style="html=1;fontSize=11;dashed=0;whiteSpace=wrap;fillColor=#083F75;strokeColor=#06315C;fontColor=#ffffff;shape=mxgraph.c4.person2;align=center;metaEdit=1;points=[[0.5,0,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0]];resizable=0;" vertex="1" parent="1">
|
||||
<mxGeometry x="314" y="600" width="200" height="180" as="geometry" />
|
||||
</mxCell>
|
||||
</object>
|
||||
<mxCell id="_wAeSdXpbb6KPP4DEc36-14" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;entryPerimeter=0;dashed=1;dashPattern=8 8;" edge="1" parent="1" source="_wAeSdXpbb6KPP4DEc36-13" target="_wAeSdXpbb6KPP4DEc36-3">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_wAeSdXpbb6KPP4DEc36-20" value="Ruft ETL Verfahren auf" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="_wAeSdXpbb6KPP4DEc36-14">
|
||||
<mxGeometry x="-0.0667" y="-1" relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<object placeholders="1" c4Name="FastAPI" c4Type="Python (FastAPI)" c4Description="Stellt aufbereitete Daten via <br>JSON/HTTPS API zur Verfügung." label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%]</div><br><div><font style="font-size: 11px"><font color="#cccccc">%c4Description%</font></div>" id="_wAeSdXpbb6KPP4DEc36-13">
|
||||
<mxCell style="rounded=1;whiteSpace=wrap;html=1;labelBackgroundColor=none;fillColor=#1061B0;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0D5091;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
|
||||
<mxGeometry x="480" y="230" width="240" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
</object>
|
||||
<mxCell id="_wAeSdXpbb6KPP4DEc36-18" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;dashed=1;dashPattern=8 8;" edge="1" parent="1" source="_wAeSdXpbb6KPP4DEc36-6" target="_wAeSdXpbb6KPP4DEc36-8">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_wAeSdXpbb6KPP4DEc36-19" value="<div>Liefert Inhalte zum Webbrowser&nbsp;</div><div>von Benutzer:innen</div>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="_wAeSdXpbb6KPP4DEc36-18">
|
||||
<mxGeometry x="-0.0888" y="-2" relative="1" as="geometry">
|
||||
<mxPoint x="5" y="7" as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<object placeholders="1" c4Name="Visual Analytics Tool" c4Type="SystemScopeBoundary" c4Application="Software System" label="<font style="font-size: 16px"><b><div style="text-align: left">%c4Name%</div></b></font><div style="text-align: left">[%c4Application%]</div>" id="_wAeSdXpbb6KPP4DEc36-23">
|
||||
<mxCell style="rounded=1;fontSize=11;whiteSpace=wrap;html=1;dashed=1;arcSize=20;fillColor=none;strokeColor=#666666;fontColor=#333333;labelBackgroundColor=none;align=left;verticalAlign=bottom;labelBorderColor=none;spacingTop=0;spacing=10;dashPattern=8 4;metaEdit=1;rotatable=0;perimeter=rectanglePerimeter;noLabel=0;labelPadding=0;allowArrows=0;connectable=0;expand=0;recursiveResize=0;editable=1;pointerEvents=0;absoluteArcSize=1;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
|
||||
<mxGeometry x="30" y="40" width="710" height="540" as="geometry" />
|
||||
</mxCell>
|
||||
</object>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
|
|
|
@ -9,6 +9,7 @@ from data import etl_region_capacities_weekdays as etl_rcw
|
|||
from data import etl_region_movAverage as etl_rmA
|
||||
from data import etl_region_properties_capacities as etl_rpc
|
||||
from data import etl_region_capacities_comparison as etl_rcc
|
||||
from data import etl_region_movAverage as etl_rmA
|
||||
from data import etl_region_properties_capacities as etl_rpc
|
||||
from fastapi import FastAPI, Response
|
||||
|
||||
|
|
|
@ -137,6 +137,7 @@ class Database:
|
|||
return self.connection.sql("""
|
||||
SELECT
|
||||
regions.name,
|
||||
regions.id,
|
||||
COUNT(*) AS count_properties
|
||||
FROM
|
||||
consultancy_d.properties
|
||||
|
@ -146,7 +147,8 @@ class Database:
|
|||
consultancy_d.regions ON regions.id = seeds.region_id
|
||||
GROUP BY
|
||||
properties.seed_id,
|
||||
regions.name
|
||||
regions.name,
|
||||
regions.id
|
||||
ORDER BY
|
||||
count_properties ASC
|
||||
""")
|
||||
|
@ -427,10 +429,15 @@ class Database:
|
|||
def properties_geo(self):
|
||||
return self.connection.sql("""
|
||||
SELECT
|
||||
p.id,
|
||||
p.check_data as coordinates
|
||||
p.id as property_id,
|
||||
p.check_data as latlng,
|
||||
r.id as region_id
|
||||
FROM
|
||||
consultancy_d.properties p
|
||||
LEFT JOIN
|
||||
consultancy_d.seeds s ON s.id = p.seed_id
|
||||
LEFT JOIN
|
||||
consultancy_d.regions r ON r.id = s.region_id
|
||||
""")
|
||||
|
||||
def properties_geo_seeds(self):
|
||||
|
|
Loading…
Reference in New Issue