232 lines
9.7 KiB
Python
232 lines
9.7 KiB
Python
from flask import Flask, render_template, request
|
|
from flask_sqlalchemy import SQLAlchemy
|
|
from tabulate import tabulate
|
|
from sqlalchemy import text
|
|
import folium
|
|
import os
|
|
from decimal import Decimal
|
|
|
|
## INIT
|
|
app = Flask(__name__, template_folder=os.path.abspath('.'))
|
|
app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv('DATABASE_URL', 'postgresql://huaqo:0000@localhost:5432/geowebapp')
|
|
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
|
db = SQLAlchemy(app)
|
|
|
|
|
|
## QUERIES
|
|
DATASET = """
|
|
SELECT {attributes}
|
|
FROM Hochschulen h
|
|
JOIN Mieten m ON m.land = h.land
|
|
LEFT JOIN Bevoelkerung b ON b.region_name = h.ort
|
|
AND b.bundesland = h.land
|
|
AND (
|
|
b.region_type = 'kreis'
|
|
OR b.region_name = 'Berlin'
|
|
OR b.region_name = 'Hamburg'
|
|
OR b.region_name = 'Bremen'
|
|
OR b.region_name = 'Hannover' AND b.region_type = 'landeshauptstadt'
|
|
OR b.region_name = 'Saarbrücken' AND b.region_type = 'landeshauptstadt')
|
|
WHERE {search_attr} ILIKE :search
|
|
ORDER BY {sort_by} {order}
|
|
LIMIT {limit};
|
|
"""
|
|
DATASET_GROUPED = """
|
|
SELECT {group_by}, COUNT(*) AS Anzahl
|
|
FROM Hochschulen
|
|
GROUP BY {group_by}
|
|
ORDER BY Anzahl DESC;
|
|
"""
|
|
|
|
## PARAMETERS
|
|
order_by_options = [
|
|
{'value': 'land', 'label': 'Bundesland'},
|
|
{'value': 'typ', 'label': 'Hochschultyp'},
|
|
{'value': 'traeger', 'label': 'Träger'},
|
|
{'value': 'precht', 'label': 'Promotionsrecht'},
|
|
{'value': 'hrecht', 'label': 'Habilitationsrecht'}
|
|
]
|
|
|
|
shortcut_options = [
|
|
{'url': '//127.0.0.1:5000/?search_attr=typ&search=&order=ASC&sort_by=gjahr&limit=10&attributes=&attributes=h.name_h&attributes=h.gjahr&attributes=h.ort&generate_map=true', 'label': 'Älteste Hochschulen in Deutschland'},
|
|
{'url': '//127.0.0.1:5000/?search_attr=typ&search=&order=DESC&sort_by=gjahr&limit=10&attributes=&attributes=h.name_h&attributes=h.gjahr&attributes=h.ort&generate_map=true', 'label': 'Jüngste Hochschulen in Deutschland'},
|
|
{'url': '//127.0.0.1:5000/?search_attr=typ&search=&order=DESC&sort_by=studenten&limit=10&attributes=&attributes=h.name_h&attributes=h.studenten&attributes=h.ort&generate_map=true', 'label': 'Hochschulen mit den meisten Studenten'},
|
|
{'url': '//127.0.0.1:5000/?search_attr=h.land&search=Berlin&order=DESC&sort_by=studenten&limit=10&attributes=&attributes=h.name_h&attributes=h.studenten&generate_map=true', 'label': 'Berliner Hochschulen mit den meisten Studenten'},
|
|
{'url': '//127.0.0.1:5000/?search_attr=typ&search=&order=ASC&sort_by=studenten&limit=10&attributes=&attributes=h.name_h&attributes=h.studenten&attributes=h.ort&generate_map=true', 'label': 'Hochschulen mit den wenigsten Studenten'},
|
|
{'url': '//127.0.0.1:5000/?search_attr=typ&search=&order=DESC&sort_by=b.total_population&limit=10&attributes=&attributes=h.name_h&attributes=h.ort&attributes=b.total_population&generate_map=true', 'label': 'Hochschulen mit den meisten Einwohnern'},
|
|
{'url': '//127.0.0.1:5000/?search_attr=typ&search=&order=ASC&sort_by=b.total_population&limit=10&attributes=&attributes=h.name_h&attributes=h.ort&attributes=b.total_population&generate_map=true', 'label': 'Hochschulen mit den wenigsten Einwohnern'},
|
|
{'url': '//127.0.0.1:5000/?search_attr=typ&search=&order=ASC&sort_by=m.mieten_ab_2019&limit=100&attributes=&attributes=h.name_h&attributes=h.ort&attributes=m.mieten_ab_2019&generate_map=true', 'label': 'Hochschulen mit den niedrigsten Mieten'},
|
|
{'url': '//127.0.0.1:5000/?search_attr=typ&search=&order=DESC&sort_by=m.mieten_ab_2019&limit=200&attributes=&attributes=h.name_h&attributes=h.ort&attributes=m.mieten_ab_2019&generate_map=true', 'label': 'Hochschulen mit den höchsten Mieten'}
|
|
]
|
|
|
|
search_options = [
|
|
{'value': 'h.name_h', 'label': 'Hochschulname'},
|
|
{'value': 'h.typ', 'label': 'Typ'},
|
|
{'value': 'h.traeger', 'label': 'Träger'},
|
|
{'value': 'h.land', 'label': 'Land'},
|
|
{'value': 'h.precht', 'label': 'Precht'},
|
|
{'value': 'h.hrecht', 'label': 'Hrecht'},
|
|
{'value': 'h.str', 'label': 'Straße'},
|
|
{'value': 'h.ort', 'label': 'Ort'},
|
|
{'value': 'h.web', 'label': 'Web'}
|
|
]
|
|
|
|
order_options = [
|
|
{'value': 'ASC', 'label': 'Aufsteigend'},
|
|
{'value': 'DESC', 'label': 'Absteigend'}
|
|
]
|
|
|
|
sort_by_options = [
|
|
{'value': 'name_h', 'label': 'Hochschulname'},
|
|
{'value': 'gjahr', 'label': 'Gründungsjahr'},
|
|
{'value': 'typ', 'label': 'Typ'},
|
|
{'value': 'traeger', 'label': 'Träger'},
|
|
{'value': 'land', 'label': 'Land'},
|
|
{'value': 'studenten', 'label': 'Studenten'},
|
|
{'value': 'precht', 'label': 'Precht'},
|
|
{'value': 'hrecht', 'label': 'Hrecht'},
|
|
{'value': 'plz', 'label': 'PLZ'},
|
|
{'value': 'str', 'label': 'Straße'},
|
|
{'value': 'ort', 'label': 'Ort'},
|
|
{'value': 'b.total_population', 'label': 'Einwohner'},
|
|
{'value': 'm.mieten_ab_2019', 'label': 'Mieten'}
|
|
]
|
|
|
|
checkbox_options = [
|
|
{'value': 'h.name_h', 'label': 'Hochschulname'},
|
|
{'value': 'h.gjahr', 'label': 'Gründungsjahr'},
|
|
{'value': 'h.typ', 'label': 'Typ'},
|
|
{'value': 'h.traeger', 'label': 'Träger'},
|
|
{'value': 'h.land', 'label': 'Land'},
|
|
{'value': 'h.studenten', 'label': 'Studenten'},
|
|
{'value': 'h.precht', 'label': 'Precht'},
|
|
{'value': 'h.hrecht', 'label': 'Hrecht'},
|
|
{'value': 'h.plz', 'label': 'PLZ'},
|
|
{'value': 'h.str', 'label': 'Straße'},
|
|
{'value': 'h.ort', 'label': 'Ort'},
|
|
{'value': 'h.web', 'label': 'Web'},
|
|
{'value': 'b.total_population', 'label': 'Einwohner'},
|
|
{'value': 'm.mieten_ab_2019', 'label': 'Mieten'}
|
|
]
|
|
|
|
## DATA QUERY
|
|
class Dataset_Parameters:
|
|
def __init__(self, order='ASC', limit='10', sort_by='gjahr', attributes=['name_h'], search='', search_attr='name_h', group_by='typ'):
|
|
if attributes is None:
|
|
attributes = ['name_h']
|
|
self.order = order
|
|
self.limit = limit
|
|
self.sort_by = sort_by
|
|
self.attributes = attributes
|
|
self.search = search
|
|
self.search_attr = search_attr
|
|
self.group_by = group_by
|
|
|
|
def update(self, **kwargs):
|
|
for key, value in kwargs.items():
|
|
if hasattr(self, key):
|
|
setattr(self, key, value)
|
|
|
|
@classmethod
|
|
def get_parameters(cls, request):
|
|
parameters = cls()
|
|
parameters.update(
|
|
order=request.args.get('order', parameters.order),
|
|
limit=request.args.get('limit', parameters.limit),
|
|
sort_by=request.args.get('sort_by', parameters.sort_by),
|
|
attributes=request.args.getlist('attributes') or parameters.attributes,
|
|
search=request.args.get('search', parameters.search),
|
|
search_attr=request.args.get('search_attr', parameters.search_attr),
|
|
group_by=request.args.get('group_by', parameters.group_by)
|
|
)
|
|
parameters.attributes = [attr for attr in parameters.attributes if attr]
|
|
if 'lat' not in parameters.attributes:
|
|
parameters.attributes.append('lat')
|
|
if 'lon' not in parameters.attributes:
|
|
parameters.attributes.append('lon')
|
|
return parameters
|
|
|
|
def get_data(query_template, parameters):
|
|
params_dict = {k: v for k, v in parameters.__dict__.items()}
|
|
for key, value in params_dict.items():
|
|
if isinstance(value, list):
|
|
params_dict[key] = ', '.join(value)
|
|
query = query_template.format(**params_dict)
|
|
result = db.session.execute(text(query), {'search': f"%{params_dict.get('search', '')}%"})
|
|
|
|
return result.fetchall()
|
|
|
|
## TABLES
|
|
def create_table(data, parameters):
|
|
lat_index = parameters.attributes.index('lat') if 'lat' in parameters.attributes else -1
|
|
lon_index = parameters.attributes.index('lon') if 'lon' in parameters.attributes else -1
|
|
|
|
filtered_data = []
|
|
for row in data:
|
|
filtered_row = [value for i, value in enumerate(row) if i not in [lat_index, lon_index]]
|
|
filtered_data.append(filtered_row)
|
|
|
|
filtered_attributes = [attr for attr in parameters.attributes if attr not in ['lat', 'lon']]
|
|
table = tabulate(filtered_data, headers=filtered_attributes, tablefmt='html')
|
|
return table
|
|
def create_grouped_table(data, parameters):
|
|
headers = [parameters.group_by, 'Anzahl']
|
|
table = tabulate(data, headers=headers, tablefmt='html')
|
|
return table
|
|
|
|
## MAP
|
|
def generate_map(data, column_names):
|
|
map_center = [51.1657, 10.4515]
|
|
map = folium.Map(location=map_center, tiles="cartodb positron", zoom_start=6)
|
|
|
|
try:
|
|
lat_index = column_names.index('lat')
|
|
lon_index = column_names.index('lon')
|
|
except ValueError:
|
|
print("Lat or Lon column not found in the result set")
|
|
return None
|
|
|
|
bounds = []
|
|
for row in data:
|
|
lat = row[lat_index]
|
|
lon = row[lon_index]
|
|
if isinstance(lat, Decimal):
|
|
lat = float(lat)
|
|
if isinstance(lon, Decimal):
|
|
lon = float(lon)
|
|
if lat is not None and lon is not None:
|
|
folium.Marker([lat, lon], popup=f"Data: {row}").add_to(map)
|
|
bounds.append([lat, lon])
|
|
|
|
if bounds:
|
|
map.fit_bounds(bounds)
|
|
|
|
map_html = map._repr_html_()
|
|
return map_html
|
|
|
|
## VIEWS
|
|
@app.route('/', methods=['GET'])
|
|
def home():
|
|
dataset_parameters = Dataset_Parameters.get_parameters(request)
|
|
dataset = get_data(DATASET, dataset_parameters)
|
|
dataset_grouped = get_data(DATASET_GROUPED, dataset_parameters)
|
|
table = create_table(dataset, dataset_parameters)
|
|
table_grouped = create_grouped_table(dataset_grouped, dataset_parameters)
|
|
map = generate_map(dataset, dataset_parameters.attributes)
|
|
return render_template(
|
|
'index.html',
|
|
table=table,
|
|
table_grouped=table_grouped,
|
|
parameters=dataset_parameters,
|
|
map=map,
|
|
order_by_options=order_by_options,
|
|
search_options=search_options,
|
|
order_options=order_options,
|
|
sort_by_options=sort_by_options,
|
|
shortcut_options=shortcut_options,
|
|
checkbox_options=checkbox_options)
|
|
|
|
## RUN
|
|
if __name__ == '__main__':
|
|
app.run(debug=True)
|