Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

try vis #606

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
154 changes: 100 additions & 54 deletions taxonium_component/src/components/Key.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import prettifyName from "../utils/prettifyName";
import { useState } from "react";
import React, { useState, useEffect } from "react";
import classNames from "classnames";
import prettifyName from "../utils/prettifyName";

const Key = ({
keyStuff,
colorByField,
Expand All @@ -14,31 +15,80 @@ const Key = ({
}) => {
const numLegendEntries = 10;
const [collapsed, setCollapsed] = useState(window.innerWidth < 800);
// sort by item.count in descending order
const sortedKeyStuff = keyStuff.sort((a, b) => b.count - a.count);
// truncate to 10 items
const isTruncated = sortedKeyStuff.length > numLegendEntries;
const topTenKeyStuff = sortedKeyStuff.slice(0, numLegendEntries);
// if there is an item with value of "", remove it
const filteredKeyStuff = topTenKeyStuff.filter((item) => item.value !== "");
if (colorByField === "None") {
return null;
}
if (!filteredKeyStuff || filteredKeyStuff.length == 0) {
const [colorRamp, setColorRamp] = useState(null);

useEffect(() => {
if (config.colorRamps && config.colorRamps[colorByField]) {
setColorRamp(config.colorRamps[colorByField]);
} else {
setColorRamp(null);
}
}, [colorByField, config.colorRamps]);

if (colorByField === "None" || !keyStuff || keyStuff.length === 0) {
return null;
}

const sortedKeyStuff = keyStuff
.sort((a, b) => b.count - a.count)
.filter((item) => item.value !== "");
const isTruncated = sortedKeyStuff.length > numLegendEntries;
const topKeyStuff = sortedKeyStuff.slice(0, numLegendEntries);

const ColorRampScale = ({ colorRamp }) => {
const { scale } = colorRamp;
const minValue = scale[0][0];
const maxValue = scale[scale.length - 1][0];
const range = maxValue - minValue;

const getPositionPercentage = (value) => {
return ((value - minValue) / range) * 100;
};

const gradientStops = scale
.map(([value, color]) => {
const percentage = getPositionPercentage(value);
return `${color} ${percentage}%`;
})
.join(", ");

return (
<div className="w-full h-32 relative mt-2">
<div
className="w-4 h-full absolute right-0"
style={{
background: `linear-gradient(to bottom, ${gradientStops})`,
}}
/>
<div className="absolute left-0 right-6 h-full">
{scale.map(([value, color], index) => {
const positionPercentage = getPositionPercentage(value);
return (
<div
key={index}
className="absolute right-6 text-xs text-gray-700 transform -translate-y-1/2"
style={{ top: `${positionPercentage}%` }}
>
<span className="mr-1">{value}</span>
<div
className="w-2 h-0.5 inline-block"
style={{ backgroundColor: color }}
/>
</div>
);
})}
</div>
</div>
);
};

return (
<div
className={classNames(
"px-2 border-right border bg-white opacity-90 absolute bottom-2 left-2 pt-1 pb-2",
collapsed ? "w-20" : "w-32"
"px-2 border-right border bg-white opacity-90 absolute bottom-2 left-2 pt-1 pb-2",
collapsed ? "w-20" : colorRamp ? "w-40" : "w-32"
)}
// z index big
style={{
zIndex: 10,

cursor: "default",
}}
style={{ zIndex: 10, cursor: "default" }}
>
<h3
className="font-bold text-gray-600 text-xs cursor-pointer"
Expand All @@ -47,47 +97,43 @@ const Key = ({
{collapsed
? "Key"
: colorByField === "genotype"
? colorByGene + ":" + colorByPosition
? `${colorByGene}:${colorByPosition}`
: prettifyName(colorByField, config)}
{/* Arrow to collapse up/down */}
<span className="float-right text-xs cursor-pointer text-gray-600">
{collapsed ? "▲" : "▼"}
</span>
</h3>
{!collapsed && (
<>
{filteredKeyStuff.map((item, index) => {
// item.color is [r, g, b]
const rgb = item.color;
const color = `rgb(${rgb[0]}, ${rgb[1]}, ${rgb[2]})`;
return (
<div
className="key-text text-xs text-gray-700 mt-0.5 break-all cursor-pointer"
key={index}
style={{
pointerEvents: "auto",
}}
onClick={() => {
setCurrentColorSettingKey(item.value);
setColorSettingOpen(true);
}}
onMouseEnter={() => {
setHoveredKey(item.value);
}}
onMouseLeave={() => setHoveredKey(null)}
title="Edit color"
>
{colorRamp ? (
<ColorRampScale colorRamp={colorRamp} />
) : (
topKeyStuff.map((item, index) => {
const rgb = item.color;
const color = `rgb(${rgb[0]}, ${rgb[1]}, ${rgb[2]})`;
return (
<div
style={{ backgroundColor: color }}
className={`circle w-2 h-2 mr-2 rounded-full inline-block transform transition-transform ${
hoveredKey === item.value ? "scale-150" : "scale-100"
}`}
/>
{item.value}
</div>
);
})}

className="key-text text-xs text-gray-700 mt-0.5 break-all cursor-pointer"
key={index}
onClick={() => {
setCurrentColorSettingKey(item.value);
setColorSettingOpen(true);
}}
onMouseEnter={() => setHoveredKey(item.value)}
onMouseLeave={() => setHoveredKey(null)}
title="Edit color"
>
<div
style={{ backgroundColor: color }}
className={`circle w-2 h-2 mr-2 rounded-full inline-block transform transition-transform ${
hoveredKey === item.value ? "scale-150" : "scale-100"
}`}
/>
{item.value}
</div>
);
})
)}
{isTruncated && <div className="text-xs text-gray-700">...</div>}
</>
)}
Expand Down
Loading