At present, the global epidemic is still serious. In order to clearly see the changing trend of the global epidemic from the outbreak to the present, I have drawn a map of the epidemic change with 230 lines of complete code. If you need a friend, you can reply to the map by keyword on the official account. Without further ado, let’s start with the picture above

Let’s focus on the drawing process of the above picture, which is mainly divided into the following three steps:

  • The data collection

  • The data processing

  • drawing

Let’s take it one at a time. The data collection

This is the first step of the Great Wall, as the saying goes “even a clever housewife can not cook a meal without rice”, since it is the map of change, of course, need each country, daily number of existing confirmed cases. Fortunately, major websites now have special pages related to the epidemic, so we can directly capture the data. Take netease as an example

We choose XHR and refresh the page again to see several interfaces, among which the list-total interface is to obtain all the countries currently affected by the epidemic and the corresponding country ID. In addition, we see that there is a list-by-Area-code interface, which is to obtain the historical daily epidemic data of each country. The request for this interface requires the areaCode parameter, which is the country ID we just said. So these two interfaces are the most important ones for us. Let’s look at the code for requesting the list-total interface

def get_and_save_all_countries():
    """Get all country names and their ids and save them as files."""

    url = 'https://c.m.163.com/ug/api/wuhan/app/data/list-total?t=317452696323'
    list_total_req = requests.get(url, headers=headers)
    if list_total_req.status_code == 200:
        area_tree = list_total_req.json()['data'] ['areaTree']

        area_dict = {}
        for area in area_tree:
            country_id = area['id']
            name = area['name']
            area_dict[country_id] = name

        area_json = json.dumps(area_dict, ensure_ascii=False)  # ensure_ASCII =False prevents characters starting with \ U after JSON encoding
        write_file('./config/countries_id2name.json', area_json)Copy the code

Here the requested data is temporarily stored in a file. With the IDS of all affected countries, we can request the List-by-Area-code interface to get epidemic data for each country. The code is similar to the above, except that the result of the request is stored in mongodb instead of a file, for the purpose of easy to add, delete, change and check. Of course, for your convenience, I imported the mongodb data into the file counties_daily.json, which you can find in the source directory.

The data processing

The processing of this step is mainly to prepare for the drawing of the third step. Because we use pyecharts framework for drawing the map, the country names we need to input for drawing the world map are In English, but the country names we collect are in Chinese, so we need to match the Chinese country names to the English country names. The end result is as follows

You can find this online, but there are two problems you need to solve to make it work. First, the Chinese names on both sides should be unified. For example, the country name we collected is Central African Republic, but the corresponding relationship is Central African Republic, which still does not correspond. Second, we need to increase the mapping relationship by ourselves. The online mapping is generally not complete, so we need to increase it by ourselves according to the data collected. After the above two steps, we should be able to map most country names to English names that Pyechars can recognize. The relevant codes are as follows

def get_cy_properties():
    Get configuration file information
    countries_id2name = read_file('./config/countries_id2name.json')
    cy_id2name_dict = json.loads(countries_id2name)
    cy_ch2en = {v: k for k, v in countries_dict.items()}

    Change the country name to match the configuration file
    cy_id2name_dict['879'] = 'Bosnia and Herzegovina'
    cy_id2name_dict['8102'] = 'Togo'
    cy_id2name_dict['8143'] = 'Democratic Republic of Congo'
    cy_id2name_dict['95983'] = 'the'
    cy_id2name_dict['8144'] = 'Africa'
    cy_id2name_dict['95000011'] = dominica

    cy_props = {}
    for key in cy_id2name_dict:
        cy_name = cy_id2name_dict[key]
        if cy_name in cy_ch2en:
            cy_props[cy_name] = {}
            cy_props[cy_name]['id'] = key
            cy_props[cy_name]['en_name'] = cy_ch2en[cy_name]

    return cy_propsCopy the code

drawing

