Skip to content

Commit

Permalink
Add GitHub Page (#16)
Browse files Browse the repository at this point in the history
* add jekyll/pages code from benchmarking, update isdir path

* copy over layouts

* update replace for new paths

* update fetch location
  • Loading branch information
ntBre authored Nov 22, 2024
1 parent 50cd05c commit b933892
Show file tree
Hide file tree
Showing 4 changed files with 377 additions and 0 deletions.
63 changes: 63 additions & 0 deletions _config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Welcome to Jekyll!
#
# This config file is meant for settings that affect your whole blog, values
# which you are expected to set up once and rarely edit after that. If you find
# yourself editing this file very often, consider using Jekyll's data files
# feature for the data you need to update frequently.
#
# For technical reasons, this file is *NOT* reloaded automatically when you use
# 'bundle exec jekyll serve'. If you change this file, please restart the server process.
#
# If you need help with YAML syntax, here are some quick references for you:
# https://learn-the-web.algonquindesign.ca/topics/markdown-yaml-cheat-sheet/#yaml
# https://learnxinyminutes.com/docs/yaml/
#
# Site settings
# These are used to personalize your new site. If you look in the HTML files,
# you will see them accessed via {{ site.title }}, {{ site.email }}, and so on.
# You can create any custom variable you would like, and they will be accessible
# in the templates via {{ site.myvariable }}.

title: Your awesome title
email: [email protected]
description: >- # this means to ignore newlines until "baseurl:"
Write an awesome description for your new site here. You can edit this
line in _config.yml. It will appear in your document head meta (for
Google search results) and in your feed.xml site description.
baseurl: "" # the subpath of your site, e.g. /blog
url: "" # the base hostname & protocol for your site, e.g. http://example.com
twitter_username: jekyllrb
github_username: jekyll

# Build settings
theme: minima
plugins:
- jekyll-feed

github: [metadata]

defaults:
- scope:
path: "submissions/*/output"
values:
isdir: true

# Exclude from processing.
# The following items will not be processed, by default.
# Any item listed under the `exclude:` key here will be automatically added to
# the internal "default list".
#
# Excluded items can be processed by explicitly listing the directories or
# their entries' file path in the `include:` list.
#
# exclude:
# - .sass-cache/
# - .jekyll-cache/
# - gemfiles/
# - Gemfile
# - Gemfile.lock
# - node_modules/
# - vendor/bundle/
# - vendor/cache/
# - vendor/gems/
# - vendor/ruby/
14 changes: 14 additions & 0 deletions _layouts/basic.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">

<script src="plotly-2.35.2.min.js" charset="utf-8"></script>

<title>benchmarking</title>
</head>
<body>
{{ content }}
</body>
</html>
292 changes: 292 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,292 @@
---
layout: basic
---
{% assign static_files = site.static_files | where: "isdir", true %}

<style>
.plot {
max-width: 50%;
display: inline-block;
}
</style>

<div id="plot-area">
<div class="plot" id="dde"></div>
<div class="plot" id="rmsd"></div>
<div class="plot" id="tfd"></div>
<div class="plot" id="bonds"></div>
<div class="plot" id="angles"></div>
<div class="plot" id="dihedrals"></div>
<div class="plot" id="impropers"></div>
</div>

<h2>Available datasets</h2>
<div id="app"></div>

<script>
// fetch `filename` and return its contents as a string
async function fetchCsv(filename) {
let res = await fetch(filename);
if (!res.ok) {
console.log(`failed to retrieve ${filename}`);
return null;
}
let text = await res.text();
return text;
}

async function fetchData(dir) {
// includes trailing slash so don't add another
let base = `${window.location.pathname}submissions/${dir}/output`
let dde = await fetchCsv(`${base}/dde.csv`);
let rmsd = await fetchCsv(`${base}/rmsd.csv`);
let tfd = await fetchCsv(`${base}/tfd.csv`);
let icrmsd = await fetchCsv(`${base}/icrmsd.csv`);
return [dde, rmsd, tfd, icrmsd];
}

// just returns the data for now, might need the record IDs eventually
function parse_csv(str) {
let lines = str.split(/\n/);
let ret = [];
for (const [i, line] of lines.entries()) {
if (i == 0) { continue } // skip header
let [rec_id, val] = line.split(',');
if (val) { // skip empty lines
ret.push(parseFloat(val));
}
}
return ret;
}

function parse_icrmsd_csv(str) {
let lines = str.split(/\n/);
let bonds = [];
let angles = [];
let dihedrals = [];
let impropers = [];
for (const [i, line] of lines.entries()) {
if (i == 0) { continue } // skip header
let [rec_id, bond, angle, dihedral, improper] = line.split(',');
if (bond) { // skip empty lines
bonds.push(parseFloat(bond));
angles.push(parseFloat(angle));
dihedrals.push(parseFloat(dihedral));
impropers.push(parseFloat(improper));
}
}

return [bonds, angles, dihedrals, impropers];
}

// these are supposedly the default plotly colors from
// https://stackoverflow.com/a/69355251/12935407
let colors = [
"#1f77b4",
"#ff7f0e",
"#2ca02c",
"#d62728",
"#9467bd",
"#8c564b",
"#e377c2",
"#7f7f7f",
"#bcbd22",
"#17becf",
];

async function handleClick(self) {
// this gives the directory name, eg 2.2-split-v1, and the current checked
// status of its checkbox
console.log(self.name, self.checked);
selected.set(self.name, self.checked);

let ddes = [];
let rmsds = [];
let tfds = [];
// icrmsds
let bonds = [];
let angles = [];
let dihedrals = [];
let impropers = [];
for ([name, checked] of selected) {
if (checked) {
let color = colors[ddes.length % colors.length];
let [dde, rmsd, tfd, icrmsd] = await fetchData(name);

if (dde) {
let dde_vals = parse_csv(dde);
ddes.push({
x: dde_vals,
nbinsx: 30,
xbins: { size: 30 / 16 },
marker: {
color: "transparent",
line: {
color: color,
width: 2
}
},
type: "histogram",
bingroup: '1',
name: name,
});
}

if (rmsd) {
let rmsd_vals = parse_csv(rmsd);
let [rx, ry] = ecdf(rmsd_vals);
rmsds.push({
x: rx,
y: ry,
mode: "lines",
name: name,
line: {
color: color,
}
});
}

if (tfd) {
let tfd_vals = parse_csv(tfd);
let [tx, ty] = ecdf(tfd_vals);
tfds.push({
x: tx,
y: ty,
mode: "lines",
name: name,
line: {
color: color,
}
});
}

// this field could be missing for old force fields
if (icrmsd) {
let [b, a, d, i] = parse_icrmsd_csv(icrmsd);
bonds.push({
x: name,
y: b,
type: 'box',
marker: {color: color},
xaxis: "x1",
yaxis: "y1",
name: name,
});
angles.push({
x: name,
y: a,
type: 'box',
marker: {color: color},
xaxis: "x2",
yaxis: "y2",
name: name,
});
dihedrals.push({
x: name,
y: d,
type: 'box',
marker: {color: color},
xaxis: "x3",
yaxis: "y3",
name: name,
});
impropers.push({
x: name,
y: i,
type: 'box',
marker: {color: color},
xaxis: "x4",
yaxis: "y4",
name: name,
});
}

// TODO assemble a data Array like in the dummy icrmsd below
}
}
if (ddes.length > 0) {
Plotly.newPlot( dde, ddes, dde_layout );
}
if (rmsds.length > 0) {
Plotly.newPlot( rmsd, rmsds, rmsd_layout );
}
if (tfds.length > 0) {
Plotly.newPlot( tfd, tfds, tfd_layout );
}
if (bonds.length > 0) {
Plotly.newPlot(BONDS, bonds, {title: "Bonds"});
}
if (angles.length > 0) {
Plotly.newPlot(ANGLES, angles, {title: "Angles"});
}
if (dihedrals.length > 0) {
Plotly.newPlot(DIHEDRALS, dihedrals, {title: "Dihedrals"});
}
if (impropers.length > 0) {
Plotly.newPlot(IMPROPERS, impropers, {title: "Impropers"});
}
}

// an ecdf is just the fraction of entries less than a given x value
function ecdf(x) {
let sx = x.toSorted((a, b) => a - b);
return [sx, sx.map((_elt, idx) => (idx + 1) / sx.length)];
}

// initialize empty plots
let dde = document.getElementById("dde");
let dde_layout = {
title: "DDE",
xaxis: { range: [-15, 15] },
barmode: "overlay"
};
Plotly.newPlot( dde, [{x: [], y: [] }], dde_layout );

let rmsd = document.getElementById("rmsd");
let rmsd_layout = {title: "RMSD"};
Plotly.newPlot( rmsd, [{x: [], y: [] }], rmsd_layout );

let tfd = document.getElementById("tfd");
let tfd_layout = {title: "TFD"};
Plotly.newPlot( tfd, [{x: [], y: [] }], tfd_layout );

let BONDS = document.getElementById("bonds");
let ANGLES = document.getElementById("angles");
let DIHEDRALS = document.getElementById("dihedrals");
let IMPROPERS = document.getElementById("impropers");
Plotly.newPlot(BONDS, [{x: [], y: [] }], {title: "Bonds"});
Plotly.newPlot(ANGLES, [{x: [], y: [] }], {title: "Angles"});
Plotly.newPlot(DIHEDRALS, [{x: [], y: [] }], {title: "Dihedrals"});
Plotly.newPlot(IMPROPERS, [{x: [], y: [] }], {title: "Impropers"});

const PAGES = [
{% for page in static_files %}
"{{ page.path }}",
{% endfor %}
];
let dirs = PAGES.map((x) => x.replace(/\/submissions\/([^/]+)\/.*$/, '$1'));
let unique_dirs = [...new Set(dirs)];
const selected = new Map();
for (dir of unique_dirs) {
selected.set(dir, false); // initially nothing is selected
}
let parent = document.getElementById("app");
for (dir of unique_dirs) {
let input = document.createElement("input");
input.type = "checkbox";
input.id = dir;
input.name = dir;
input.innerHTML = dir;
input.setAttribute("onclick", "handleClick(this)");

let label = document.createElement("label");
label.innerHTML = dir;
label.for = dir;

let br = document.createElement("br");

parent.appendChild(input);
parent.appendChild(label);
parent.appendChild(br);
}
</script>
8 changes: 8 additions & 0 deletions plotly-2.35.2.min.js

Large diffs are not rendered by default.

0 comments on commit b933892

Please sign in to comment.