Skip to content

Commit

Permalink
v3.0.0-alpha.0 (#119)
Browse files Browse the repository at this point in the history
* Convert pre-compiled model structures to `model` class

* Rebuild code

* Replace var with let

* Add plotting with plotly for NodeJS (not for HTML)

* Fix plotting with `com` module and rebuild code

* Add plotting in the Web

* Fix tests for plotly

* [Deprecation] Deprecate `com` module (#118)

* Rebuild code

* Add documentation

* Update documentation

* Version Bump and Docs Rebuild

* Apply suggestions from code review

Co-authored-by: q9i <46249765+quantum9Innovation@users.noreply.github.com>

* Remove unnecassary variable and rebuild code

Co-authored-by: q9i <46249765+quantum9Innovation@users.noreply.github.com>
  • Loading branch information
Quantalabs and quantum9Innovation authored Jan 7, 2022
1 parent 0a200ad commit 6117e2b
Show file tree
Hide file tree
Showing 65 changed files with 906 additions and 1,774 deletions.
409 changes: 0 additions & 409 deletions EpiJS/com.js

This file was deleted.

109 changes: 57 additions & 52 deletions EpiJS/comp.js

Large diffs are not rendered by default.

2 changes: 0 additions & 2 deletions EpiJS/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
const pre = require('./pre')
const com = require('./com')
const comp = require('./comp')
const model = require('./model')
const package = require('../package.json');
Expand All @@ -13,7 +12,6 @@ let description = package.description;
exports.pre = pre;
exports.about = 'EpiJS \n'+description+'\n----------------------------------\n By @epispot \n GitHub - https://github.com/epispot/EpiJS \n Version - '+ version;
exports.version = version;
exports.com = com;
exports.comp = comp;
exports.model = model;
exports.utils = utils;
Expand Down
26 changes: 13 additions & 13 deletions EpiJS/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,17 +63,17 @@ class Model {
*model.get_data(100) // Get data for 100 days.
*/
get_data(time) { // skipcq: JS-0045
var key = {}
var newkey = {}
let key = {}
let newkey = {}

// For key in this.key, add it to newkey and key.
for (var key_key in this.key) {
for (let key_key in this.key) {
key[key_key] = this.key[key_key]
newkey[key_key] = this.key[key_key]
}

for (var x = 0; x < time; x++) {
var y; // skipcq: JS-0119
for (let x = 0; x < time; x++) {
let y; // skipcq: JS-0119
for (y in this.compartments) {
newkey[this.compartments[y][1]] = this.compartments[y][0].get_data(key)
}
Expand All @@ -88,7 +88,7 @@ class Model {
"population": key[this.compartments[y][1]],
"compartments": {}
}
for (var z in this.compartments[y][0].compartments) {
for (let z in this.compartments[y][0].compartments) {
return_val[this.compartments[y][1]].compartments[z] = this.compartments[y][0].getSubData(z, key)
}
}
Expand Down Expand Up @@ -121,7 +121,7 @@ class Model {
* sirm.remove(recovered) // Removes the recovered compartment.
*/
remove(compartment) {
for (var x = 0; x < this.compartments.length; x++) {
for (let x = 0; x < this.compartments.length; x++) {
if (this.compartments[x][0] === compartment) {
this.compartments.splice(x, 1)
}
Expand Down Expand Up @@ -182,13 +182,13 @@ class Model {
*mexport(sirm, "output.js", file_type=".js")
*/
function mexport(model, output, file_type=".json") {
var jsonout = {
let jsonout = {
"compartments": {

},
"key": model.key
}
for (var x in model.compartments) {
for (let x in model.compartments) {
if (model.compartments[x][0].compartments === {}) {
delete model.compartments[x][0].compartments
}
Expand All @@ -213,14 +213,14 @@ function mexport(model, output, file_type=".json") {
*/
function mimport(input, file_type=".json") {
if (file_type === ".json") {
var json = JSON.parse(fs.readFileSync(input))
let json = JSON.parse(fs.readFileSync(input))
} else if (file_type === ".js") {
var json = require(output)
let json = require(output)
}

var comp = []
let comp = []

for (var x in json.compartments) {
for (let x in json.compartments) {
// If compartments key does not exist in json.compartments[x], then add it
if (!Object.prototype.hasOwnProperty.call(json.compartments[x],"compartments")) {
json.compartments[x].compartments = {}
Expand Down
185 changes: 101 additions & 84 deletions EpiJS/plots.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,102 +7,119 @@
* ```
*/


const chart = require('chart.js') // skipcq: JS-0502
const http = require('http')
const Plotly = require('plotly.js-dist-min')

/**
* Plots a output of a model from the pre module.
* @param {Array} model - The output from the pre module function.
* @param {HTMLCanvasElement} canvas - The canvas to show the output.
* @param {Number} days - The amount of days to plot
* @param {Array} colors - Custom colors for the graph, in the same order the compartments are.
* @param {Object} options - Optional. Custom configuration to pass into the options parameter for chart.js, defaults to:
*
* ```JSON
* {
* title: {
* display: true,
* text: "Total Cases"
* },
* scales: {
* yAxes: [{
* ticks: {
* beginAtZero: true
* }
* }]
* }
* }
* ```
*
* @returns Returns the chart.js chart, if needed for modification.
*
* Plots models from pre or model modules. If in Node, this will generate a localhost, otherwise it will plot it in the HTML div element provided.
* @param {Object} model A model class from the pre or model modules.
* @param {Number} time The number of days to plot.
* @param {String} name The ID of the plot. If this is in HTML, it will be the ID of the div element for the graph.
* @param {String} title The title of the graph.
* @example
*
* let sirout1 = sir(4, 9999, 1000, 100, 1/21, 10999, true)
* let susceptible = new Idiom("S-(B*S*I/p)");
* let infected = new Idiom("I+(B*S*I/p)-(u*I)");
* let recovered = new Idiom("R+(u*I)");
*
* let key = {
* "S": 10000,
* "B": 0.3,
* "I": 100,
* "R": 0,
* "p": 10100,
* "u": 0.2
* };
*
* plot(sirout1, "canvas-pre1", 100) // Plots data for 100 days onto the canvas-pre1 chart, with the data from the SIR model.
* let sirm = new Model([[susceptible2, "S"], [infected2, "I"], [recovered2, "R"]], key)
*
* plot(sirout1, 100, "SIR", "SIR Model (Population vs. Time)")
*/
function plot(model, canvas, days, colors=null, options={title: {display: true, text: 'Total Cases'}, scales: {yAxes: [{ticks: {beginAtZero: true}}]}}) {
let data = {// skipcq: JS-0502
labels: [],
datasets: []
}
for (let i = 0; i < days; i++) {// skipcq: JS-0502
data.labels.push('Day '+i)
}
if (colors !== null) {
for (let i = 0; i < model.length; i++) {// skipcq: JS-0502
data.datasets.push({
label: model[i].name,
data: model[i].data,
borderColor: colors[i]
})
}
function plot(model, time, name, title='Cases vs. Time') {
// Get model data for every day up to and including `time`
let data = {
xvals: [],
yvals: {}
}
else {
for (let i = 0; i < model.length; i++) {// skipcq: JS-0502
data.datasets.push({
label: model[i].label,
data: model[i].data,
borderColor: '#'+Math.floor(Math.random()*16777215).toString(16)
})
}

for (let x in model.compartments) {
data.yvals[model.compartments[x][1]] = []
}

let sirChart = new Chart(canvas, {// skipcq: JS-0502
type: 'line',
data: data,
options: options
});
return sirChart;
}
// For every day until `time`, get the data
for (let x = 0; x < time; x++) {
let current = model.get_data(x+1)

/**
* Manipulate the chart.js graph
*
* @param id The chart.js graph
* @param {String} mvalue The value to manipulate in `chart.data.datasets[x]`. This can be any valid chart.js parameter. See https://www.chartjs.org/docs/latest/charts/line.html#line-styling
* @param value The value to insert into the graph
* @returns The chart.js graph
*
* @example
*
* let sirout1 = sir(4, 9999, 1000, 100, 1/21, 10999, true)
*
* let sirplot = plot(sirout1, "canvas-pre1", 100)
*
* sirplot.manipulate(sirplot, "fill", true) // Set fill to true
*/
function manipulate(id, mvalue, value) {
var manip = Chart.getChart(id)// skipcq: JS-0502
// For every compartment, get the data
for (let y in model.compartments) {
// If the compartment data is an object, get .population
if (typeof current[model.compartments[y][1]] === 'object') {
data.yvals[model.compartments[y][1]].push(current[model.compartments[y][1]].population)
} else {
data.yvals[model.compartments[y][1]].push(current[model.compartments[y][1]])
}
}
data.xvals.push(x+1)
}

for (var x in manip.data.datasets) {
manip.data.datasets[x][mvalue] = value
// Create the plot
let plotlyData = []
for (let x in data.yvals) {
plotlyData.push({
x: data.xvals,
y: data.yvals[x],
name: x,
mode: 'lines'
})
}

manip.update()
return manip
if (typeof process === 'object' && String(process) === '[object process]') { // Is running in NodeJS
// Create http server
let server = http.createServer((req, res) => {
// Send the plot as HTML
res.writeHead(200, {'Content-Type': 'text/html'})
res.write(`<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
</head>
<body>
<div id="plot"></div>
<script>
let data = ${JSON.stringify(plotlyData)}
let layout = {
title: '${title}',
xaxis: {
title: 'Days'
},
yaxis: {
title: 'Cases'
}
}
Plotly.newPlot('plot', data, layout)
</script>
</body>
</html>`)
res.end()
})

// Start the server
server.listen(8080)
console.log('[@epispot/epijs] Plotly server running on http://localhost:8080')
}
else { // Is running in the browser
// Create the plot
let layout = {
title: title,
xaxis: {
title: 'Days'
},
yaxis: {
title: 'Cases'
}
}
Plotly.newPlot(name, plotlyData, layout)
}
}

exports.plot = plot;
exports.manipulate = manipulate;
exports.plot = plot
Loading

0 comments on commit 6117e2b

Please sign in to comment.