Skip to content

Commit

Permalink
Merge pull request #85 from Imageomics/hover-details
Browse files Browse the repository at this point in the history
Highlight weights on hover
  • Loading branch information
johnbradley authored Feb 9, 2024
2 parents 620050b + 98e3d3c commit db3aa99
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 17 deletions.
11 changes: 10 additions & 1 deletion andromeda-ui/components/DataExplorer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ interface DataExplorerProps {
weights: any | undefined;
datasetID: string | undefined;
columnSettings: any;
columnDetails: any;
drFunc: any;
rdrFunc: any;
onClickBack: any;
Expand All @@ -27,14 +28,15 @@ interface DataExplorerProps {

export default function DataExplorer(props: DataExplorerProps) {
const { images, setImageData, pointScaling, setPointScaling,
weights, datasetID, columnSettings,
weights, datasetID, columnSettings, columnDetails,
drFunc, rdrFunc, onClickBack } = props;
const [imageSize, setImageSize] = useState<number>(DEFAULT_IMAGE_SIZE);
const [showLabel, setShowLabel] = useState<boolean>(true);
const [showImage, setShowImage] = useState<boolean>(true);
const [sliderWeights, setSliderWeights] = useState<any>(weights);
const [working, setWorking] = useState<boolean>(false);
const stageRef = useRef<any>(null);
const [highlightImageKey, setHighlightImageKey] = useState<string>();

function onImageMoved(x: number, y: number, label: string) {
if (images) {
Expand All @@ -55,9 +57,15 @@ export default function DataExplorer(props: DataExplorerProps) {
}

if (weights) {
let highlightValues: {[key:string]: number} = {}
if (highlightImageKey) {
highlightValues = images.find((x) => x.label == highlightImageKey).values;
}

weightControls = Object.keys(weights).map(key => <WeightSlider
key={key}
id={key}
highlight={highlightValues[key]}
weights={sliderWeights}
onChange={(evt: any) => onChangeWeight(key, parseFloat(evt.target.value))} />);
}
Expand Down Expand Up @@ -128,6 +136,7 @@ export default function DataExplorer(props: DataExplorerProps) {
showImage={showImage}
onImageMoved={onImageMoved}
images={images}
setHighlightImageKey={setHighlightImageKey}
/>
<div className="flex gap-2 my-2 mr-2">
<ColoredButton
Expand Down
4 changes: 4 additions & 0 deletions andromeda-ui/components/ImageGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ interface ImageGridProps {
showLabel: boolean;
showImage: boolean;
onImageMoved: any;
setHighlightImageKey: any;
images: any[];
}

Expand Down Expand Up @@ -55,10 +56,13 @@ export default function ImageGrid(props: ImageGridProps) {
const { stageRef, size, imageSize, pointScaling, showLabel, showImage, images } = props;
function onMouseEnter(evt: any) {
stageRef.current.container().style.cursor = 'move';
const dataLabel = evt.currentTarget.attrs["data-label"];
props.setHighlightImageKey(dataLabel);
}

function onMouseLeave(evt: any) {
stageRef.current.container().style.cursor = 'grab';
props.setHighlightImageKey(undefined);
}

const imageControls = images.map(item => createImage(
Expand Down
39 changes: 26 additions & 13 deletions andromeda-ui/components/WeightSlider.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,37 @@
interface WeightSliderProps {
id: string;
weights: any;
highlight: number | undefined;
onChange: any;
}

export default function WeightSlider({ id, weights, onChange }: WeightSliderProps) {
const value = weights[id];
const SLIDER_WIDTH = 200;


export default function WeightSlider({ id, weights, highlight, onChange }: WeightSliderProps) {
const value = weights[id];
let highlightDiv = null;
if (highlight !== undefined) {
const hintPosition = highlight * (SLIDER_WIDTH - 4);
highlightDiv = <div className="absolute left-2 top-1 inline w-1 bg-cyan-600 h-3" style={{"left": hintPosition + "px"}}>
&nbsp;
</div>;
}
return <div key={id} className="flex flex-nowrap">
<input
type="range"
id={id}
name={id}
value={value}
onChange={onChange}
min="0.001"
max="0.999"
step="0.001"
className="w-60"
></input>
<div className="relative">
<input
type="range"
id={id}
name={id}
value={value}
onChange={onChange}
min="0.001"
max="0.999"
step="0.001"
style={{"width": SLIDER_WIDTH + "px"}}
></input>
{highlightDiv}
</div>
&nbsp;
<label htmlFor="volume">{id}</label>
</div>
Expand Down
17 changes: 15 additions & 2 deletions andromeda/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import pandas as pd
from flask import abort
import andromeda
from sklearn.preprocessing import MinMaxScaler


class DatasetStore(object):
Expand Down Expand Up @@ -75,6 +76,14 @@ def get_normalized_dataframe(self):

return df[self.selected_columns]

def get_min_max_scaled_dataframe(self):
df = self.read_dataframe()
df.set_index(self.label_column_name, inplace=True)
df = df.select_dtypes('number')
scaler = MinMaxScaler()
df[df.columns] = scaler.fit_transform(df[df.columns])
return df

def get_label_to_url(self):
df = self.read_dataframe()
return dict(zip(df[self.label_column_name], df[self.url_column_name]))
Expand All @@ -92,9 +101,13 @@ def dimensional_reduction(self, weights):
image_coordinate_df = andromeda.dimension_reduction(
normalized_df, weight_series
)

self.add_label_and_url_columns(image_coordinate_df)
return weight_series.to_dict(), image_coordinate_df.to_dict("records")
min_max_dataframe = self.get_min_max_scaled_dataframe()
coordinate_dict_ary = image_coordinate_df.to_dict("records")
for item in coordinate_dict_ary:
series = min_max_dataframe.loc[item['label']]
item['values'] = series.to_dict()
return weight_series.to_dict(), coordinate_dict_ary

@staticmethod
def create_weight_series(weights, columns):
Expand Down
4 changes: 3 additions & 1 deletion andromeda/tests/test_dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,11 @@ def fake_get_path():

self.assertEqual(weights.keys(), set(["R1", "B1", "G1"]))
self.assertEqual(len(image_coordinates), 3)
self.assertEqual(image_coordinates[0].keys(), set(["x", "y", "label", "url"]))
self.assertEqual(image_coordinates[0].keys(), set(["x", "y", "label", "url", "values"]))
self.assertEqual(image_coordinates[0]["label"], "p1")
self.assertEqual(image_coordinates[0]["url"], "https://example.com/p1.jpg")
self.assertEqual(image_coordinates[0]["values"].keys(), set(["R1", "B1", "G1"]))
self.assertEqual(image_coordinates[0]["values"]["B1"], 0.2)
self.assertEqual(image_coordinates[1]["url"], "")

@patch('dataset.os')
Expand Down

0 comments on commit db3aa99

Please sign in to comment.