Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions rrnl/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Creating RRNLs for Vega

Using this program, you can easily create your own reference range number lines.

* RRNL visualizations are created using the `numberline_to_vega.py` program. When running it, make sure that the file for creating your RRNL is in the same directory as this program, and that the files `classes.py` and `setters.py` are there as well.
- make sure that your JSON file for creating your RRNL is valid in the RRNL domain-specific language. Look at one of the included examples, like `plateletcount.json`, to see how these files are formatted.
* When you run the program, you will be prompted to put in the name of a file. Type the name of a file in the directory that you wish to convert to a Vega object.
* The generated `vega.json` file will be a valid Vega object that will generate a RRNL based on the inputted file. You can insert the Vega object into [the Vega Editor](https://vega.github.io/editor) to view and export the RRNL.
- You can also view the RRNL embedded in an HTML file using the generated `vega.html` file.
- If your file is an array of multiple objects in the RRNL domain-specific language, then a separate JSON file will be created for each object, titled `vega1.json`, `vega2.json`, etc. Every RRNL in the file will be included in `vega.html`.
* If you are familiar with Vega, you can edit the outputted Vega object to make any changes to your RRNL that aren't possible with this program.

## Adding Gradients

If you wish to add a gradient to your RRNL, you can do so using `d3.html`.

* Paste the output from `numberline_to_vega.py` into the Vega Editor and click "Export" at the top of the page.
* Click "Download" under "Export to SVG".
* Add the downloaded SVG file to the same directory as `d3.html`.
* In `d3.html`, change the path nme in the line `const svg = await d3.xml("/rrnl/visualization.svg");` to the path to your SVG file.
* Open `d3.html` locally to view your RRNL.
Binary file added rrnl/__pycache__/classes.cpython-312.pyc
Binary file not shown.
Binary file added rrnl/__pycache__/setters.cpython-312.pyc
Binary file not shown.
31 changes: 31 additions & 0 deletions rrnl/asthmacontrol.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"title": {
"text": "Level of Asthma Control",
"font": "Arial",
"fontSize": 13,
"color": "black"
},
"data": {
"categories": [
{"name": "Controlled", "end": 1.5, "color": "green"},
{"name": "Not Controlled", "end": 6.0, "color": "red"}
],
"start": 0
},
"separation": {
"color": "black",
"width": 5
},
"labels": {
"position": "on"
},
"tickmarks": {
"tickCount": 12,
"position": "bottom"
},
"value_indicator": {
"value": 3.2,
"title": "Victor's Score",
"overlap": false
}
}
73 changes: 73 additions & 0 deletions rrnl/classes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
class Title:
def __init__ (self, text: str):
self.text = text
self.align = "center"
self.font = "Arial"
self.fontSize = 14
self.color = "black"

def set_align(self, align: str):
self.align = align

def set_font(self, font: str):
self.font = font

def set_fontSize(self, fontSize: int):
self.fontSize = fontSize

def set_color(self, color: str):
self.color = color

class Data:
def __init__ (self, categories: list):
self.categories = categories
self.start = 0

def set_start(self, start: int):
self.start = start

class CategorySeparation:
def __init__ (self):
self.color = "black"
self.width = 0

def set_color(self, color: str):
self.color = color

def set_width(self, width: int):
self.width = width

class CategoryLabels:
def __init__ (self):
self.position = "on"

def set_position(self, position: str):
self.position = position

class TickMarks:
def __init__ (self):
self.tickCount = 10
self.position = "bottom"

def set_tickCount(self, tickCount: int):
self.tickCount = tickCount

def set_position(self, position: str):
self.position = position



class ValueIndicator:
def __init__ (self, value: float, title: str):
self.value = value
self.title = title
self.overlap = False

def set_value(self, value: int):
self.value = value

def set_title(self, title: str):
self.title = title

def set_overlap(self, overlap: bool):
self.overlap = overlap
98 changes: 98 additions & 0 deletions rrnl/d3.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>RRNL with Gradient</title>
</head>
<body>
<div id="container"></div>
<script type="module">

import * as d3 from "https://cdn.jsdelivr.net/npm/d3@7/+esm";

const container = document.getElementById("container");

//get svg from same folder
const svg = await d3.xml("/rrnl/visualization.svg");
const rrnl = svg.documentElement;

//retrieve the svg creating the number line
const itemString = rrnl.innerHTML;
const parser = new DOMParser();
const doc = parser.parseFromString(itemString, "image/svg+xml");

const bars = d3.select(rrnl).select("g.mark-rect.role-mark");

let colors = []
let positions = []
let firstPosition;
let lastPosition;
const defs = rrnl.appendChild(
doc.createElementNS("http://www.w3.org/2000/svg", "defs")
);

// Add the gradient definition to <defs>
const gradient = defs.appendChild(doc.createElementNS("http://www.w3.org/2000/svg", "linearGradient"));
gradient.setAttribute("id", "rrnlGradient");
gradient.setAttribute("x1", "0%");
gradient.setAttribute("y1", "0%");
gradient.setAttribute("x2", "100%");
gradient.setAttribute("y2", "0%");

//save color and position of every bar
bars.selectAll("path").each(function(d, i, nodes) {
if (i === 0) {
firstPosition = d3.select(this).attr("d");
}
if (i === nodes.length - 1) {
lastPosition = d3.select(this).attr("d");
}
colors.push(d3.select(this).attr("fill"))
positions.push(d3.select(this).attr("d"))
});

//get the values of d for first and last bars in
const firstPositionValues = firstPosition.match(/-?\d*\.?\d+/g).map(Number);
const lastPositionValues = lastPosition.match(/-?\d*\.?\d+/g).map(Number);

//calculate where the gradient bar is drawn
const startValue = firstPositionValues[0];
const startHeight = firstPositionValues[1];
const endValue = lastPositionValues[0] + lastPositionValues[2];
const endHeight = lastPositionValues[3];

let gradientBar = "M" + startValue + "," + startHeight + "h" + endValue + "v" + endHeight + "h-" + endValue + "Z"

//create gradient
let width = endValue;
bars.selectAll("path").each(function(d, i) {

let position = d3.select(this).attr("d");
let positionValues = position.match(/-?\d*\.?\d+/g).map(Number);
let sectionStart = positionValues[0];
let sectionEnd = positionValues[0] + positionValues[2];

let firstStop = (sectionStart / width) * 100;
let secondStop = (sectionEnd / width) * 100;
let middleStop = (firstStop + secondStop) / 2;

let stop = doc.createElementNS("http://www.w3.org/2000/svg", "stop");
stop.setAttribute("offset", middleStop + "%");
stop.setAttribute("stop-color", d3.select(this).attr("fill"));
gradient.appendChild(stop);
});

//add the bar's position and gradient to a path
const newPath = doc.createElementNS("http://www.w3.org/2000/svg", "path");
newPath.setAttribute("d", gradientBar);
newPath.setAttribute("fill", "url(#rrnlGradient)");

//remove previous bars and append the newly created bar in its place
bars.selectAll("path").remove();
bars.node().appendChild(newPath);

container.append(rrnl);

</script>
</body>
</html>
Loading
Loading