This step involves two core processes — constructing data structures and drawing diagrams. First, I constructed three data structures, date_list, cy_name_list, and nCOv_data. Date_list stores a list of dates, which takes a while because we’re drawing giFs; Cy_name_list holds a list of all countries in the collection (English names); Ncov_data is a dictionary where key is the date and value is an array of the number of confirmed cases in each country that day. The code to generate these three data structures is as follows

def parse_ncov_data(start_date, end_date, records):
    if not records:
        return

    date_list = get_date_range(start_date, end_date)
    cy_name_list = []
    res = {}
    # Capture current confirmed cases in each country on a daily basis
    for i, record in enumerate(records):
        cy_name = record['cy_en_name']
        cy_name_list.append(cy_name)

        # Analysing daily data and counting existing confirmed cases
        existing_case_dict = {}
        for ncov_daily in record['data'] ['list']:
            date_str = ncov_daily['date']
            confirm = ncov_daily['total'] ['confirm']  # Cumulative diagnosis
            heal = ncov_daily['total'] ['heal']  # Cumulative diagnosis
            dead = ncov_daily['total'] ['dead']  # Cumulative deaths

            existing_case = confirm - heal - dead
            existing_case_dict[date_str] = existing_case

        last_existing_case = 0
        # Merge the number of confirmed cases per day into the RES
        for date_str in date_list:
            if date_str not in res:  # initialization
                res[date_str] = []

            existing_case = existing_case_dict.get(date_str)
            if existing_case is None:
                existing_case = last_existing_case
            res[date_str].append(existing_case)

            last_existing_case = existing_case

    return date_list, cy_name_list, resCopy the code

The argument records is an array, each element of which represents a country, and the contents are the data we requested from the list-by-Area-code interface in the first step. Finally, use Pyecharts to draw and go directly to the code

def render_map(date_list, cy_name_list, ncov_data):
    tl = Timeline()  # Create a timeline rotation multi graph, you can make the graph according to the input time to move
    # is_auto_play: Auto play
    # play_interval: indicates the playback interval, in milliseconds
    # is_loop_play: Whether to loop
    tl.add_schema(is_auto_play=True, play_interval=50, is_loop_play=False)

    for date_str in date_list:  # List of iterations
        map0 = (
            Map()  # Create a map chart
            # Add country names cy_name_list and nCOv_data [date_str] of confirmed cases in each country that day
            .add("Global Epidemic Trends", [list(z) for z in zip(cy_name_list, ncov_data[date_str])], 
                "world", is_map_symbol_show=False)
            .set_series_opts(label_opts=opts.LabelOpts(is_show=False))  # do not display country name
            .set_global_opts(
                title_opts=opts.TitleOpts(title="% s day" % date_str),  # Chart title
                visualmap_opts=opts.VisualMapOpts(max_=80),   # When confirmed cases are greater than 80, the map color is red
            )
        )
        tl.add(map0, "%s" % date_str)  # Add the map status of the day to the timeline

    tl.render()  Render. HTML file is created in the current directoryCopy the code

The code is commented, so I won’t repeat it here. Running render_map will generate a render. HTML file in the current directory, which will automatically play the epidemic trend, such as the GIF at the beginning of this article. In addition, some friends may ask, can directly output GIF. This point I also tried, Baidu, Google, GitHub tutorial basically tried again, more regret did not find a reliable method. So advise you to give up this road, curve to save the country, record a video into GIF can be convenient and fast. After all, life is short, and the time saved by Python can’t be filled up with meaningless holes. So the whole process is introduced, although the idea is not complex, but the local details still need to spend some time processing. Complete code a total of 230 lines, need friends in the public number to reply to the keyword epidemic map can be.

There have been signs of a rebound in some parts of the country recently. I hope you will continue to be vigilant in both your work and life. Let’s hope this epidemic passes soon and wait for the day when the global map turns white.

Welcome the public account “du Code” to export the dry goods you can’t see elsewhere.