Country dependant receiver rankings (#157)

* Added receiver_rankings, fixed receiver_status

* Added receiver_rankings updates

* Modified receiver_ranking.html

* Removed obsolete code

* Bugfix: order countries for select box
pull/78/head
Meisterschueler 2020-12-03 11:24:23 +01:00 zatwierdzone przez GitHub
rodzic 0dea6210c1
commit b5893e9e61
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
8 zmienionych plików z 165 dodań i 25 usunięć

Wyświetl plik

@ -7,7 +7,7 @@ from sqlalchemy.orm.exc import NoResultFound
from app import db
from app import cache
from app.model import Airport, Country, Sender, SenderInfo, TakeoffLanding, Logbook, Receiver, SenderPosition, RelationStatistic, ReceiverStatistic, SenderStatistic, FrequencyScanFile
from app.model import Airport, Country, Sender, SenderInfo, TakeoffLanding, Logbook, Receiver, SenderPosition, RelationStatistic, ReceiverRanking, ReceiverStatistic, SenderStatistic, FrequencyScanFile
from app.main import bp
from app.main.matplotlib_service import create_range_figure
@ -222,18 +222,36 @@ def sender_ranking():
ranking=sender_statistics)
@bp.route("/receiver_ranking.html")
@cache.cached()
@bp.route("/receiver_ranking.html", methods=["GET", "POST"])
@cache.cached(query_string=True)
def receiver_ranking():
receiver_statistics = db.session.query(ReceiverStatistic) \
.filter(db.and_(ReceiverStatistic.date == date.today(), ReceiverStatistic.is_trustworthy == db.true())) \
.order_by(ReceiverStatistic.max_distance.desc()) \
.all()
sel_country = request.args.get("country")
countries = db.session.query(Country) \
.filter(Country.gid == ReceiverRanking.country_id) \
.filter(ReceiverRanking.date == date.today()) \
.order_by(Country.iso2)
# Get receiver selection list
if sel_country:
ranking = db.session.query(ReceiverRanking) \
.join(Country) \
.filter(db.and_(ReceiverRanking.country_id == Country.gid, Country.iso2 == sel_country)) \
.filter(db.and_(ReceiverRanking.date == date.today())) \
.order_by(ReceiverRanking.global_rank.asc()) \
.all()
else:
ranking = db.session.query(ReceiverRanking) \
.filter(db.and_(ReceiverRanking.date == date.today())) \
.order_by(ReceiverRanking.global_rank.asc()) \
.all()
return render_template(
"receiver_ranking.html",
title="Receiver Ranking",
ranking=receiver_statistics)
sel_country=sel_country,
countries=countries,
ranking=ranking)
@bp.route("/upload_file", methods=["POST"])

Wyświetl plik

@ -22,3 +22,4 @@ from .sender_statistic import SenderStatistic
from .receiver_statistic import ReceiverStatistic
from .sender_position_statistic import SenderPositionStatistic
from .sender_direction_statistic import SenderDirectionStatistic
from .receiver_ranking import ReceiverRanking

Wyświetl plik

@ -0,0 +1,26 @@
from app import db
class ReceiverRanking(db.Model):
__tablename__ = "receiver_rankings"
id = db.Column(db.Integer, primary_key=True)
date = db.Column(db.Date)
local_rank = db.Column(db.Integer)
global_rank = db.Column(db.Integer)
max_distance = db.Column(db.Float(precision=2))
max_normalized_quality = db.Column(db.Float(precision=2))
messages_count = db.Column(db.Integer)
coverages_count = db.Column(db.Integer)
senders_count = db.Column(db.Integer)
# Relations
receiver_id = db.Column(db.Integer, db.ForeignKey("receivers.id", ondelete="CASCADE"), index=True)
receiver = db.relationship("Receiver", foreign_keys=[receiver_id], backref=db.backref("rankings", order_by=date.desc()))
country_id = db.Column(db.Integer, db.ForeignKey("countries.gid", ondelete="CASCADE"), index=True)
country = db.relationship("Country", foreign_keys=[country_id], backref=db.backref("rankings", order_by=date.desc()))
__table_args__ = (db.Index('idx_receiver_rankings_uc', 'date', 'receiver_id', unique=True), )

Wyświetl plik

@ -41,8 +41,3 @@ class ReceiverStatus(db.Model):
good_senders_signal = None
good_senders = None
good_and_bad_senders = None
# Calculated values (from this software)
location_mgrs = db.Column(db.String(15)) # full mgrs (15 chars)
location_mgrs_short = db.Column(db.String(9)) # reduced mgrs (9 chars), e.g. used for melissas range tool
agl = db.Column(db.Float(precision=2))

Wyświetl plik

