Skip to content

Commit

Permalink
added markers and ugly popup
Browse files Browse the repository at this point in the history
  • Loading branch information
Yukthiw committed Jul 29, 2024
1 parent 2ef5bb2 commit e967842
Show file tree
Hide file tree
Showing 6 changed files with 225 additions and 69 deletions.
47 changes: 47 additions & 0 deletions Eplant/views/WorldEFP/InfoContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { styled } from '@mui/material'

interface InfoContentProps {
id: string
mean: number
std: number
sample_size: number
pos: { x: number; y: number }
}

const InfoContent = ({ id, mean, std, sample_size, pos }: InfoContentProps) => {
return (
<StyledInfoContent x={pos.x} y={pos.y}>
<p>
<strong>{id}</strong>
</p>
<p>Mean: {mean}</p>
<p>Standard error: {std}</p>
<p>Sample size: {sample_size}</p>
</StyledInfoContent>
)
}

const StyledInfoContent = styled('div')<{ x: number; y: number }>(
({ theme, x, y }) => ({
position: 'absolute',
top: y,
left: x,
border: '1px solid #ccc',
backgroundColor: theme.palette.background.active,
padding: '10px',
borderRadius: '10px',
boxShadow: '0 0 10px rgba(0, 0, 0, 0.1)',
transform: 'translate(-50%, -50%)',
maxWidth: '200px',
width: '200px',
'& p': {
margin: '5px 0',
},
'& strong': {
display: 'block',
marginBottom: '10px',
},
})
)

export default InfoContent
72 changes: 64 additions & 8 deletions Eplant/views/WorldEFP/MapContainer.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,85 @@
import { MouseEvent, useState } from 'react'
import { random } from 'lodash'

import { AdvancedMarker, APIProvider, Map } from '@vis.gl/react-google-maps'
import { useTheme } from '@mui/material'
import {
AdvancedMarker,
APIProvider,
InfoWindow,
Map,
useAdvancedMarkerRef,
} from '@vis.gl/react-google-maps'

import WorldEFPIcon from './icon'
import { WorldEFPData, WorldEFPState } from './types'
import InfoContent from './InfoContent'
import { Coordinates, WorldEFPData, WorldEFPState } from './types'
import { getWorldEFPColour } from './utils'

interface MapContainerProps {
activeData: WorldEFPData
state: WorldEFPState
}
const MapContainer = ({ activeData, state }: MapContainerProps) => {
const defaultCenter = { lat: 49, lng: 11 }
const theme = useTheme()
const [infoWindowShown, setInfoWindowShown] = useState(false)
const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 })

const handleMouseOver = (event: MouseEvent<HTMLDivElement>) => {
console.log('yo')
setInfoWindowShown(true)
setMousePosition({
x: event.clientX,
y: event.clientY,
})
}

