Skip to content
Merged
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,6 @@ Cargo.lock
#.idea/*~
.DS_Store
env/
venv/
site/
static/
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ opt-level = 0

[profile.release]
opt-level = 3

63 changes: 34 additions & 29 deletions heatmap/src/canvas/drawing.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use web_sys::{CanvasRenderingContext2d, console};
use wasm_bindgen::JsValue;

use web_sys::{console, CanvasRenderingContext2d};

pub fn draw_responsive_heatmap(
context: &CanvasRenderingContext2d,
Expand All @@ -10,12 +9,11 @@ pub fn draw_responsive_heatmap(
canvas_width: f64,
canvas_height: f64,
device_pixel_ratio: f64,
) -> Result<(), JsValue>
{
) -> Result<(), JsValue> {
let rows = values.len();
let cols = values[0].len();
console::log_1(&JsValue::from_str(&format!("up in the draw function")));
// Get canvas dimensions
// Get canvas dimensions
// Calculate dynamic padding and box size
let adj_canvas_width = canvas_width * device_pixel_ratio;
let adj_canvas_height = canvas_height * device_pixel_ratio;
Expand All @@ -24,13 +22,16 @@ pub fn draw_responsive_heatmap(
let padding_bottom = adj_canvas_height * 0.05;
let _padding_right = adj_canvas_width * 0.05;

// let box_width = (adj_canvas_width - padding_left - padding_right) / (cols as f64 * 1.1);
// let box_height = (adj_canvas_height - padding_top - padding_bottom) / (rows as f64 * 1.1);
// let box_width = (adj_canvas_width - padding_left - padding_right) / (cols as f64 * 1.1);
// let box_height = (adj_canvas_height - padding_top - padding_bottom) / (rows as f64 * 1.1);

let box_width = 30.0;
let box_height = 30.0;
// Clear the canvas
console::log_1(&JsValue::from_str(&format!("pad left {} pad bottom {}",&padding_left, &padding_bottom)));
console::log_1(&JsValue::from_str(&format!(
"pad left {} pad bottom {}",
&padding_left, &padding_bottom
)));
context.clear_rect(0.0, 0.0, adj_canvas_width, adj_canvas_height);
println!("cleared rec");
// Draw the heatmap
Expand All @@ -46,17 +47,17 @@ pub fn draw_responsive_heatmap(
_ => "#FFFFFF",
};
//context.set_fill_style_str(&JsValue::from(color));
context.set_fill_style_str(color);
context.set_fill_style_str(color);

let x = padding_left + (col as f64 * box_width);
let y = padding_top + (row as f64 * box_height);
context.fill_rect(x, y, box_width, box_height);

// Draw box borders
//context.set_stroke_style(&JsValue::from("#FFFFFF"));
context.set_stroke_style_str("#FFFFFF");
context.set_stroke_style_str("#FFFFFF");
context.set_line_width(2.0 / device_pixel_ratio);

if row < rows - 1 {
context.begin_path();
context.move_to(x, y + box_height);
Expand All @@ -73,19 +74,22 @@ pub fn draw_responsive_heatmap(
}
}
console::log_1(&JsValue::from_str(&format!(
"after the rows and cols padding bottom: {}, height: {}",
&padding_bottom,
&(box_height * rows as f64),
)));
"after the rows and cols padding bottom: {}, height: {}",
&padding_bottom,
&(box_height * rows as f64),
)));

// Draw X-axis
context.begin_path();
//context.set_stroke_style_str(&JsValue::from("#000000"));
context.set_stroke_style_str("#000000");
context.move_to(padding_left, (box_height * rows as f64) + padding_bottom);
context.line_to((box_height * rows as f64) + padding_bottom, (box_height * rows as f64) + padding_left);
context.line_to(
(box_height * rows as f64) + padding_bottom,
(box_height * rows as f64) + padding_left,
);
context.stroke();

// Draw Y-axis
context.begin_path();
context.move_to(padding_left, padding_top);
Expand All @@ -97,11 +101,12 @@ pub fn draw_responsive_heatmap(
context.set_font(&format!("{}px Arial", label_font_size));
context.set_text_align("center");
context.set_text_baseline("top");

for col in 0..cols {
let x = padding_left + col as f64 * box_width + box_width / 2.0;
let y = (box_height * rows as f64) + padding_bottom + 5.0; // Position below the heatmap
context.fill_text(&x_labels[col], x, y)
let y = (box_height * rows as f64) + padding_bottom + 5.0; // Position below the heatmap
context
.fill_text(&x_labels[col], x, y)
.map_err(|_| JsValue::from_str(&format!("Failed to draw text at column {}", col)))?;

// Draw ticks
Expand All @@ -114,11 +119,12 @@ pub fn draw_responsive_heatmap(
// Draw Y-axis ticks and labels
context.set_text_align("right");
context.set_text_baseline("middle");

for row in 0..rows {
let x = padding_left - 10.0; // Position to the left of the heatmap
let x = padding_left - 10.0; // Position to the left of the heatmap
let y = padding_top + row as f64 * box_height + box_height / 2.0;
context.fill_text(&y_labels[row], x, y)
context
.fill_text(&y_labels[row], x, y)
.map_err(|_| JsValue::from_str(&format!("Failed to draw text at row {}", row)))?;

// Draw ticks
Expand All @@ -128,9 +134,8 @@ pub fn draw_responsive_heatmap(
context.stroke();
}
console::log_1(&JsValue::from_str(&format!(
"at the end of draw funct Canvas width: {}, height: {}",
&adj_canvas_width,
&adj_canvas_height
)));
"at the end of draw funct Canvas width: {}, height: {}",
&adj_canvas_width, &adj_canvas_height
)));
Ok(())
}
}
10 changes: 5 additions & 5 deletions heatmap/src/heatmap_data.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
//! This module contains the data structure for the heatmap

use serde::{Serialize, Deserialize};
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct HeatmapData {
pub values: Vec<Vec<i32>>,
pub x_labels: Vec<String>,
pub y_labels: Vec<String>,
pub values: Vec<Vec<i32>>,
pub x_labels: Vec<String>,
pub y_labels: Vec<String>,
}

impl HeatmapData {
Expand All @@ -31,4 +31,4 @@ mod tests {
assert_eq!(heatmap_data.x_labels, Vec::<String>::new());
assert_eq!(heatmap_data.y_labels, Vec::<String>::new());
}
}
}
83 changes: 49 additions & 34 deletions heatmap/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
//! # A Heatmap in Rust web assembly calling d3.js
//!
//! You will need to use wasm-pack to build instead of cargo
//! You will need to use wasm-pack to build instead of cargo
//! wasm-pack build --target web
//! And some way of serving locally
//! And some way of serving locally
//! http-server .
//! It requires the index.html in the static directory
//! Currently working with fixed data
//! and a rusty colour theme
#![allow(non_snake_case)]
pub mod heatmap_data;
pub mod canvas;
pub mod heatmap_data;

// internal imports
use canvas::drawing::draw_responsive_heatmap;
use heatmap_data::HeatmapData;

// external imports
use std::rc::Rc;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsValue;
use web_sys::{window, HtmlCanvasElement, CanvasRenderingContext2d};
use web_sys::console;
use std::rc::Rc;
use web_sys::{window, CanvasRenderingContext2d, HtmlCanvasElement};

