Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
60120a7
renaming class
cornhundred Jul 3, 2025
1a311b3
clustergram registry
cornhundred Jul 3, 2025
5ba6e97
linting fixes
cornhundred Jul 3, 2025
212318a
removed print statement
cornhundred Jul 3, 2025
4fe6b4a
removed name logic
cornhundred Jul 3, 2025
e7e9115
Add Parquet export support for Clustergram widget (#111)
cornhundred Jul 7, 2025
5be64f0
Update src/celldega/clust/matrix.py
cornhundred Jul 7, 2025
9f91403
ruff fix
cornhundred Jul 7, 2025
d08be3b
docs: add parquet_data usage (#117)
cornhundred Jul 7, 2025
dc1435d
Add Clustergram parquet widget tests (#116)
cornhundred Jul 7, 2025
7c97931
upadted test
cornhundred Jul 7, 2025
eb4a6a8
fixed test lint
cornhundred Jul 7, 2025
118883b
ruff format
cornhundred Jul 7, 2025
5b144d4
format JS
cornhundred Jul 7, 2025
1a3fada
Allow numeric and categorical attributes
cornhundred Jul 8, 2025
2fe807f
merging in changes from main
cornhundred Jul 9, 2025
e1e1d92
fixed loading numerical attr
cornhundred Jul 9, 2025
a4a9eb0
added pring
cornhundred Jul 9, 2025
6177ce7
Deprecate JSON network export (#128)
cornhundred Jul 10, 2025
fc7a0d5
renamed attrs attr
cornhundred Jul 10, 2025
1addd24
numerical attributes starting to viz
cornhundred Jul 10, 2025
6856a8b
changed default colors
cornhundred Jul 10, 2025
1e3933e
lint
cornhundred Jul 10, 2025
48fbaf9
swapped colors
cornhundred Jul 10, 2025
7796584
use col_attr/row_attr to filter AnnData.obs/var
cornhundred Jul 10, 2025
4d4684a
added tooltip attribute name
cornhundred Jul 10, 2025
11e0b4f
changed default behavior of categories in DataFrame and AnnData API
cornhundred Jul 10, 2025
bab1d86
adjusted warnings/errors for matrix_cell_thresh
cornhundred Jul 11, 2025
f9820bf
Add finalize cleanup for widgets (#134)
cornhundred Jul 11, 2025
2f4d7a4
format
cornhundred Jul 11, 2025
0d661b4
fixed comment on colors
cornhundred Jul 11, 2025
e321041
added example notebook
cornhundred Jul 11, 2025
ca5ebef
added example notebook
cornhundred Jul 11, 2025
70ade6e
modifie notebook
cornhundred Jul 11, 2025
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
2 changes: 1 addition & 1 deletion docs/overview/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@ cgm = dega.viz.Clustergram(parquet_data=pq_data, width=500, height=500)
cgm
```

`Clustergram` also accepts `network` or `matrix` arguments, but `parquet_data` is recommended for large datasets.
`Clustergram` can also be initialized directly from a `Matrix` instance which internally uses `export_viz_parquet`. Passing a legacy JSON `network` is now deprecated.
3 changes: 2 additions & 1 deletion docs/python/viz/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

The `Clustergram` widget accepts a `parquet_data` argument for efficient
initialization. Use [`Matrix.export_viz_parquet`](../clust/api.md#celldega.clust.matrix.Matrix.export_viz_parquet)
to generate this data from a clustered matrix.
to generate this data from a clustered matrix. Passing a JSON ``network``
object is deprecated; pass ``matrix`` or ``parquet_data`` instead.

::: celldega.viz

5 changes: 1 addition & 4 deletions js/deck-gl/core/calc_viewport.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,10 @@ export const calc_viewport = async (
);

if (tiles_in_view.length < max_tiles_to_view) {

viz_state.obs_store.deck_check.set({
...viz_state.obs_store.deck_check.get(),
trx_data: false,
path_data: false
path_data: false,
});

viz_state.close_up = true;
Expand All @@ -59,7 +58,6 @@ export const calc_viewport = async (
viz_state
);


// gene bar graph update
const filtered_transcripts = viz_state.combo_data.trx.filter(
(pos) =>
Expand Down Expand Up @@ -134,5 +132,4 @@ export const calc_viewport = async (
}

viz_state.layers_obj = layers_obj;

};
2 changes: 0 additions & 2 deletions js/deck-gl/layers/cell_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import { get_scatter_data } from '../../read_parquet/get_scatter_data';
import { scale_umap_data } from '../../umap/scale_umap_data';

const cell_layer_onclick = async (info, d, deck_ist, layers_obj, viz_state) => {

// Check if the device is a touch device
const isTouchDevice =
'ontouchstart' in window || navigator.maxTouchPoints > 0;
Expand Down Expand Up @@ -285,5 +284,4 @@ export const toggle_spatial_umap = (deck_ist, layers_obj, viz_state) => {
getPosition: [viz_state.umap.state],
},
});

};
1 change: 0 additions & 1 deletion js/deck-gl/layers/path_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ export const update_path_layer_data = async (
layers_obj,
viz_state
) => {

const polygonPathsConcat = await grab_cell_tiles_in_view(
base_url,
tiles_in_view,
Expand Down
1 change: 0 additions & 1 deletion js/deck-gl/layers/trx_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ const trx_layer_callback = async (
viz_state.vector_name_integer,
viz_state.aws
);

};

export const ini_trx_layer = (genes) => {
Expand Down
12 changes: 4 additions & 8 deletions js/deck-gl/matrix/matrix_tooltip.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,37 +10,33 @@ export const get_tooltip = (viz_state, params) => {
if (object) {
// Check which layer the tooltip is currently over
if (layer.id === 'row-label-layer') {
// Display the row label when hovering over the row_label_layer
return {
html: `Row Label: ${object.name}`,
style: { color: 'white' },
};
} else if (layer.id === 'col-label-layer') {
// Display the row label when hovering over the row_label_layer
return {
html: `Col Label: ${object.name}`,
style: { color: 'white' },
};
} else if (layer.id === 'row-layer') {
// Display the row label when hovering over the row_label_layer
const row_attr_name = viz_state.attr.names.row[object.level];
return {
html: `Row Label: ${object.name}`,
html: `${row_attr_name}: ${object.name}`,
style: { color: 'white' },
};
} else if (layer.id === 'col-layer') {
// Display the row label when hovering over the row_label_layer
const col_attr_name = viz_state.attr.names.col[object.level];
return {
html: `Col Label: ${object.name}`,
html: `${col_attr_name}: ${object.name}`,
style: { color: 'white' },
};
} else if (layer.id === 'row-dendro-layer') {
// Display the row label when hovering over the row_label_layer
return {
html: `row-dendro-${object.properties.name}<br>${object.properties.all_names}`,
style: { color: 'white' },
};
} else if (layer.id === 'col-dendro-layer') {
// Display the row label when hovering over the row_label_layer
return {
html: `row-dendro-${object.properties.name}<br>${object.properties.all_names}`,
style: { color: 'white' },
Expand Down
1 change: 0 additions & 1 deletion js/global_variables/cat.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,4 @@ export const update_selected_cats = (cats, new_selected_cats, obs_store) => {

// Update obs_store
obs_store.selected_cats.set(cats.selected_cats);

};
1 change: 0 additions & 1 deletion js/global_variables/selected_genes.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,4 @@ export const update_selected_genes = (genes, new_selected_genes, obs_store) => {

// Update obs_store
obs_store.selected_genes.set(genes.selected_genes);

};
57 changes: 33 additions & 24 deletions js/matrix/cat_data.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,11 @@ const colorToRgba = (colorStr, alpha = 255) => {
return [d3col.r, d3col.g, d3col.b, alpha];
};

const set_cat_data = (network, viz_state, axis) => {
export const set_cat_data = (network, viz_state, axis) => {
const isRow = axis === 'row';
const nodes = isRow ? network.row_nodes : network.col_nodes;
const num_cats = isRow
? viz_state.cats.num_cats.row
: viz_state.cats.num_cats.col;
const num_attr = isRow ? viz_state.attr.num.row : viz_state.attr.num.col;
const max_abs = isRow ? viz_state.attr.maxabs.row : viz_state.attr.maxabs.col;
const cat_offset = isRow
? viz_state.viz.row_cat_offset
: viz_state.viz.col_cat_offset;
Expand All @@ -26,30 +25,48 @@ const set_cat_data = (network, viz_state, axis) => {

const cat_data = nodes
.flatMap((node, node_index) => {
return Array.from({ length: num_cats }).map((_, cat_index) => {
const cat_name = `cat-${cat_index}`;
const inst_cat = node[cat_name];
return Array.from({ length: num_attr }).map((_, attr_index) => {
let value;
let color_rgba;
const maxVal = max_abs[attr_index];
const isNumeric = maxVal !== null && maxVal !== undefined;

if (!inst_cat) {
return null;
if (isNumeric) {
const attr_name = `num-${attr_index}`;
value = node[attr_name];
if (value === undefined || value === null || isNaN(value)) {
return null;
}
// dark gray rgba for positive, orange rgba for negative
const neg = [255, 165, 0];
const pos = [169, 169, 169];
const color = value >= 0 ? pos : neg;
const scale = maxVal === 0 ? 1 : maxVal;
const alpha = Math.min(1, Math.abs(value) / scale);
color_rgba = [...color, Math.round(alpha * 255)];
} else {
const cat_name = `cat-${attr_index}`;
value = node[cat_name];
if (!value) {
return null;
}
const ini_color = network.global_cat_colors[value];
color_rgba = colorToRgba(ini_color, 255);
}

const ini_color = network.global_cat_colors[inst_cat];
const color_rgba = colorToRgba(ini_color, 255);

return {
position: isRow
? [
cat_offset * (cat_index + 0.5) + 20,
cat_offset * (attr_index + 0.5) + 20,
node_offset * (node_index + 0.5),
]
: [
node_offset * (node_index + 0.5),
cat_offset * (cat_index + 1.5) - 30,
cat_offset * (attr_index + 1.5) - 30,
],
color: color_rgba,
name: inst_cat,
level: cat_index,
name: value,
level: attr_index,
original_index: node_index,
};
});
Expand All @@ -58,11 +75,3 @@ const set_cat_data = (network, viz_state, axis) => {

return cat_data;
};

export const set_row_cat_data = (network, viz_state) => {
return set_cat_data(network, viz_state, 'row');
};

export const set_col_cat_data = (network, viz_state) => {
return set_cat_data(network, viz_state, 'col');
};
37 changes: 22 additions & 15 deletions js/matrix/mat_data.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,37 @@
export const set_mat_data = (network, viz_state) => {
// Iterate over each row and column in network.mat
let inst_color;
network.mat.forEach((rowArray, index_row) => {
rowArray.forEach((tile_value, index_col) => {
if (tile_value >= 0) {
inst_color = [255, 0, 0];
} else {
inst_color = [0, 0, 255];
}
const { mat } = network;
const { col_offset, row_offset } = viz_state.viz;
const { max_abs_value } = viz_state.mat;
const { mat_data } = viz_state.mat;

for (let index_row = 0; index_row < mat.length; index_row++) {
const rowArray = mat[index_row];

for (let index_col = 0; index_col < rowArray.length; index_col++) {
const tile_value = rowArray[index_col];

// Optional: skip small/zero values to reduce memory
if (tile_value == null || Math.abs(tile_value) < 1e-6) continue;

const inst_color = tile_value >= 0 ? [255, 0, 0] : [0, 0, 255];

const p = {
position: [
viz_state.viz.col_offset * (index_col + 0.5),
viz_state.viz.row_offset * (index_row + 1.5),
col_offset * (index_col + 0.5),
row_offset * (index_row + 1.5),
],
color: [
inst_color[0],
inst_color[1],
inst_color[2],
(255 * Math.abs(tile_value)) / viz_state.mat.max_abs_value,
(255 * Math.abs(tile_value)) / max_abs_value,
],
value: tile_value,
row: index_row,
col: index_col,
};
viz_state.mat.mat_data.push(p);
});
});

mat_data.push(p);
}
}
};
27 changes: 17 additions & 10 deletions js/matrix/set_constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,19 @@ export const set_mat_constants = (
viz_state.viz = {};
viz_state.viz.height_margin = 100;

viz_state.cats = {};
viz_state.cats.num_cats = {};

// use network cat_colors to figure out how many categories there are
viz_state.cats.num_cats.row = Object.keys(network.row_cats).length;
viz_state.cats.num_cats.col = Object.keys(network.col_cats).length;
viz_state.attr = {};
viz_state.attr.names = {
row: network.row_attr || [],
col: network.col_attr || [],
};
viz_state.attr.maxabs = {
row: network.row_attr_maxabs || [],
col: network.col_attr_maxabs || [],
};
viz_state.attr.num = {
row: viz_state.attr.names.row.length,
col: viz_state.attr.names.col.length,
};

viz_state.root.style.height = `${height + viz_state.viz.height_margin}px`;

Expand All @@ -40,9 +47,9 @@ export const set_mat_constants = (
viz_state.viz.col_cat_offset = 9;

viz_state.viz.mat_width =
width - viz_state.viz.row_cat_offset * viz_state.cats.num_cats.row;
width - viz_state.viz.row_cat_offset * viz_state.attr.num.row;
viz_state.viz.mat_height =
height - viz_state.viz.col_cat_offset * viz_state.cats.num_cats.col;
height - viz_state.viz.col_cat_offset * viz_state.attr.num.col;

viz_state.mat = {};
viz_state.mat.num_rows = network.mat.length;
Expand Down Expand Up @@ -99,12 +106,12 @@ export const set_mat_constants = (

viz_state.viz.col_region =
(viz_state.viz.col_cat_height + viz_state.viz.extra_space.col) *
viz_state.cats.num_cats.col +
viz_state.attr.num.col +
viz_state.viz.col_label;

viz_state.viz.row_region =
(viz_state.viz.row_cat_width + viz_state.viz.extra_space.row) *
viz_state.cats.num_cats.row +
viz_state.attr.num.row +
viz_state.viz.row_label;

viz_state.viz.col_width = viz_state.viz.mat_width / viz_state.mat.num_cols;
Expand Down
13 changes: 8 additions & 5 deletions js/obs_store/obs_store.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,18 @@ export const create_obs_store = () => {
path_layer: true,
trx_layer: true,
trx_data: true,
path_data: true
path_data: true,
}),
deck_ready: Observable(false),
};

store.deck_check.subscribe((check) => {
const ready = Object.values(check).every((v) => v === true);
store.deck_ready.set(ready);
}, { immediate: false });
store.deck_check.subscribe(
(check) => {
const ready = Object.values(check).every((v) => v === true);
store.deck_ready.set(ready);
},
{ immediate: false }
);

return store;
};
5 changes: 1 addition & 4 deletions js/ui/bar_plot.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,17 @@ export const bar_callback_cluster = (
_layers_obj,
_viz_state
) => {

// add cell_layer, path_layer, and trx_layer to the deck_check observable
_viz_state.obs_store.deck_check.set({
..._viz_state.obs_store.deck_check.get(),
cell_layer: false,
path_layer: false,
trx_layer: false,
});

update_cat(_viz_state.cats, 'cluster');
update_selected_cats(_viz_state.cats, [d.name], _viz_state.obs_store);
update_selected_genes(_viz_state.genes, [], _viz_state.obs_store);

};

export const bar_callback_gene = async (
Expand Down Expand Up @@ -61,7 +59,6 @@ export const bar_callback_gene = async (
_viz_state.vector_name_integer,
_viz_state.aws
);

};

export const bar_callback_rgn = (
Expand Down
3 changes: 0 additions & 3 deletions js/ui/gene_search.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ const sst_gene_search_callback = async (deck_sst, viz_state, layers_sst) => {
const new_cat = inst_gene === '' ? 'cluster' : inst_gene;

if (inst_gene === '' || viz_state.genes.gene_names.includes(inst_gene)) {

update_cat(viz_state.cats, new_cat);

viz_state.obs_store.deck_check.set({
Expand Down Expand Up @@ -47,7 +46,6 @@ const ist_gene_search_callback = async (deck_ist, layers_obj, viz_state) => {
const new_cat = inst_gene === '' ? 'cluster' : inst_gene;

if (inst_gene === '' || viz_state.genes.gene_names.includes(inst_gene)) {

update_cat(viz_state.cats, new_cat);

viz_state.obs_store.deck_check.set({
Expand Down Expand Up @@ -85,7 +83,6 @@ const ist_gene_search_callback = async (deck_ist, layers_obj, viz_state) => {
viz_state.aws
);
}

}
};

Expand Down
Loading
Loading