Skip to content
Open
Show file tree
Hide file tree
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
98 changes: 51 additions & 47 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,54 +20,54 @@ jobs:
python-version: ["3.12"]

steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v6

- name: Setup pnpm (v5.0.0)
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320
with:
run_install: |
args: [ --force ]
- name: Setup pnpm (v5.0.0)
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320
with:
run_install: |
args: [ --force ]

- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
cache: pnpm
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
cache: pnpm

- name: Run Typescript tests and lint client code
run: |
pnpm lint
pnpm lint:tsc
pnpm build
pnpm test
- name: Run Typescript tests and lint client code
run: |
pnpm lint
pnpm lint:tsc
pnpm build
pnpm test

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
- name: Install server dependencies
run: |
python -m pip install --upgrade pip
python -m pip install ruff
if [ -f server/requirements.txt ]; then pip install -r server/requirements.txt; fi
- name: Lint with ruff
run: |
# stop the build if there are Python syntax errors or undefined names
ruff check server --select=E9,F63,F7,F82 --output-format=full
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
ruff check server --exit-zero --line-length=127 --statistics
- name: Test with pytest
run: |
pytest -vvv server/davidia/tests/
- name: Build sdist and wheel
run: |
pipx run build server
pipx run build server/example-client --outdir server/dist
- name: Upload sdist and wheel as artifacts
uses: actions/upload-artifact@v6
with:
name: dist
path: server/dist
- name: Setup Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
- name: Install server dependencies
run: |
python -m pip install --upgrade pip
python -m pip install ruff
if [ -f server/requirements.txt ]; then pip install -r server/requirements.txt; fi
- name: Lint with ruff
run: |
# stop the build if there are Python syntax errors or undefined names
ruff check server --select=E9,F63,F7,F82 --output-format=full
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
ruff check server --exit-zero --line-length=127 --statistics
- name: Test with pytest
run: |
pytest -vvv server/davidia/tests/
- name: Build sdist and wheel
run: |
pipx run build server
pipx run build server/example-client --outdir server/dist
- name: Upload sdist and wheel as artifacts
uses: actions/upload-artifact@v7
with:
name: dist
path: server/dist

pypi:
# Upload to PyPI and make a release on every tag
Expand All @@ -85,7 +85,11 @@ jobs:

steps:
# Download sdist and wheel from dist job
- uses: actions/download-artifact@v7
- uses: actions/download-artifact@v8
with:
path: dist
- name: Display structure of downloaded files
run: ls -R
# Publish to PyPI using trusted publishing
- name: Publish to PyPI (v1.13.0)
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e
- name: Publish to PyPI (v1.14.0)
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,6 @@ dmypy.json
**/node_modules
/.pnp
.pnp.js
pnpm-lock.yaml

# testing
/coverage
Expand Down
14 changes: 10 additions & 4 deletions DEVELOP.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,17 @@ Build web client

### `pnpm build`

## Quick start

To run everything quickly for a demo

### `PYTHONPATH=server python -c 'from demos.simple import start_and_run_all_demos; start_and_run_all_demos()'`

## Running Python plot server

From the top level of the repository, you can run:

### `cd server && uvicorn --factory davidia.main:create_app` or `PYTHONPATH=server python server/davidia/main.py -c`
### `cd server && uvicorn --port 8000 --factory davidia.main:create_app` or `PYTHONPATH=server python -m davidia.main -P 8000 -c`

