Grafik Covid-19 yang Benar

Di saat-saat obsesi yang meluas terhadap perpustakaan dan kerangka kerja web, kami mulai melupakan kegembiraan memecahkan masalah dengan cara yang minimal. Pada artikel ini, kami akan zapilit layanan web pada topik yang relevan menggunakan vanilla Python dan JavaScript, dan juga menginstalnya di Halaman GitLab . Cepat, minimalis, tanpa ketergantungan yang tidak perlu, dan seanggun mungkin.


Vidosy terinspirasi Bagaimana Mengenalinya Jika kita Pemukulan COVID - 19 dari minutephysics , saya membuat sketsa di (dari teleworking dan rumah urusan) layanan gratis waktu yang didasarkan pada data dari penyebaran Maps coronavirus di Rusia dan di dunia dari Yandex membangun grafik, mirip dengan yang di halaman Covid Trends . Inilah yang terjadi:



Menarik? Ayo pergi!


Di mana mendapatkan data?


Sekitar waktu ketika saya memiliki ide untuk mereproduksi grafik dari minutephysics untuk wilayah Rusia, Yandex menambahkan histogram untuk setiap wilayah ke peta.



, . - , , , , requests . , ( , , , ):


from urllib.request import urlopen
from html.parser import HTMLParser
import json

class Covid19DataLoader(HTMLParser):
    page_url = "https://yandex.ru/web-maps/covid19"

    def __init__(self):
        super().__init__()
        self.config_found = False
        self.config = None

    def load(self):
        with urlopen(self.page_url) as response:
            page = response.read().decode("utf8")
        self.feed(page)
        return self.config['covidData']

    def handle_starttag(self, tag, attrs):
        if tag == 'script':
            for k, v in attrs:
                if k == 'class' and v == 'config-view':
                    self.config_found = True

    def handle_data(self, data):
        if self.config_found and not self.config:
            self.config = json.loads(data)

?


, β€” HTML-, Chart.js. - , string.Template:


def get_html(covid_data):
    template_str = open(page_path, 'r', encoding='utf-8').read()
    template = Template(template_str)
    page = template.substitute(
        covid_data=json.dumps(covid_data),
        data_info=get_info(covid_data)
    )
    return page

page_path :


<!DOCTYPE html>
<html>
<head><!-- ... --></head>
    <body>
    <!-- ... -->
    <div>$data_info</div>
    <script type="text/javascript">
        let covid_data = $covid_data
        // ...
    </script>
</body>
</html>

! ! !


?


. Python:


from http.server import BaseHTTPRequestHandler
from lib.data_loader import Covid19DataLoader
from lib.page_maker import get_html

class Handler(BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/':
            self.send_response(200)
            self.send_header('Content-Type', 'text/html')
            self.end_headers()
            try:
                response = get_html(Covid19DataLoader().load())
                self.wfile.write(response.encode('utf-8'))
            except Exception as e:
                self.send_error(500)
                print(f'{type(e).__name__}: {e}')
        else:
            self.send_error(404)

, GitLab Pages, !


, , , .
: . (, cron). , !



Aatish Bhatia, Y , X β€” .


, 3 , . " ?" , , , - ( ) , !


from datetime import timedelta
from functools import reduce

y_axis_window = timedelta(days=3).total_seconds()

def get_cases_in_window(data, current_time):
    window_open_time = current_time - y_axis_window
    cases_in_window = list(filter(lambda s: window_open_time <= s['ts'] < current_time, data))
    return cases_in_window

def differentiate(data):
    result = [data[0]]
    for prev_i, cur_sample in enumerate(data[1:]):
        result.append({
            'ts': cur_sample['ts'],
            'value': cur_sample['value'] - data[prev_i]['value']
        })
    return result

def get_trend(histogram):
    trend = []
    new_cases = differentiate(histogram)
    for sample in histogram:
        current_time = sample['ts']
        total_cases = sample['value']
        new_cases_in_window = get_cases_in_window(new_cases, current_time)
        total_new_cases_in_window = reduce(lambda a, c: a + c['value'], new_cases_in_window, 0)
        trend.append({'x': total_cases,'y': total_new_cases_in_window})
    return trend

def get_trends(data_items):
    return { area['name']: get_trend(area['histogram']) for area in data_items }


, ( CSS Grid, ), . , - . .


?


Docker, , β€” VPS, docker-compose up --build -d, cron - ( , ?? , ...), , , http.server , . GitLab CI ssh ( ).


, , , .


GitLab Pages:


import os
from lib.data_loader import Covid19DataLoader
from lib.data_processor import get_trends
from lib.page_maker import get_html

page_dir = 'public'
page_name = 'index.html'

print('Updating Covid-19 data from Yandex...')
raw_data = Covid19DataLoader().load()
print('Calculating trends...')
trends = get_trends(raw_data['items'])
page = get_html({'raw_data': raw_data, 'trends': trends})

if not os.path.isdir(page_dir):
    os.mkdir(page_dir)
page_path = os.path.join(page_dir, page_name)
open(page_path, 'w', encoding='utf-8').write(page)
print(f'Page saved as "{page_path}"')

, https://himura.gitlab.io/covid19, .gitlab-ci.yml:


image: python
pages:
    stage: deploy
    only: [ master ]
    script:
        - python ./get_static_html.py
    artifacts:
      paths: [ public ]

Pipeline Schedules:



- :



β€” :



?


, GitLab: https://gitlab.com/himura/covid19


, , 2 . , - MVP, , - . , , β€” . known issues:


  • ( css grid )
  • ,

Saya harap artikel itu menarik dan / atau bermanfaat, dan saya juga sangat berharap bahwa segera kita semua akan melihat bagaimana garis-garis grafik menurun.
Jadilah sehat dan jangan menambahkan dependensi ke kode Anda yang dapat Anda lakukan tanpa!


All Articles