Skip to content

Commit

Permalink
File prefixed for external data; new examples.
Browse files Browse the repository at this point in the history
  • Loading branch information
lmcinnes committed Feb 17, 2024
1 parent 87bf5c0 commit 8de8638
Show file tree
Hide file tree
Showing 5 changed files with 236 additions and 7 deletions.
23 changes: 16 additions & 7 deletions datamapplot/interactive_rendering.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,10 +193,10 @@
const unzippedLabelData = fflate.gunzipSync(labelDataBuffer);
const labelData = await loaders.parse(unzippedLabelData, JSONLoader);
{% else %}
const pointData = await loaders.load("point_df.arrow", ArrowLoader);
const unzippedHoverData = await loaders.load("point_hover_data.zip", ZipLoader);
const pointData = await loaders.load("{{file_prefix}}_point_df.arrow", ArrowLoader);
const unzippedHoverData = await loaders.load("{{file_prefix}}_point_hover_data.zip", ZipLoader);
const hoverData = await loaders.parse(unzippedHoverData["point_hover_data.arrow"], ArrowLoader);
const unzippedLabelData = await loaders.load("label_data.zip", ZipLoader);
const unzippedLabelData = await loaders.load("{{file_prefix}}_label_data.zip", ZipLoader);
const labelData = await loaders.parse(unzippedLabelData["label_data.json"], JSONLoader);
{% endif %}
Expand Down Expand Up @@ -518,6 +518,7 @@ def render_html(
initial_zoom_fraction=1.0,
background_color=None,
darkmode=False,
offline_data_prefix=None,
tooltip_css=None,
hover_text_html_template=None,
extra_point_data=None,
Expand Down Expand Up @@ -658,9 +659,14 @@ def render_html(
darkmode: bool (optional, default=False)
Whether to use darkmode.
offline_data_prefix: str or None (optional, default=None)
If ``inline_data=False`` a number of data files will be created storing data for
the plot and referenced by the HTML file produced. If not none then this will provide
a prefix on the filename of all the files created.
tooltip_css: str or None (optional, default=None)
Custom CSS used to fine the properties of the tooltip. If ``None`` a default
CSS style will be used. This should simply the the required CSS directives
CSS style will be used. This should simply be the required CSS directives
specific to the tooltip.
hover_text_html_template: str or None (optional, default=None)
Expand Down Expand Up @@ -833,14 +839,16 @@ def render_html(
label_data_json = label_dataframe.to_json(orient="records")
gzipped_label_data = gzip.compress(bytes(label_data_json, "utf-8"))
base64_label_data = base64.b64encode(gzipped_label_data).decode()
file_prefix = None
else:
base64_point_data = ""
base64_hover_data = ""
base64_label_data = ""
point_data.to_feather("point_df.arrow", compression="uncompressed")
file_prefix = offline_data_prefix if offline_data_prefix is not None else "datamapplot"
point_data.to_feather(f"{file_prefix}_point_df.arrow", compression="uncompressed")
hover_data.to_feather("point_hover_data.arrow", compression="uncompressed")
with zipfile.ZipFile(
"point_hover_data.zip",
f"{file_prefix}_point_hover_data.zip",
"w",
compression=zipfile.ZIP_DEFLATED,
compresslevel=9,
Expand All @@ -849,7 +857,7 @@ def render_html(
os.remove("point_hover_data.arrow")
label_dataframe.to_json("label_data.json", orient="records")
with zipfile.ZipFile(
"label_data.zip", "w", compression=zipfile.ZIP_DEFLATED, compresslevel=9
f"{file_prefix}_label_data.zip", "w", compression=zipfile.ZIP_DEFLATED, compresslevel=9
) as f:
f.write("label_data.json")
os.remove("label_data.json")
Expand Down Expand Up @@ -906,6 +914,7 @@ def render_html(
base64_point_data=base64_point_data,
base64_hover_data=base64_hover_data,
base64_label_data=base64_label_data,
file_prefix=file_prefix,
point_size=point_size,
point_outline_color=point_outline_color,
point_line_width=point_line_width,
Expand Down
Binary file added examples/cord19_extra_data.arrow
Binary file not shown.
Binary file added examples/cord19_marker_size_array.npy
Binary file not shown.
51 changes: 51 additions & 0 deletions examples/plot_interactive_cord19.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"""
Interactive CORD-19
-------------------
Demonstrating interactive plotting with colormaps and search with the CORD-19 large data map.
For a full size version see
https://lmcinnes.github.io/datamapplot_examples/CORD19_data_map_example.html
"""
import numpy as np
import bz2
import datamapplot
import colorcet

cord19_data_map = np.load("cord19_umap_vectors.npy")
cord19_label_layers = []
for i in range(6):
cord19_label_layers.append(
np.load(f"cord19_layer{i}_cluster_labels.npy", allow_pickle=True)
)
cord19_hover_text = [
x.decode("utf-8").strip()
for x in bz2.open(
"cord19_large_hover_text.txt.bz2",
mode="r"
)
]
cord19_marker_size_array = np.log(1+np.load("cord19_marker_size_array.npy"))

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.4,
title="CORD-19 Data Map",
sub_title="A data map of papers relating to COVID-19 and SARS-CoV-2",
font_family="Cinzel",
logo="https://allenai.org/newsletters/archive/2023-03-newsletter_files/927c3ca8-6c75-862c-ee5d-81703ef10a8d.png",
logo_width=128,
marker_size_array=cord19_marker_size_array,
cmap=colorcet.cm.CET_C2s,
noise_color="#aaaaaa66",
cluster_boundary_polygons=True,
enable_search=True,
)
plot
169 changes: 169 additions & 0 deletions examples/plot_interactive_custom_cord19.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
"""
Interactive 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 bz2
import seaborn as sns
from matplotlib.colors import rgb2hex

import datamapplot

cord19_data_map = np.load("cord19_umap_vectors.npy")
cord19_label_layers = []
for i in range(6):
cord19_label_layers.append(
np.load(f"cord19_layer{i}_cluster_labels.npy", allow_pickle=True)
)
cord19_hover_text = [
x.decode("utf-8").strip()
for x in bz2.open(
"cord19_large_hover_text.txt.bz2",
mode="r"
)
]

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;
}
#legend {
position: absolute;
top: 0;
right: 0;
margin: 16px;
padding: 12px;
border-radius: 16px;
z-index: 2;
background: #ffffffcc;
font-family: Cinzel;
font-size: 8pt;
box-shadow: 2px 3px 10px #aaaaaa44;
}
#title-container {
max-width: 75%;
}
"""
# Construct HTML for the legend
custom_html = """
<div id="legend">
"""
for field, color in color_mapping.items():
custom_html += f' <div class="row"><div id="{field}" class="box" style="background-color:{color};padding:0px 0 1px 0;text-align:center"></div>{field}</div>\n'
custom_html += """
</div>
"""

# 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');
legend.addEventListener('click', function (event) {
const primary_field = event.srcElement.id;
selectPoints(primary_field, (i) => (hoverData.data.primary_field[i] == primary_field));
for (const row of legend.children) {
for (const item of row.children) {
if (item.id == primary_field) {
item.innerHTML = "✓";
} else {
item.innerHTML = "";
}
}
}
search.value = "";
});
search.addEventListener("input", (event) => {
for (const row of legend.children) {
for (const item of row.children) {
item.innerHTML = "";
}
}
});
"""

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.4,
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,
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,
)
plot

0 comments on commit 8de8638

Please sign in to comment.