From f370dde5851174955d798b91d5bcdd4d7256d283 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Fri, 17 Apr 2026 11:18:38 -0400 Subject: [PATCH 1/3] Added more colors --- ui/src/components/umap/bed-embedding-plot.tsx | 4 ++-- ui/src/components/umap/bed-embedding-view.tsx | 10 ++++---- ui/src/components/umap/embedding-legend.tsx | 4 ++-- ui/src/components/umap/embedding-plot.tsx | 4 ++-- .../contexts/mosaic-coordinator-context.tsx | 7 +++--- ui/src/utils.ts | 24 ++++++++++++++++++- 6 files changed, 38 insertions(+), 15 deletions(-) diff --git a/ui/src/components/umap/bed-embedding-plot.tsx b/ui/src/components/umap/bed-embedding-plot.tsx index f3a93cc7..9b173985 100644 --- a/ui/src/components/umap/bed-embedding-plot.tsx +++ b/ui/src/components/umap/bed-embedding-plot.tsx @@ -3,9 +3,9 @@ import { useEffect, useState, useRef, useMemo, forwardRef, useImperativeHandle } import toast from 'react-hot-toast'; import * as vg from '@uwdata/vgplot'; -import { tableau20 } from '../../utils'; +import { categoryPalette } from '../../utils'; -const categoryColors = [...tableau20, '#cccccc']; +const categoryColors = [...categoryPalette, '#cccccc']; import { AtlasTooltip } from './atlas-tooltip'; import { useMosaicCoordinator } from '../../contexts/mosaic-coordinator-context'; diff --git a/ui/src/components/umap/bed-embedding-view.tsx b/ui/src/components/umap/bed-embedding-view.tsx index 06aeaf77..2470f64b 100644 --- a/ui/src/components/umap/bed-embedding-view.tsx +++ b/ui/src/components/umap/bed-embedding-view.tsx @@ -2,7 +2,7 @@ import { EmbeddingViewMosaic } from 'embedding-atlas/react'; import { useEffect, useState, useRef, useMemo } from 'react'; import * as vg from '@uwdata/vgplot'; -import { isPointInPolygon, tableau20 } from '../../utils'; +import { isPointInPolygon, categoryPalette, MAX_CATEGORIES } from '../../utils'; import { useBedCart } from '../../contexts/bedcart-context'; import { components } from '../../../bedbase-types'; import { AtlasTooltip } from './atlas-tooltip'; @@ -47,10 +47,10 @@ export const BEDEmbeddingView = (props: Props) => { const [pinGrouping, setPinGrouping] = useState(colorGrouping); const categoryColors = useMemo(() => { - const colors = [...tableau20, '#cccccc']; + const colors = [...categoryPalette, '#cccccc']; if (legendItems) { legendItems.forEach((item: any) => { - if (item.name === 'UNKNOWN' && item.category < 20) { + if (item.name === 'UNKNOWN' && item.category < MAX_CATEGORIES) { colors[item.category] = '#cccccc'; } }); @@ -365,8 +365,8 @@ export const BEDEmbeddingView = (props: Props) => { const fieldName = colorGrouping.replace('_category', ''); const query = ` SELECT - CASE WHEN ${colorGrouping} < 20 THEN ${fieldName} ELSE 'Other' END as name, - CASE WHEN ${colorGrouping} < 20 THEN ${colorGrouping} ELSE 20 END as category, + CASE WHEN ${colorGrouping} < ${MAX_CATEGORIES} THEN ${fieldName} ELSE 'Other' END as name, + CASE WHEN ${colorGrouping} < ${MAX_CATEGORIES} THEN ${colorGrouping} ELSE ${MAX_CATEGORIES} END as category, COUNT(*) as count FROM data GROUP BY 1, 2 diff --git a/ui/src/components/umap/embedding-legend.tsx b/ui/src/components/umap/embedding-legend.tsx index 0bf562b9..716fa9c6 100644 --- a/ui/src/components/umap/embedding-legend.tsx +++ b/ui/src/components/umap/embedding-legend.tsx @@ -1,4 +1,4 @@ -import { tableau20 } from "../../utils"; +import { categoryPalette } from "../../utils"; type LegendItem = { category: string; @@ -89,7 +89,7 @@ export const EmbeddingLegend = (props: Props) => { > - + {item.name} {filterSelection?.category === item.category && ( diff --git a/ui/src/components/umap/embedding-plot.tsx b/ui/src/components/umap/embedding-plot.tsx index a9302b0d..5414b90c 100644 --- a/ui/src/components/umap/embedding-plot.tsx +++ b/ui/src/components/umap/embedding-plot.tsx @@ -3,7 +3,7 @@ import { useEffect, useState, useRef, useMemo, forwardRef, useImperativeHandle } import toast from 'react-hot-toast'; import * as vg from '@uwdata/vgplot'; -import { tableau20 } from '../../utils'; +import { categoryPalette } from '../../utils'; import { AtlasTooltip } from './atlas-tooltip'; import { useMosaicCoordinator } from '../../contexts/mosaic-coordinator-context'; @@ -507,7 +507,7 @@ export const EmbeddingPlot = forwardRef((props, ref) => identifier='id' text='name' category={colorGrouping} - categoryColors={tableau20} + categoryColors={categoryPalette} additionalFields={{ Description: 'description', Assay: 'assay', 'Cell Line': 'cell_line', 'Cell Type': 'cell_type' }} height={height || embeddingHeight} width={containerWidth} diff --git a/ui/src/contexts/mosaic-coordinator-context.tsx b/ui/src/contexts/mosaic-coordinator-context.tsx index 41aafeba..324ca8cd 100644 --- a/ui/src/contexts/mosaic-coordinator-context.tsx +++ b/ui/src/contexts/mosaic-coordinator-context.tsx @@ -1,6 +1,7 @@ import { createContext, useContext, useMemo, useRef, ReactNode, useState, useEffect } from 'react'; import * as vg from '@uwdata/vgplot'; import { UMAP_PARQUET_URL } from '../const.ts'; +import { MAX_CATEGORIES } from '../utils'; interface MosaicCoordinatorContextType { getCoordinator: () => vg.Coordinator; @@ -52,9 +53,9 @@ export const MosaicCoordinatorProvider = ({ children }: { children: ReactNode }) FROM data GROUP BY cell_type ) SELECT d.*, - CASE WHEN ac.rank < 20 THEN ac.rank ELSE 20 END AS assay_category, - CASE WHEN cc.rank < 20 THEN cc.rank ELSE 20 END AS cell_line_category, - CASE WHEN ct.rank < 20 THEN ct.rank ELSE 20 END AS cell_type_category + CASE WHEN ac.rank < ${MAX_CATEGORIES} THEN ac.rank ELSE ${MAX_CATEGORIES} END AS assay_category, + CASE WHEN cc.rank < ${MAX_CATEGORIES} THEN cc.rank ELSE ${MAX_CATEGORIES} END AS cell_line_category, + CASE WHEN ct.rank < ${MAX_CATEGORIES} THEN ct.rank ELSE ${MAX_CATEGORIES} END AS cell_type_category FROM data d JOIN assay_counts ac ON d.assay = ac.assay JOIN cell_line_counts cc ON d.cell_line = cc.cell_line diff --git a/ui/src/utils.ts b/ui/src/utils.ts index de4a926e..8d58dbe1 100644 --- a/ui/src/utils.ts +++ b/ui/src/utils.ts @@ -174,7 +174,9 @@ export const convertStatusCodeToMessage = (statusCode: number | undefined) => { } }; -export const tableau20 = [ +export const MAX_CATEGORIES = 40; + +export const categoryPalette = [ '#1f77b4', '#aec7e8', '#ff7f0e', @@ -195,6 +197,26 @@ export const tableau20 = [ '#dbdb8d', '#17becf', '#9edae5', + '#393b79', + '#5254a3', + '#6b6ecf', + '#9c9ede', + '#637939', + '#8ca252', + '#b5cf6b', + '#cedb9c', + '#8c6d31', + '#bd9e39', + '#e7ba52', + '#e7cb94', + '#843c39', + '#ad494a', + '#d6616b', + '#e7969c', + '#7b4173', + '#a55194', + '#ce6dbd', + '#de9ed6', ]; // Point-in-polygon test using ray casting algorithm From 32074afaeaa73659fbe61ba1873e6b646e6c48cc Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Fri, 17 Apr 2026 11:24:28 -0400 Subject: [PATCH 2/3] collor change --- ui/src/utils.ts | 80 ++++++++++++++++++++++++------------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/ui/src/utils.ts b/ui/src/utils.ts index 8d58dbe1..1a49bcb9 100644 --- a/ui/src/utils.ts +++ b/ui/src/utils.ts @@ -177,46 +177,46 @@ export const convertStatusCodeToMessage = (statusCode: number | undefined) => { export const MAX_CATEGORIES = 40; export const categoryPalette = [ - '#1f77b4', - '#aec7e8', - '#ff7f0e', - '#ffbb78', - '#2ca02c', - '#98df8a', - '#d62728', - '#ff9896', - '#9467bd', - '#c5b0d5', - '#8c564b', - '#c49c94', - '#e377c2', - '#f7b6d3', - '#7f7f7f', - '#c7c7c7', - '#bcbd22', - '#dbdb8d', - '#17becf', - '#9edae5', - '#393b79', - '#5254a3', - '#6b6ecf', - '#9c9ede', - '#637939', - '#8ca252', - '#b5cf6b', - '#cedb9c', - '#8c6d31', - '#bd9e39', - '#e7ba52', - '#e7cb94', - '#843c39', - '#ad494a', - '#d6616b', - '#e7969c', - '#7b4173', - '#a55194', - '#ce6dbd', - '#de9ed6', + '#e6194b', + '#3cb44b', + '#4363d8', + '#f58231', + '#911eb4', + '#42d4f4', + '#f032e6', + '#ffe119', + '#bfef45', + '#469990', + '#9a6324', + '#800000', + '#000075', + '#808000', + '#fabed4', + '#aaffc3', + '#ffd8b1', + '#dcbeff', + '#a9a9a9', + '#1a9850', + '#d73027', + '#4575b4', + '#f46d43', + '#762a83', + '#66c2a5', + '#5e4fa2', + '#d53e4f', + '#3288bd', + '#c51b7d', + '#35978f', + '#bf812d', + '#8073ac', + '#e08214', + '#01665e', + '#de77ae', + '#542788', + '#b35806', + '#1b7837', + '#c994c7', + '#daa520', ]; // Point-in-polygon test using ray casting algorithm From 412e40f8dbe124a219a31811a8225fde4f1fc1da Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Fri, 17 Apr 2026 11:39:46 -0400 Subject: [PATCH 3/3] Small umap page improvements --- ui/src/components/umap/embedding-stats.tsx | 2 +- ui/src/const.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/src/components/umap/embedding-stats.tsx b/ui/src/components/umap/embedding-stats.tsx index 10830a8b..a89fd3dc 100644 --- a/ui/src/components/umap/embedding-stats.tsx +++ b/ui/src/components/umap/embedding-stats.tsx @@ -71,7 +71,7 @@ export const EmbeddingStats = (props: Props) => { return (
Selection Count
-
+
{rows.map((row) => { const total = totalCounts.get(row.category) ?? 0; diff --git a/ui/src/const.ts b/ui/src/const.ts index b0d1633d..5c06ca81 100644 --- a/ui/src/const.ts +++ b/ui/src/const.ts @@ -6,7 +6,7 @@ const EXAMPLE_URL = `${API_BASE}/bed/example`; export const UMAP_PARQUET_URL = 'https://huggingface.co/databio/bedbase-umap/resolve/main/hg38_umap_all_3_13.parquet'; -// export const UMAP_PARQUET_URL = `${window.location.origin}/test_big_3_13.parquet`; +// export const UMAP_PARQUET_URL = `${window.location.origin}/hg38_umap_all_3_13.parquet`; // Legacy JSON URL (kept for backward compatibility) export const UMAP_URL = 'https://huggingface.co/databio/bedbase-umap/resolve/main/hg38_umap_3_13.json';