Commit 2aa35629 authored by Randy Heiland's avatar Randy Heiland
Browse files

cleanup

parent e19aca7a
BSD 3-Clause License
Copyright (c) 2020, PhysiCell-Tools
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# pc4covid19 - COVID19 (SARS-CoV-2) tissue simulator nanoHUB app
**Version:** 3.0
**Release date:** 3 July 2020
## Overview
This repository contains code and data for the nanoHUB app https://nanohub.org/tools/pc4covid19.
Here, we primarily report on changes to the app's GUI.
It is based on the model at https://github.com/pc4covid19/COVID19. Refer to that repository
for a summary of changes to the model.
### Caveats and disclaimers:
**This model is under active development using rapid prototyping:**
* It has not been peer reviewed.
* It is intended to drive basic scientific research and public education at this stage.
* **It cannot be used for public policy decisions.**
* **It cannot be used for individual medical decisions.**
**This model will be continually refined with input from the community, particularly experts in infectious diseases. The validation state will be updated as this progresses.**
## Release summary:
### 3.0:
The major change to the GUI in this release is the addition of a 'Cell Types' tab.
This allows editing parameters associated with `<cell_definitions>` in the configuration file.
This version also includes a `<style>` block in the Jupyter notebook that fixed an unwanted scrollbar in the lengthy `About` tab.
### 2.0:
The major change to the GUI in this release is the addition of an 'Animate' tab.
This allows animation of cells (not substrates) in the tab and the generation of a .mp4
video that can be downloaded. The animation uses the cells' SVG files.
### 1.0:
Provides a "standard" PhysiCell-based Jupyter notebook GUI consisting of 5 tabs:
* About: a description of the model and the app
* Config Basics: input parameters common to all models (e.g., domain grid, simulation time, choice/frequency of outputs)
* Microenvironment: microenvironment parameters that are model-specific
* User Params: user parameters that are model-specific
* Out: Plots: output display of cells and substrates
diff -r src/BioFVM/ ~/dev/COVID19-dev/PhysiCell/BioFVM/
diff -r src/core/ ~/dev/COVID19-dev/PhysiCell/core/
diff -r src/custom_modules/ ~/dev/COVID19-dev/PhysiCell/custom_modules/
diff data/PhysiCell_settings.xml ~/dev/COVID19-dev/PhysiCell/config/PhysiCell_settings.xml
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"extensions": {
"jupyter_dashboards": {
"version": 1,
"views": {
"grid_default": {
"hidden": true
},
"report_default": {
"hidden": true
}
}
}
}
},
"outputs": [],
"source": [
"%matplotlib inline\n",
"#from IPython.core.display import display, HTML\n",
"#display(HTML(\"<style>.container { width:100% !important; }</style>\"))"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"extensions": {
"jupyter_dashboards": {
"version": 1,
"views": {
"grid_default": {
"hidden": true
},
"report_default": {
"hidden": true
}
}
}
}
},
"outputs": [
{
"data": {
"application/javascript": [
"\n",
"requirejs.undef('filepicker');\n",
"\n",
"define('filepicker', [\"@jupyter-widgets/base\"], function(widgets) {\n",
"\n",
" var FilePickerView = widgets.DOMWidgetView.extend({\n",
" render: function(){\n",
" this.file = document.createElement('input');\n",
" this.file.setAttribute('class', 'fileinput');\n",
" this.file.setAttribute('id', this.cid);\n",
" this.file.multiple = this.model.get('multiple');\n",
" this.file.required = true;\n",
" this.file.setAttribute('type', 'file');\n",
" this.file.setAttribute('style', 'display:none');\n",
"\n",
" this.label = document.createElement('label');\n",
" this.label.setAttribute('for', this.cid);\n",
" this.label.setAttribute('style', 'border: 1px solid; border-radius: 5px; display: inline-block; padding: 6px 12px');\n",
"\n",
" this.icon = document.createElement('i');\n",
" this.icon.setAttribute(\"class\", \"fa fa-upload\");\n",
"\n",
" if (this.file.multiple) {\n",
" this.labelstr = \" Upload Files\";\n",
" } else {\n",
" this.labelstr = \" Upload File\";\n",
" }\n",
" this.label.innerHTML = this.labelstr;\n",
" this.label.prepend(this.icon);\n",
" this.el.appendChild(this.label);\n",
" this.el.appendChild(this.file);\n",
" this.listenTo(this.model, 'change:send', this._send_changed, this);\n",
" this.listenTo(this.model, 'change:reset', this._reset, this);\n",
" this.update();\n",
" },\n",
"\n",
" events: {\n",
" // List of events and their handlers.\n",
" 'change': 'handle_file_change'\n",
" },\n",
"\n",
" _reset: function() {\n",
" this.label.innerHTML = this.labelstr;\n",
" this.label.prepend(this.icon);\n",
" this.file.removeAttribute(\"disabled\");\n",
" },\n",
"\n",
" _send_changed: function() {\n",
" var that = this;\n",
" var send = this.model.get('send');\n",
" var fnum = send[0];\n",
" var offset = send[1];\n",
" var chunk_size=64*1024;\n",
" var reader;\n",
"\n",
" if (fnum == -1) {\n",
" // ignore\n",
" return\n",
" }\n",
"\n",
" if (offset == 0) {\n",
" this.model.set('sent', -1);\n",
" this.touch();\n",
" }\n",
"\n",
" // console.log('send: ' + fnum + ' ' + offset);\n",
" function tob64( buffer ) {\n",
" var binary = '';\n",
" var bytes = new Uint8Array( buffer );\n",
" var len = bytes.byteLength;\n",
" for (var i = 0; i < len; i++) {\n",
" binary += String.fromCharCode( bytes[ i ] );\n",
" }\n",
" return window.btoa( binary );\n",
" }\n",
"\n",
" var reader_done = function (event) {\n",
" // chunk is finished. Send to python\n",
" if (event.target.error == null) {\n",
" var b64 = tob64(event.target.result);\n",
" that.model.set('data', b64);\n",
" that.model.set('sent', offset);\n",
" that.touch();\n",
" } else {\n",
" console.log(\"Read error: \" + event.target.error);\n",
" that.model.set('data', '');\n",
" that.model.set('sent', -2);\n",
" that.touch();\n",
" }\n",
" that.touch();\n",
" }\n",
" \n",
" var chunk_reader = function (_offset, _f) {\n",
" // console.log('CR' + ' ' + _f + ' ' + _offset);\n",
" reader = new FileReader();\n",
" var chunk = _f.slice(_offset, chunk_size + _offset); \n",
" reader.readAsArrayBuffer(chunk);\n",
" reader.onload = reader_done;\n",
" }\n",
" \n",
" // OK. request next chunk\n",
" chunk_reader(offset, this.files[fnum]);\n",
" },\n",
" \n",
" \n",
" handle_file_change: function(evt) {\n",
"\n",
" var _files = evt.target.files;\n",
" var filenames = [];\n",
" var file_readers = [];\n",
" this.files = [];\n",
"\n",
" for (var i = 0; i < _files.length; i++) {\n",
" var file = _files[i];\n",
" console.log(\"Filename: \" + file.name);\n",
" console.log(\"Type: \" + file.type);\n",
" console.log(\"Size: \" + file.size + \" bytes\");\n",
" this.files.push(file);\n",
" filenames.push([file.name, file.size]);\n",
" };\n",
" \n",
" // Set the filenames of the files.\n",
" this.model.set('filenames', filenames);\n",
" this.touch();\n",
"\n",
" // update the label\n",
" if (filenames.length == 0) {\n",
" this.label.innerHTML = this.labelstr;\n",
" this.file.removeAttribute(\"disabled\");\n",
" } else if (filenames.length == 1) {\n",
" this.label.innerHTML = \" \" + filenames[0][0];\n",
" this.file.setAttribute('disabled', 'true');\n",
" } else {\n",
" this.label.innerHTML = \" \" + filenames.length + \" files selected\";\n",
" this.file.setAttribute('disabled', 'true'); \n",
" };\n",
" this.label.prepend(this.icon);\n",
" },\n",
" });\n",
"\n",
" // Register the FilePickerView with the widget manager.\n",
" return {\n",
" FilePickerView: FilePickerView\n",
" };\n",
"});\n"
],
"text/plain": [
"<IPython.core.display.Javascript object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import sys, os\n",
"sys.path.insert(0, os.path.abspath('bin'))\n",
"import pc4covid19"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"extensions": {
"jupyter_dashboards": {
"version": 1,
"views": {
"grid_default": {
"col": 0,
"height": 43,
"hidden": false,
"row": 0,
"width": 11
},
"report_default": {
"hidden": false
}
}
}
},
"scrolled": false
},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "9ba52e0b64db4f63b75f34af731d6876",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"VBox(children=(HBox(children=(Dropdown(description='Load Config', options={'DEFAULT': '/Users/heiland/git/pc4c…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"pc4covid19.gui"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"extensions": {
"jupyter_dashboards": {
"version": 1,
"views": {
"grid_default": {},
"report_default": {
"hidden": true
}
}
}
}
},
"outputs": [],
"source": [
"#from debug import debug_view\n",
"#debug_view"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"extensions": {
"jupyter_dashboards": {
"activeView": "report_default",
"version": 1,
"views": {
"grid_default": {
"cellMargin": 10,
"defaultCellHeight": 20,
"maxColumns": 12,
"name": "grid",
"type": "grid"
},
"report_default": {
"name": "report",
"type": "report"
}
}
}
},
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.4"
},
"tool": true
},
"nbformat": 4,
"nbformat_minor": 2
}
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"style = \"\"\"\n",
" <style>\n",
" .jupyter-widgets-output-area .output_scroll {\n",
" height: unset !important;\n",
" border-radius: unset !important;\n",
" -webkit-box-shadow: unset !important;\n",
" box-shadow: unset !important;\n",
" }\n",
" .jupyter-widgets-output-area {\n",
" height: auto !important;\n",
" width: 100%; !important;\n",
" }\n",
" </style>\n",
" \"\"\""
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"extensions": {
"jupyter_dashboards": {
"version": 1,
"views": {
"grid_default": {
"hidden": true
},
"report_default": {
"hidden": true
}
}
}
}
},
"outputs": [
{
"data": {
"text/html": [
"\n",
" <style>\n",
" .jupyter-widgets-output-area .output_scroll {\n",
" height: unset !important;\n",
" border-radius: unset !important;\n",
" -webkit-box-shadow: unset !important;\n",
" box-shadow: unset !important;\n",
" }\n",
" .jupyter-widgets-output-area {\n",
" height: auto !important;\n",
" width: 100%; !important;\n",
" }\n",
" </style>\n",
" "
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"%matplotlib inline\n",
"from IPython.core.display import display, HTML\n",
"# display(HTML(\"<style>.container { width:100%; !important; }</style>\"))\n",
"display(HTML(style))"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"extensions": {
"jupyter_dashboards": {
"version": 1,
"views": {
"grid_default": {
"hidden": true
},
"report_default": {
"hidden": true
}
}
}
}
},
"outputs": [
{
"data": {
"application/javascript": [
"\n",
"requirejs.undef('filepicker');\n",
"\n",
"define('filepicker', [\"@jupyter-widgets/base\"], function(widgets) {\n",
"\n",
" var FilePickerView = widgets.DOMWidgetView.extend({\n",
" render: function(){\n",
" this.file = document.createElement('input');\n",
" this.file.setAttribute('class', 'fileinput');\n",
" this.file.setAttribute('id', this.cid);\n",
" this.file.multiple = this.model.get('multiple');\n",
" this.file.required = true;\n",
" this.file.setAttribute('type', 'file');\n",
" this.file.setAttribute('style', 'display:none');\n",
"\n",
" this.label = document.createElement('label');\n",
" this.label.setAttribute('for', this.cid);\n",
" this.label.setAttribute('style', 'border: 1px solid; border-radius: 5px; display: inline-block; padding: 6px 12px');\n",
"\n",
" this.icon = document.createElement('i');\n",
" this.icon.setAttribute(\"class\", \"fa fa-upload\");\n",
"\n",
" if (this.file.multiple) {\n",
" this.labelstr = \" Upload Files\";\n",
" } else {\n",
" this.labelstr = \" Upload File\";\n",
" }\n",
" this.label.innerHTML = this.labelstr;\n",
" this.label.prepend(this.icon);\n",
" this.el.appendChild(this.label);\n",
" this.el.appendChild(this.file);\n",
" this.listenTo(this.model, 'change:send', this._send_changed, this);\n",
" this.listenTo(this.model, 'change:reset', this._reset, this);\n",
" this.update();\n",
" },\n",
"\n",
" events: {\n",
" // List of events and their handlers.\n",
" 'change': 'handle_file_change'\n",
" },\n",
"\n",
" _reset: function() {\n",
" this.label.innerHTML = this.labelstr;\n",
" this.label.prepend(this.icon);\n",
" this.file.removeAttribute(\"disabled\");\n",
" },\n",
"\n",
" _send_changed: function() {\n",
" var that = this;\n",
" var send = this.model.get('send');\n",
" var fnum = send[0];\n",
" var offset = send[1];\n",
" var chunk_size=64*1024;\n",
" var reader;\n",
"\n",
" if (fnum == -1) {\n",
" // ignore\n",
" return\n",
" }\n",
"\n",
" if (offset == 0) {\n",
" this.model.set('sent', -1);\n",
" this.touch();\n",
" }\n",
"\n",
" // console.log('send: ' + fnum + ' ' + offset);\n",
" function tob64( buffer ) {\n",
" var binary = '';\n",
" var bytes = new Uint8Array( buffer );\n",
" var len = bytes.byteLength;\n",
" for (var i = 0; i < len; i++) {\n",
" binary += String.fromCharCode( bytes[ i ] );\n",
" }\n",
" return window.btoa( binary );\n",
" }\n",
"\n",
" var reader_done = function (event) {\n",
" // chunk is finished. Send to python\n",
" if (event.target.error == null) {\n",
" var b64 = tob64(event.target.result);\n",
" that.model.set('data', b64);\n",
" that.model.set('sent', offset);\n",
" that.touch();\n",
" } else {\n",
" console.log(\"Read error: \" + event.target.error);\n",
" that.model.set('data', '');\n",
" that.model.set('sent', -2);\n",
" that.touch();\n",
" }\n",
" that.touch();\n",
" }\n",
" \n",
" var chunk_reader = function (_offset, _f) {\n",
" // console.log('CR' + ' ' + _f + ' ' + _offset);\n",
" reader = new FileReader();\n",
" var chunk = _f.slice(_offset, chunk_size + _offset); \n",
" reader.readAsArrayBuffer(chunk);\n",
" reader.onload = reader_done;\n",
" }\n",
" \n",
" // OK. request next chunk\n",
" chunk_reader(offset, this.files[fnum]);\n",
" },\n",
" \n",
" \n",
" handle_file_change: function(evt) {\n",
"\n",
" var _files = evt.target.files;\n",
" var filenames = [];\n",
" var file_readers = [];\n",
" this.files = [];\n",
"\n",
" for (var i = 0; i < _files.length; i++) {\n",
" var file = _files[i];\n",
" console.log(\"Filename: \" + file.name);\n",
" console.log(\"Type: \" + file.type);\n",
" console.log(\"Size: \" + file.size + \" bytes\");\n",
" this.files.push(file);\n",
" filenames.push([file.name, file.size]);\n",
" };\n",
" \n",
" // Set the filenames of the files.\n",
" this.model.set('filenames', filenames);\n",
" this.touch();\n",
"\n",
" // update the label\n",
" if (filenames.length == 0) {\n",
" this.label.innerHTML = this.labelstr;\n",
" this.file.removeAttribute(\"disabled\");\n",
" } else if (filenames.length == 1) {\n",
" this.label.innerHTML = \" \" + filenames[0][0];\n",
" this.file.setAttribute('disabled', 'true');\n",
" } else {\n",
" this.label.innerHTML = \" \" + filenames.length + \" files selected\";\n",
" this.file.setAttribute('disabled', 'true'); \n",
" };\n",
" this.label.prepend(this.icon);\n",
" },\n",
" });\n",
"\n",
" // Register the FilePickerView with the widget manager.\n",
" return {\n",