const handleMouseOut = (event: MouseEvent<HTMLDivElement>) => {
setInfoWindowShown(false)
setMousePosition({
x: 0,
y: 0,
})
}
return (
<APIProvider apiKey={import.meta.env.VITE_MAPS_API_KEY}>
<APIProvider apiKey={import.meta.env.VITE_MAPS_API_KEY} version='beta'>
<Map
defaultCenter={defaultCenter}
defaultZoom={10}
mapId={import.meta.env.VITE_MAP_ID}
>
{activeData.positions.map((e, index) => {
const colour = index === 0 ? 'red' : 'yellow'
{activeData.positions.map((pos, index) => {
const colour = getWorldEFPColour(
theme,
activeData.efpData[index].mean,
activeData.efpMax
)
return (
<AdvancedMarker key={index} position={e}>
<WorldEFPIcon sx={{ fill: colour }}></WorldEFPIcon>
</AdvancedMarker>
<>
<AdvancedMarker key={index} position={pos}>
<div
onMouseOver={handleMouseOver}
onMouseLeave={handleMouseOut}
style={{
width: 24,
height: 24,
position: 'absolute',
opacity: 1,
backgroundColor: 'white',
}}
></div>
<WorldEFPIcon sx={{ fill: colour }}></WorldEFPIcon>
</AdvancedMarker>
{infoWindowShown && (
<InfoContent
id={'asd'}
mean={12}
std={12}
sample_size={12}
pos={mousePosition}
></InfoContent>
)}
</>
)
})}
</Map>
Expand Down
39 changes: 39 additions & 0 deletions Eplant/views/WorldEFP/WorldEFPPopper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { Popper } from '@mui/material'

Check failure on line 1 in Eplant/views/WorldEFP/WorldEFPPopper.tsx

View workflow job for this annotation

GitHub Actions / lint-and-format

Run autofix to sort these imports!
import { useState } from 'react'

export default function WorldEFPPopper() {
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null)

const handleClick = (event: React.MouseEvent<HTMLElement>) => {
setAnchorEl(anchorEl ? null : event.currentTarget)
}

const open = Boolean(anchorEl)
const id = open ? 'simple-popper' : undefined

return (
<div>
<Popper id={id} open={open} anchorEl={anchorEl}>
<StyledPopperDiv>The content of the Popper.</StyledPopperDiv>
</Popper>
</div>
)
}

const StyledPopperDiv = styled('div')(

Check failure on line 23 in Eplant/views/WorldEFP/WorldEFPPopper.tsx

View workflow job for this annotation

GitHub Actions / build

Cannot find name 'styled'.
({ theme }) => css`

Check failure on line 24 in Eplant/views/WorldEFP/WorldEFPPopper.tsx

View workflow job for this annotation

GitHub Actions / build

Binding element 'theme' implicitly has an 'any' type.

Check failure on line 24 in Eplant/views/WorldEFP/WorldEFPPopper.tsx

View workflow job for this annotation

GitHub Actions / build

Cannot find name 'css'. Did you mean 'CSS'?
background-color: ${theme.palette.mode === 'dark' ? grey[900] : '#fff'};

Check failure on line 25 in Eplant/views/WorldEFP/WorldEFPPopper.tsx

View workflow job for this annotation

GitHub Actions / build

Cannot find name 'grey'.
border-radius: 8px;
border: 1px solid ${theme.palette.mode === 'dark' ? grey[700] : grey[200]};

Check failure on line 27 in Eplant/views/WorldEFP/WorldEFPPopper.tsx

View workflow job for this annotation

GitHub Actions / build

Cannot find name 'grey'.

Check failure on line 27 in Eplant/views/WorldEFP/WorldEFPPopper.tsx

View workflow job for this annotation

GitHub Actions / build

Cannot find name 'grey'.
box-shadow: ${theme.palette.mode === 'dark'
? `0px 4px 8px rgb(0 0 0 / 0.7)`
: `0px 4px 8px rgb(0 0 0 / 0.1)`};
padding: 0.75rem;
color: ${theme.palette.mode === 'dark' ? grey[100] : grey[700]};

Check failure on line 32 in Eplant/views/WorldEFP/WorldEFPPopper.tsx

View workflow job for this annotation

GitHub Actions / build

Cannot find name 'grey'.

Check failure on line 32 in Eplant/views/WorldEFP/WorldEFPPopper.tsx

View workflow job for this annotation

GitHub Actions / build

Cannot find name 'grey'.
font-size: 0.875rem;
font-family: 'IBM Plex Sans', sans-serif;
font-weight: 500;
opacity: 1;
margin: 0.25rem 0;
`
)
96 changes: 37 additions & 59 deletions Eplant/views/WorldEFP/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import _ from 'lodash'
import _, { max, mean } from 'lodash'

import GeneticElement from '@eplant/GeneticElement'
import { View, ViewProps } from '@eplant/View'
Expand All @@ -8,8 +8,14 @@ import { getEFPSampleData } from '../eFP'
import { EFPData, EFPGroup, EFPTissue } from '../eFP/types'

import MapContainer from './MapContainer'
import { Coordinates, WorldEFPData, WorldEFPState } from './types'
const WorldEFP: View<any, WorldEFPState, any> = {
import {
Coordinates,
WorldEFPData,
WorldEFPGroupData,
WorldEFPMicroArrayResponse,
WorldEFPState,
} from './types'
const WorldEFP: View<WorldEFPData, WorldEFPState, any> = {
name: 'World-EFP',
id: 'World-EFP',
getInitialState() {
Expand All @@ -28,9 +34,11 @@ const WorldEFP: View<any, WorldEFPState, any> = {
loadEvent: (progress: number) => void
) {
if (!gene) throw ViewDataError.UNSUPPORTED_GENE
const markersURL =
'https://private-1e099f-eplant3.apiary-mock.com/microarray_gene_expression/world_efp/At1g01010'
const markerData = await fetch(markersURL)
const microArrayDataURL =
'https://bar.utoronto.ca/api_dev/microarray_gene_expression/world_efp/arabidopsis/At1g01010'
const microArrayData: WorldEFPMicroArrayResponse = await fetch(
microArrayDataURL
)
.then((response) => {
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`)
Expand All @@ -42,63 +50,34 @@ const WorldEFP: View<any, WorldEFPState, any> = {
throw error
})

const positions: Coordinates[] = markerData.map((e) => {
return {
lat: parseFloat(e.position.lat),
lng: parseFloat(e.position.lng),
const positions: Coordinates[] = []
const groupData: WorldEFPGroupData[] = []

Object.entries(microArrayData.data).forEach(([key, marker]) => {
// Coordinates
positions.push({
lat: parseFloat(marker.position.lat),
lng: parseFloat(marker.position.lng),
})

// Sample data
const efpGroupData = {
name: marker.id,
id: key,
mean: mean(Object.values(marker.values)),
}

groupData.push(efpGroupData)
})
console.log(positions)
const groupData: EFPGroup[] = []
// markerData.foreach(
// (group: {
// id: string
// source: string
// position: { lat: string; lng: string }
// samples: [string, number][]
// ctrlSamples: [string, number][]
// }) => {
// const samples = group.samples.map((v) => v[1])
// const ctrls = group.ctrlSamples.map((v) => v[1])
// const sampleTissue = {
// name: group.id,
// id: group.id,
// ...getEFPSampleData(samples),
// } as EFPTissue
// const tissueValue = sampleTissue.mean
// const ctrlValue = _.mean(ctrls)
// groupData.push({
// name: group.id,
// control: Number.isFinite(ctrlValue) ? ctrlValue : undefined,
// tissues: [sampleTissue],
// ...getEFPSampleData([tissueValue]),
// })
// }
// )

// const efpData: EFPData = {
// groups: groupData,
// control: _.mean(
// groupData
// .map((g) => g.control)
// .filter((g: unknown) => Number.isFinite(g))
// ),
// min: Math.min(...groupData.map((g: { min: any }) => g.min)),
// max: Math.max(...groupData.map((g: { max: any }) => g.max)),
// mean: _.mean(groupData.map((g: { mean: any }) => g.mean)),
// std:
// _.sum(
// groupData.map(
// (g: { std: number; samples: number }) => g.std ** 2 * g.samples
// )
// ) / _.sum(groupData.map((g: { samples: any }) => g.samples)),
// samples: _.sum(groupData.map((g: { samples: any }) => g.samples)),
// supported:
// Number.isFinite(_.mean(groupData.map((g: { mean: any }) => g.mean))) &&
// groupData.length > 0,
// }
const groupMax = groupData.reduce((extremum, group) => {
return group.mean > extremum ? group.mean : extremum
}, -Infinity)

return {
positions: positions,
efpData: groupData,
efpMax: groupMax,
}
},
component({
Expand All @@ -108,7 +87,6 @@ const WorldEFP: View<any, WorldEFPState, any> = {
}: ViewProps<WorldEFPData, WorldEFPState, any>) {
if (!geneticElement) return <></>
return <MapContainer activeData={activeData} state={state}></MapContainer>
// else return <div>hi</div>
},
icon: () => <div></div>,
description: 'Find publications that mention your gene of interest.',
Expand Down
28 changes: 26 additions & 2 deletions Eplant/views/WorldEFP/types.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { ColorMode, EFPData } from '../eFP/types'

export type Coordinates = { lat: number; lng: number }

type MapTypeId = 'roadmap' | 'satellite' | 'hybrid' | 'terrain'

export type WorldEFPState = {
position: Coordinates
zoom: number
Expand All @@ -14,6 +16,28 @@ export type WorldEFPState = {

export type WorldEFPData = {
positions: Coordinates[]
efpData: EFPData
markerSVGString: string
efpData: WorldEFPGroupData[]
efpMax: number
}

export interface WorldEFPMicroArrayResponse {
wasSuccessful: boolean
data: { [key: string]: WorldEFPMicroArrayData }
}

export interface WorldEFPMicroArrayData {
source: string
id: string
samples: string[]
ctrlSamples: string[]
position: { lat: string; lng: string }
probeset: string
values: { [key: string]: number }
code: string
}

export interface WorldEFPGroupData {
name: string
id: string
mean: number
}
12 changes: 12 additions & 0 deletions Eplant/views/WorldEFP/utils.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { mix } from 'color2k'

import { Theme } from '@mui/material'

export const getWorldEFPColour = (theme: Theme, value: number, max: number) => {
const ratio = value / max
return mix(
theme.palette.neutral.main,
theme.palette.hot.main,
Math.abs(ratio)
)
}

0 comments on commit e967842

Please sign in to comment.