@ -76,6 +76,30 @@ def update_statistics(date_str=None):
GROUP BY date, receiver_id, is_trustworthy;
""")
# Update receiver rankings
db.session.execute(f"""
DELETE FROM receiver_rankings
WHERE date = '{date_str}';
INSERT INTO receiver_rankings AS rr (date, receiver_id, country_id, local_rank, global_rank, max_distance, max_normalized_quality, messages_count, coverages_count, senders_count)
SELECT
rs.date,
rs.receiver_id,
r.country_id,
RANK() OVER (PARTITION BY rs.date, r.country_id ORDER BY rs.max_distance DESC) AS local_rank,
RANK() OVER (ORDER BY rs.max_distance DESC) AS global_rank,
rs.max_distance,
rs.max_normalized_quality,
rs.messages_count,
rs.coverages_count,
rs.senders_count
FROM receiver_statistics AS rs
LEFT JOIN receivers AS r ON rs.receiver_id = r.id
WHERE rs.date = '{date_str}' AND rs.is_trustworthy IS TRUE;
""")
db.session.commit()

Wyświetl plik

@ -8,25 +8,44 @@
<div class="panel panel-success">
<div class="panel-heading"><h3 class="panel-title">Receiver Ranking</h3></div>
<div class="panel-body">
<form>
<div class="well">
<select name="country" onchange="this.form.submit();">
<option value="">(all)</option>
{% for country in countries %}
<option value="{{ country.iso2 }}"{% if sel_country == country.iso2 %} SELECTED{% endif %}>{{ country.iso2 }}</option>
{% endfor %}
</select>
</div>
</form>
<table id="myTable" class="table table-striped table-bordered tablesorter tablesorter-bootstrap">
<tr>
<th>#</th>
<th>Country</th>
<th colspan="2">Ranking</th>
<th colspan="2">Receiver</th>
<th colspan="2">Maximum</th>
<th colspan="3">Counter</th>
</tr>
<tr>
<th class="text-right">Local</th>
<th class="text-right">Global</th>
<th>Name</th>
<th>Airport</th>
<th class="text-right">Maximum distance [km]</th>
<th class="text-right">Maximal normalized signal quality [dB]</th>
<th class="text-right">Sender counter</th>
<th class="text-right">Coverage counter</th>
<th class="text-right">Message counter</th>
<th class="text-right">Distance [km]</th>
<th class="text-right">Normalized signal quality [dB]</th>
<th class="text-right">Senders</th>
<th class="text-right">Coverages</th>
<th class="text-right">Messages</th>
</tr>
{% for entry in ranking %}
<tr>
<td>{{ loop.index }}</td>
<td><img src="{{ url_for('static', filename='img/Transparent.gif') }}" class="flag flag-{{ entry.receiver.country.iso2|lower }}" alt="{{ entry.receiver.country.iso2 }}"/></td>
<td>{{ entry.receiver|to_html_link|safe }}</a></td>
<td>{{ entry.receiver.airport|to_html_link|safe }}</a></td>
<td class="text-right">{{ entry.local_rank }}</td>
<td class="text-right">{{ entry.global_rank }}</td>
<td><img src="{{ url_for('static', filename='img/Transparent.gif') }}" class="flag flag-{{ entry.receiver.country.iso2|lower }}" alt="{{ entry.receiver.country.iso2 }}"/> {{ entry.receiver|to_html_link|safe }}</td>
<td>{{ entry.receiver.airport|to_html_link|safe }}</td>
<td class="text-right">{{ '%0.1f' | format(entry.max_distance/1000.0) }}</td>
<td class="text-right">{{ '%0.1f' | format(entry.max_normalized_quality) }}</td>
<td class="text-right">{{ entry.senders_count }}</td>

Wyświetl plik

@ -5,7 +5,7 @@
<link rel="stylesheet" href="{{ url_for('static', filename='css/flags/flags.css') }}"/>
<div class="container">
<div class="panel panel-success" id="asdf">
<div class="panel panel-success">
<div class="panel-heading"><h3 class="panel-title">Receivers</h3></div>
<div class="panel-body">

Wyświetl plik

@ -0,0 +1,57 @@
"""Add ReceiverRanking
Revision ID: 7f5b8f65a977
Revises: c53fdb39f5a5
Create Date: 2020-12-02 22:33:58.821112
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '7f5b8f65a977'
down_revision = 'c53fdb39f5a5'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('receiver_rankings',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('date', sa.Date(), nullable=True),
sa.Column('local_rank', sa.Integer(), nullable=True),
sa.Column('global_rank', sa.Integer(), nullable=True),
sa.Column('max_distance', sa.Float(precision=2), nullable=True),
sa.Column('max_normalized_quality', sa.Float(precision=2), nullable=True),
sa.Column('messages_count', sa.Integer(), nullable=True),
sa.Column('coverages_count', sa.Integer(), nullable=True),
sa.Column('senders_count', sa.Integer(), nullable=True),
sa.Column('receiver_id', sa.Integer(), nullable=True),
sa.Column('country_id', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['country_id'], ['countries.gid'], ondelete='CASCADE'),
sa.ForeignKeyConstraint(['receiver_id'], ['receivers.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_index('idx_receiver_rankings_uc', 'receiver_rankings', ['date', 'receiver_id'], unique=True)
op.create_index(op.f('ix_receiver_rankings_country_id'), 'receiver_rankings', ['country_id'], unique=False)
op.create_index(op.f('ix_receiver_rankings_receiver_id'), 'receiver_rankings', ['receiver_id'], unique=False)
op.drop_column('receiver_statuses', 'agl')
op.drop_column('receiver_statuses', 'location_mgrs')
op.drop_column('receiver_statuses', 'location_mgrs_short')
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('receiver_statuses', sa.Column('location_mgrs_short', sa.VARCHAR(length=9), autoincrement=False, nullable=True))
op.add_column('receiver_statuses', sa.Column('location_mgrs', sa.VARCHAR(length=15), autoincrement=False, nullable=True))
op.add_column('receiver_statuses', sa.Column('agl', sa.REAL(), autoincrement=False, nullable=True))
op.drop_index(op.f('ix_receiver_rankings_receiver_id'), table_name='receiver_rankings')
op.drop_index(op.f('ix_receiver_rankings_country_id'), table_name='receiver_rankings')
op.drop_index('idx_receiver_rankings_uc', table_name='receiver_rankings')
op.drop_table('receiver_rankings')
# ### end Alembic commands ###