//returns a JsValue to javascript
#[wasm_bindgen(start)]
Expand All @@ -31,44 +31,55 @@ pub fn start() -> Result<(), JsValue> {
let window = Rc::new(window);
let window_clone = Rc::clone(&window);
let document = window.document().ok_or(JsValue::from_str("no document"))?;
console::log_1(&JsValue::from_str(&format!("up in the start of the function")));
console::log_1(&JsValue::from_str(&format!(
"up in the start of the function"
)));
// Get the canvas element
let canvas = document
.get_element_by_id("heatmap")
.ok_or(JsValue::from_str("Canvas element not found"))?
.dyn_into::<HtmlCanvasElement>()?;
console::log_1(&JsValue::from_str(&format!("called the canvas")));
let heatmap_values = vec![
vec![2, 1, 0, 1, 0], // row 1
vec![1, 2, 0, 0, 1], // row 2
vec![2, 0, 1, 2, 1], // row 3
vec![0, 0, 0, 2, 0], // row 4
vec![2, 1, 0, 1, 0], // row 1
vec![1, 2, 0, 0, 1], // row 2
vec![2, 0, 1, 2, 1], // row 3
vec![0, 0, 0, 2, 0], // row 4
vec![1, 2, 0, 1, 1], // row 5
];
console::log_1(&JsValue::from_str(&format!("called the heatmap vals")));
let x_labels: Vec<String> = vec!["A", "B", "C", "D", "E"].iter().map(|s| s.to_string()).collect();
let y_labels: Vec<String> = vec!["R1", "R2", "R3", "R4", "R5"].iter().map(|s| s.to_string()).collect();

let num_rows = heatmap_values.len(); // Should be 5
let num_cols = heatmap_values[0].len(); // Should be 5
let x_labels: Vec<String> = vec!["A", "B", "C", "D", "E"]
.iter()
.map(|s| s.to_string())
.collect();
let y_labels: Vec<String> = vec!["R1", "R2", "R3", "R4", "R5"]
.iter()
.map(|s| s.to_string())
.collect();

let num_rows = heatmap_values.len(); // Should be 5
let num_cols = heatmap_values[0].len(); // Should be 5
let mut heatmap_data = HeatmapData::new();
heatmap_data.values = heatmap_values.clone();
heatmap_data.x_labels = x_labels.clone();
heatmap_data.y_labels = y_labels.clone();
let box_size = 100.0;
let device_pixel_ratio = window.device_pixel_ratio();
console::log_1(&JsValue::from_str(&format!("num rows are {:?} num cols are {:?}", &num_rows, &num_cols)));

console::log_1(&JsValue::from_str(&format!(
"num rows are {:?} num cols are {:?}",
&num_rows, &num_cols
)));

// Dynamically set canvas size based on number of rows and columns
let canvas_width = num_cols as f64 * box_size; // 6 columns * 50px
let canvas_width = num_cols as f64 * box_size; // 6 columns * 50px
let canvas_height = num_rows as f64 * box_size; // 6 rows * 50px
canvas.set_width(canvas_width as u32);
canvas.set_height(canvas_height as u32);
console::log_1(&JsValue::from_str(&format!(
"Canvas width: {}, height: {}",
canvas.width(),
canvas.height()
)));
)));

let context = canvas
.get_context("2d")?
Expand All @@ -77,24 +88,26 @@ pub fn start() -> Result<(), JsValue> {

// Define the heatmap matrix (3x3) with values representing different colors
context.scale(device_pixel_ratio, device_pixel_ratio)?;

draw_responsive_heatmap(
&context,
heatmap_values.clone(),
x_labels.clone(),
y_labels.clone(),
canvas_width,
canvas_height,
device_pixel_ratio,
)?;
&context,
heatmap_values.clone(),
x_labels.clone(),
y_labels.clone(),
canvas_width,
canvas_height,
device_pixel_ratio,
)?;

let handle_heatmap_resize = move || -> Result<(), JsValue> {
let new_width = window_clone.inner_width()
let new_width = window_clone
.inner_width()
.map_err(|_| JsValue::from_str("error getting inner width"))?
.as_f64()
.ok_or(JsValue::from_str("error converting width to f64"))?;

let new_height = window_clone.inner_height()
let new_height = window_clone
.inner_height()
.map_err(|_| JsValue::from_str("error getting inner height"))?
.as_f64()
.ok_or(JsValue::from_str("error converting height to f64"))?;
Expand All @@ -105,9 +118,11 @@ pub fn start() -> Result<(), JsValue> {
canvas.set_width(canvas_new_width as u32);
canvas.set_height(canvas_new_height as u32);

context.set_transform(1.0, 0.0, 0.0, 1.0, 0.0, 0.0)
context
.set_transform(1.0, 0.0, 0.0, 1.0, 0.0, 0.0)
.map_err(|_| JsValue::from_str("error setting transform"))?;
context.scale(device_pixel_ratio, device_pixel_ratio)
context
.scale(device_pixel_ratio, device_pixel_ratio)
.map_err(|_| JsValue::from_str("error scaling context"))?;

draw_responsive_heatmap(
Expand All @@ -128,9 +143,9 @@ pub fn start() -> Result<(), JsValue> {
console::error_1(&e);
}
};

let closure = Closure::wrap(Box::new(error_handled_heatmap_resize) as Box<dyn FnMut()>);

window.add_event_listener_with_callback("resize", closure.as_ref().unchecked_ref())?;
closure.forget();

Expand Down
8 changes: 6 additions & 2 deletions microBioRust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,17 @@ repository = "https://github.com/LCrossman/microBioRust"
[lints.rust]
unsafe_code = "forbid"

[lib]
path = "src/lib.rs"

[dependencies]
paste = "1.0"
itertools = "0.10.1"
itertools = "0.14.0"
protein-translate = "0.2.0"
bio = "2.3.0"
anyhow = "1.0"
thiserror = "1.0"
thiserror = "2.0.12"
regex = "1.5"
chrono = "0.4.38"
clap = { version = "4.5.19", features = ["derive"] }

Loading