Everything online I found for plotly.js is using plotly python which doesn’t help me too much since I need it in JS, python also seems to use additional libraries. I created a function that plots it
export const RenderUmapPlotsData = (csv, runid, camera) => {
try {
const getPlotColor = index => {
switch (index) {
case 0:
return '#FF4500'; // OrangeRed
case 1:
return '#32CD32'; // LimeGreen
case 2:
return '#1E90FF'; // DodgerBlue
case 3:
return '#FFD700'; // Gold
case 4:
return '#4B0082'; // Indigo
case 5:
return '#FF1493'; // DeepPink
case 6:
return '#00CED1'; // DarkTurquoise
case 7:
return '#FF6347'; // Tomato
case 8:
return '#ADFF2F'; // GreenYellow
case 9:
return '#8A2BE2'; // BlueViolet
case 10:
return '#00FF7F'; // SpringGreen
case 11:
return '#8B0000'; // DarkRed
case 12:
return '#B8860B'; // DarkGoldenRod
case 13:
return '#4682B4'; // SteelBlue
case 14:
return '#D2691E'; // Chocolate
case 15:
return '#DA70D6'; // Orchid
case 16:
return '#5F9EA0'; // CadetBlue
case 17:
return '#7FFF00'; // Chartreuse
case 18:
return '#DC143C'; // Crimson
case 19:
return '#FF8C00'; // DarkOrange
case 20:
return '#9932CC'; // DarkOrchid
case 21:
return '#00BFFF'; // DeepSkyBlue
case 22:
return '#228B22'; // ForestGreen
case 23:
return '#FF00FF'; // Fuchsia
default:
return '#000000'; // Black
}
};
const getRunIdByCamera = (runid) => {
return runid?.split('_')[0] || runid
}
const y = csv.map(item => item.y);
const barcodes = csv.map(item => item.barcode)
const X_umap_0 = csv.flatMap(item => item.X_umap_0);
const X_umap_1 = csv.flatMap(item => item.X_umap_1);
const xMin = [
Math.min(...X_umap_0),
Math.min(...X_umap_1)
];
const xMax = [
Math.max(...X_umap_0),
Math.max(...X_umap_1)
];
const X = csv.map(item => [
item.X_umap_0.map(val => (val - xMin[0]) / (xMax[0] - xMin[0])),
item.X_umap_1.map(val => (val - xMin[1]) / (xMax[1] - xMin[1]))
]);
const uniqueY = Array.from(new Set(y));
const data = uniqueY.map((j, idx) => {
const existingBarcodeName = barcodes.find((_, i) => y[i] === j);
const name = existingBarcodeName ? existingBarcodeName : j === -1 ? 'unidentified barcode / failed quality RSQ' : j.toString();
const trace = {
x: [],
y: [],
mode: 'markers',
marker: {
color: idx === -1 ? 'black' : getPlotColor(idx),
size: 6,
symbol: 'circle',
},
name: idx === -1 ? 'unidentified barcode / failed quality RSQ' : name,
type: 'scatter',
};
X.forEach((item, index) => {
if (y[index] === j) {
trace.x.push(item[0][0]);
trace.y.push(item[1][0]);
}
});
return trace;
});
const layout = {
title: `UMAP Projection ${getRunIdByCamera(runid)} ${camera}`,
xaxis: {
visible: true,
},
yaxis: {
visible: true,
},
legend: {
x: 1.1,
y: 1,
font: {
size: 15,
},
},
};
const dataUmap = data;
const config = {
modeBarButtonsToRemove: ['sendDataToCloud', 'displaylogo', 'pan2d', 'pan3d', 'autoScale2d', 'resetScale2d'],
displaylogo: false,
displayModeBar: true
};
return { data: dataUmap, layout: layout, config: config };
} catch (e) {
console.log(e)
return undefined;
}
}
I spoke to the Algorithms Developer that assigned me the ticket and he sent me this code block in python that is the logic to plot it
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
def plot_Umap(df_Umap, df_existing_barcodes=None, runID=""):
X = np.stack([df_Umap["X_umap_0"], df_Umap["X_umap_1"]], axis=1)
y = df_Umap["Y"]
x_min, x_max = np.min(X, 0), np.max(X, 0)
X = (X - x_min) / (x_max - x_min)
cmap = plt.cm.get_cmap("tab20b", len(np.unique(y)))
fig = plt.figure(figsize=(12, 6))
for idx, j in enumerate(np.unique(y)):
if (df_existing_barcodes is not None) & np.any(df_existing_barcodes.values == j):
barcode_name = df_existing_barcodes[(df_existing_barcodes.values == j)].index[0]
else:
barcode_name = str(j)
if j == -1:
plt.plot(
X[(y == -1), 0],
X[(y == -1), 1],
".",
color="black",
markersize=2,
label="unidentified barcode n / failed quality RSQ",
)
else:
plt.plot(X[(y == j), 0], X[(y == j), 1], ".", color=cmap(idx), markersize=2, label=" " + barcode_name)
plt.xticks([])
plt.yticks([])
title = set_title("UMAP", runID)
plt.title(title, fontsize=20)
plt.legend(fontsize=15, markerscale=5, bbox_to_anchor=(1.1, 1), loc="upper left")
So with my RenderUmapPlotsData(), it’s the converted python code. But I got a single scatter point for each key, I was expecting multiple per key. I don’t use python so I am not sure if I accurately converted the logic or if the matplotlib.pyplot python library plots it differently from plotly.js.
Data structure I’m sending to the plot is
data: [
{
“barcode”: “TT”,
“y”: 1018,
“X_umap_0”: [5.633621096611023, 5.426720380783081, 5.546037912368774, 5.689118146896362, …],
“X_umap_1”: [ 4.7906142473220825, 4.880273103713989, 4.7140690088272095, 5.0658169984817505, …],
},
{
“barcode”: “Z0115”,
“y”: 940,
“X_umap_0”: [0.8259536474943161, 0.72834712266922, 1.5240634679794312, 0.7071684952825308, …],
“X_umap_1”: [3.501920700073242, 4.718092381954193, 2.6759512424468994, 3.722422480583191, …],
},
]
Data structure being sent to pythons plot_Umap is
Output I got:
Output I was expecting: