Skip to content

Commit

Permalink
Initial working version
Browse files Browse the repository at this point in the history
  • Loading branch information
LKMason committed May 1, 2024
1 parent 7e6b144 commit 1212536
Show file tree
Hide file tree
Showing 13 changed files with 1,498 additions and 0 deletions.
1 change: 1 addition & 0 deletions data/centroids.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions data/moran_us_cancer_mortality-2011-2020_county.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions data/us_counties.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
58 changes: 58 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>MoranPlot Dashboard</title>
<link rel="icon" href="icon.svg">
<link crossorigin="anonymous" type="text/css" rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.3.0/css/all.min.css" defer />
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-GLhlTQ8iRABdZLl6O3oVMWSktQOp6b7In1Zl3/Jr59b6EGGoI1aFkw7cmDA6j6gD" crossorigin="anonymous">
<link href="style.css" rel="stylesheet">
</head>

<body>
<header>
<div id="logo-container">
<i id="logo-icon" class="fas fa-globe-americas"></i>
<span id="logo-text">MoranPlot Dashboard</span>
</div>

<div id="links-container">
<a href="https://github.com/episphere/moranplot"><i class="fa-brands fa-github"></i> </a>
<!-- <i class="fa-brands fa-npm"></i> -->
<a href="https://arxiv.org/abs/2404.05897"><i class="fa-solid fa-scroll"></i></a>
<!-- <i class="fa-solid observable-logo"></i> -->
</div>
</header>

<div id="main-container">
<div id="dashboard">
<div id="left-container" class="base-card">
<div id="network-container"></div>
<div id="dual-container"></div>
</div>
<div id="map-container" class="base-card">
</div>

</div>

<!-- <div id="main-container">
<div id="test-dash">
<div id="left-container-test">
<div id="network-container-test"></div>
<div id="dual-container-test"></div>
</div>
<div id="map-container-test"></div>
</div>
</div> -->

<!-- <div id="container">
<div id="network-container"></div>
<div id="dual-container"></div>
<div id="map-container"></div>
</div> -->


<script src="src/dashboard.js" type="module"></script>
</html>
138 changes: 138 additions & 0 deletions src/ClusterMap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import * as Plot from 'https://cdn.jsdelivr.net/npm/@observablehq/[email protected]/+esm';
import * as d3 from 'https://cdn.jsdelivr.net/npm/[email protected]/+esm';

import { mergeOptions } from "./helper.js"

export class ClusterMap {
constructor(results, featureCollection, options={}) {
this.results = results
this.featureCollection = featureCollection
this.zExtent = d3.extent(results, d => d.z)

options = mergeOptions({
width: 640, height: 480,
style: { fontSize: "12px" },
colorMode: "label",
colors: {
highlight: "orange",
highHigh: "red",
highLow: "pink",
lowHigh: "lightblue",
lowLow: "blue",
notSignificant: "whitesmoke"
},
pointOpacity: 0.8,
hoverListener: d => d,
plotOptions: {
x: { axis: null}, y: { axis: null },
}
}, options)

Object.assign(this, options)

this.colorMap = new Map([
["High-high", this.colors.highHigh],
["High-low", this.colors.highLow],
["Low-high", this.colors.lowHigh],
["Low-low", this.colors.lowLow],
["Not significant", this.colors.notSignificant]
])

this.resultMap = d3.index(results, d => d.id)
if (!this.plotOptions.color) {
this.setColorMode(this.colorMode)
}

this.styleSheet = document.createElement("style")
this.styleSheet.innerText = `
.geo-path {
cursor: pointer;
}
`

this.plotContainer = document.createElement("div")
this.plotContainer.appendChild(this.styleSheet)
}

setColorMode(mode) {
this.mode = mode

if (mode == "value") {
this.plotOptions.color = {
scheme: "PRGn", pivot: d3.mean(results, d => d.value), legend: true
}
}
}

plot() {
let plot = null
if (this.colorMode == "value") {
plot = Plot.plot({
...this.plotOptions,
marks: [
Plot.geo(this.featureCollection, {
fill: d => this.resultMap.get(d.id)?.value,
}),
Plot.geo(this.featureCollection, {
stroke: d => this.colorMap.get(this.resultMap.get(d.id)?.label),
strokeWidth: 1,
})
]
})
} else if (this.colorMode == "label") {
plot = Plot.plot({
...this.plotOptions,
width: this.width,
marks: [
Plot.geo(this.featureCollection, {
fill: d => this.colorMap.get(this.resultMap.get(d.id)?.label),
stroke: "lightgrey", strokeOpacity: .5,
}),
]
})
}

this.geoPaths = d3.select(plot)
.select("g[aria-label='geo']")
.selectAll("path")
.attr("class", "geo-path")

this.geoPaths.on("mouseover", (e,i) => {
const feature = this.featureCollection.features[i]
const result = this.resultMap.get(feature.id)
this.#focus(result.id, d3.select(e.target))
if (this.hoverListener) this.hoverListener(result, e)
})

this.geoPaths.on("mouseleave", () => {
this.hoverListener(null)
this.#focus(null, d3.select())
})

this.plotContainer.innerHTML = ''
this.plotContainer.appendChild(this.styleSheet)
this.plotContainer.appendChild(plot)
return this.plotContainer
}

focus(id) {
const select = id ? this.geoPaths.filter(d => this.featureCollection.features[d]?.id == id) : d3.select()
this.#focus(id, select)
}

#focus(id, elemSelect) {
if (this.prevElemSelect) {
this.prevElemSelect.attr("stroke", "lightgrey")
.attr("stroke-width", 1)
}

elemSelect.attr("stroke", this.colors.highlight)
.attr("stroke-width", 3)
elemSelect.raise()
this.prevElemSelect = elemSelect
}

onHover(listener) {
this.hoverListener = listener
}
}
Loading

0 comments on commit 1212536

Please sign in to comment.