Interactive Custom CORD-19

Demonstrating interactive plotting and what can be achieved with the extra options available via custom_html, custom_css and custom_js to construct a clickable legend for selecting subsets of data based on the field of research (click on the colour swatches in the legend to select a specific field).

For a full size version see https://lmcinnes.github.io/datamapplot_examples/CORD19_customised_example.html



import numpy as np
import pandas as pd
import seaborn as sns
from matplotlib.colors import rgb2hex

import datamapplot

cord19_data_map = np.load("cord19_umap_vectors.npz")["arr_0"]
cord19_label_layers = []
for i in range(6):
    cord19_label_layers.append(
        np.load(f"cord19_layer{i}_cluster_labels.npz", allow_pickle=True)["arr_0"]
    )
cord19_hover_text = np.load("cord19_large_hover_text.npz", allow_pickle=True)["arr_0"]

color_mapping = {}
color_mapping["Medicine"] = "#bbbbbb"
for key, color in zip(("Biology", "Chemistry", "Physics"), sns.color_palette("YlOrRd_r", 3)):
    color_mapping[key] = rgb2hex(color)
for key, color in zip(("Business", "Economics", "Political Science"), sns.color_palette("BuPu_r", 3)):
    color_mapping[key] = rgb2hex(color)
for key, color in zip(("Psychology", "Sociology", "Geography", "History"), sns.color_palette("YlGnBu_r", 4)):
    color_mapping[key] = rgb2hex(color)
for key, color in zip(("Computer Science", "Engineering", "Mathematics"), sns.color_palette("light:teal_r", 4)[:-1]):
    color_mapping[key] = rgb2hex(color)
for key, color in zip(("Environmental Science", "Geology", "Materials Science"), sns.color_palette("pink", 3), ):
    color_mapping[key] = rgb2hex(color)
for key, color in zip(("Art", "Philosophy", "Unknown"), sns.color_palette("bone", 3)):
    color_mapping[key] = rgb2hex(color)

cord19_extra_data = pd.read_feather("cord19_extra_data.arrow")
cord19_extra_data["color"] = cord19_extra_data.primary_field.map(color_mapping)
marker_color_array = cord19_extra_data.primary_field.map(color_mapping)
marker_size_array = np.log(1 + cord19_extra_data.citation_count.values)

# Add custom CSS to style the legend element we will add to the plot
custom_css = """
.row {
    display : flex;
    align-items : center;
}
.box {
    height:10px;
    width:10px;
    border-radius:2px;
    margin-right:5px;
    padding:0px 0 1px 0;
    text-align:center;
    color: white;
    font-size: 14px;
}
#legend {
    position: absolute;
    top: 0;
    right: 0;
}
#title-container {
    max-width: 75%;
}
"""
# Construct HTML for the legend
custom_html = """
<div id="legend" class="container-box">
"""
for field, color in color_mapping.items():
    custom_html += f'    <div class="row"><div id="{field}" class="box" style="background-color:{color};"></div>{field}</div>\n'
custom_html += "</div>\n"

# Create a custom tooltip, highlighting the field of research and citation count
badge_css = """
    border-radius:6px;
    width:fit-content;
    max-width:75%;
    margin:2px;
    padding: 2px 10px 2px 10px;
    font-size: 10pt;
"""
hover_text_template = f"""
<div>
    <div style="font-size:12pt;padding:2px;">{{hover_text}}</div>
    <div style="background-color:{{color}};color:#fff;{badge_css}">{{primary_field}}</div>
    <div style="background-color:#eeeeeeff;{badge_css}">citation count: {{citation_count}}</div>
</div>
"""

# Add custom javascript to make the legend interactive/clickable,
# and interact with search selection
custom_js = """
const legend = document.getElementById("legend");
const selectedPrimaryFields = new Set();

legend.addEventListener('click', function (event) {
    const selectedField = event.srcElement.id;

    if (selectedField) {
        if (selectedPrimaryFields.has(selectedField)) {
            selectedPrimaryFields.delete(selectedField);
            event.srcElement.innerHTML = "";
        } else {
            selectedPrimaryFields.add(selectedField);
            event.srcElement.innerHTML = "✓";
        }
    }
    const selectedIndices = [];
    datamap.metaData.primary_field.forEach((field, i) => {
        if (selectedPrimaryFields.has(field)) {
            selectedIndices.push(i);
        }
    });
    datamap.addSelection(selectedIndices, "legend");
});
"""

plot = datamapplot.create_interactive_plot(
    cord19_data_map,
    cord19_label_layers[0],
    cord19_label_layers[1],
    cord19_label_layers[2],
    cord19_label_layers[3],
    cord19_label_layers[4],
    cord19_label_layers[5],
    hover_text=cord19_hover_text,
    initial_zoom_fraction=0.99,
    title="CORD-19 Data Map",
    sub_title="A data map of papers relating to COVID-19",
    font_family="Cinzel",
    logo="https://allenai.org/newsletters/archive/2023-03-newsletter_files/927c3ca8-6c75-862c-ee5d-81703ef10a8d.png",
    logo_width=128,
    color_label_text=False,
    marker_size_array=marker_size_array,
    marker_color_array=marker_color_array,
    point_radius_max_pixels=16,
    text_outline_width=4,
    text_min_pixel_size=16,
    text_max_pixel_size=48,
    min_fontsize=16,
    max_fontsize=32,
    noise_color="#aaaaaa44",
    cluster_boundary_polygons=True,
    color_cluster_boundaries=False,
    extra_point_data=cord19_extra_data,
    hover_text_html_template=hover_text_template,
    on_click="window.open(`http://google.com/search?q=\"{hover_text}\"`)",
    enable_search=True,
    custom_css=custom_css,
    custom_html=custom_html,
    custom_js=custom_js,
    inline_data=False,
    offline_data_prefix="custom_cord_gallery",
)
plot

Total running time of the script: (0 minutes 28.774 seconds)

Gallery generated by Sphinx-Gallery