Open [localhost:8000](http://localhost:8000) to view it in the browser. Now test plot server with,

Expand All @@ -30,9 +36,9 @@ Open [localhost:8000](http://localhost:8000) to view it in the browser. Now test

Set the environment variable `DVD_BENCHMARK` as `on` or add a `-b` argument:

### `cd server && DVD_BENCHMARK=on uvicorn --factory davidia.main:create_app`
### `DVD_BENCHMARK=on PYTHONPATH=server python server/davidia/main.py`
### `PYTHONPATH=server python server/davidia/main.py -c -b`
### `cd server && DVD_BENCHMARK=on uvicorn --port 8000 --factory davidia.main:create_app`
### `DVD_BENCHMARK=on PYTHONPATH=server python -m davidia.main -P 8000 -c`
### `PYTHONPATH=server python -m davidia.main -P 8000 -c -b`

Run the script to trigger benchmarks:

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import reactRefresh from 'eslint-plugin-react-refresh';
import globals from 'globals';

import base from '../../eslint.config.mjs';
import base from '../../eslint.config.js';

export default [
...base,
Expand Down
2 changes: 1 addition & 1 deletion client/component/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,6 @@
"three": ">=0.182.0",
"typedoc": "^0.28.15",
"vite-plugin-dts": "^4.5.4",
"vitest": "^4.0.15"
"vitest": "^4.1.1"
}
}
4 changes: 1 addition & 3 deletions client/component/src/AnyPlot.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import afterFrame from 'afterframe';
import { useRef } from 'react';

import { HeatmapVisCanvas } from './HeatmapPlot';
import type { HeatmapPlotProps } from './HeatmapPlot';
Expand Down Expand Up @@ -64,10 +63,9 @@ function AnyVisCanvas(props: AnyPlotProps) {
* @returns {JSX.Element} The rendered component.
*/
function AnyPlot(props: AnyPlotProps) {
const interactionTime = useRef<number>(0);
const interaction = measureInteraction();
afterFrame(() => {
interactionTime.current = interaction.end();
interaction.end();
});

if ('cellWidth' in props) {
Expand Down
24 changes: 13 additions & 11 deletions client/component/src/AspectConfigModal.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { type Aspect, ToggleGroup } from '@h5web/lib';
import { useEffect, useRef, useState } from 'react';
import { useState } from 'react';
import type { PropsWithChildren } from 'react';
import { MdAspectRatio } from 'react-icons/md';

Expand Down Expand Up @@ -29,18 +29,20 @@ interface AspectConfigModalProps {
*/
function AspectConfigModal(props: PropsWithChildren<AspectConfigModalProps>) {
const { aspect: initAspect, setAspect, children } = props;
const typeRef = useRef('number');
const [aspectType, setAspectType] = useState('number');
const [aspectRatio, setAspectRatio] = useState<number>(2.0);

useEffect(() => {
const initType = getAspectType(initAspect);
console.log('Set initial type', initType, initAspect);
typeRef.current = initType;
setAspectRatio(initType === 'number' ? (initAspect as number) : 2.0);
}, [initAspect]);
const initType = getAspectType(initAspect);
console.log('Set initial type', props);
if (initType != aspectType) {
setAspectType(initType);
if (initType === 'number') {
setAspectRatio(initAspect as number);
}
}

function handleAspectTypeChange(val: string) {
typeRef.current = val;
setAspectType(val);
if (val === 'number') {
setAspect(aspectRatio);
} else {
Expand All @@ -57,7 +59,7 @@ function AspectConfigModal(props: PropsWithChildren<AspectConfigModalProps>) {
<div className={styles.aspect}>
<LabelledInput<number>
key="0"
disabled={typeRef.current !== 'number'}
disabled={aspectType !== 'number'}
label="aspect ratio"
input={aspectRatio}
isValid={(v) => isValidPositiveNumber(v, 10)}
Expand All @@ -77,7 +79,7 @@ function AspectConfigModal(props: PropsWithChildren<AspectConfigModalProps>) {
<ToggleGroup
role="radiogroup"
ariaLabel="aspect"
value={typeRef.current}
value={aspectType}
onChange={handleAspectTypeChange}
>
<ToggleGroup.Btn label="number" value="number" />
Expand Down
8 changes: 3 additions & 5 deletions client/component/src/AxialSelectionConfig.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import LabelledInput from './LabelledInput';
import { isNumber } from './utils';
import type AxialSelection from './selections/AxialSelection';
import AxialSelection from './selections/AxialSelection';
import { XInput, YInput } from './SelectionConfigComponents';
import { Fragment } from 'react';
import type { SelectionHandler } from './selections/utils';
Expand Down Expand Up @@ -39,9 +39,8 @@ function AxialSelectionConfig(props: AxialSelectionConfigProps) {
label="x length"
input={selection.length}
updateValue={(l: number) => {
selection.length = l;
if (updateSelection) {
updateSelection(selection);
updateSelection({ ...selection, length: l } as AxialSelection);
}
}}
decimalPlaces={8}
Expand All @@ -62,9 +61,8 @@ function AxialSelectionConfig(props: AxialSelectionConfigProps) {
label="y length"
input={selection.length}
updateValue={(l: number) => {
selection.length = l;
if (updateSelection) {
updateSelection(selection);
updateSelection({ ...selection, length: l } as AxialSelection);
}
}}
decimalPlaces={8}
Expand Down
37 changes: 19 additions & 18 deletions client/component/src/AxisConfigModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,24 +131,25 @@ function AxisConfigModal<S extends ScaleType>(
/>
);

return Modal({
title: props.title,
icon: props.icon,
button: props.colourMap ? (
<ColorMapGradient colorMap={props.colourMap} />
) : null,
hideToggle: props.hideToggle,
children: (
<>
{labelInput}
{scaleSelector}
{colourMapSelector}
{domainSelector}
{pointSizeInput}
{props.children}
</>
),
});
const button = props.colourMap ? (
<ColorMapGradient colorMap={props.colourMap} />
) : undefined;

return (
<Modal
title={props.title}
icon={props.icon}
button={button}
hideToggle={props.hideToggle}
>
{labelInput}
{scaleSelector}
{colourMapSelector}
{domainSelector}
{pointSizeInput}
{props.children}
</Modal>
);
}

export type { AxisConfigModalProps };
Expand Down
Loading