Skip to content

Commit

Permalink
DRY workflows and ColorBar snap tick labels to nice values (#22)
Browse files Browse the repository at this point in the history
* DRY workflows

* update deps

* add test/unit/BohrAtom.test.ts

* add props snap_ticks, ramp_points, nice_range to ColorBar

remove prop precision, seems to be well handled by d3.scaleLinear.nice()

* fix ColorBar.test.ts and remove PR to main trigger from gh-pages.yml

* refactor pretty_num() to use d3.format() with SI units for abs(num) > 1 and floating or exponential for abs(num) < 1

* fix type of ElementTile.svelte precision prop

* pretty_num() reinstate return '' if num === null
  • Loading branch information
janosh authored Apr 3, 2023
1 parent a9cd480 commit a4edc93
Show file tree
Hide file tree
Showing 15 changed files with 167 additions and 135 deletions.
40 changes: 1 addition & 39 deletions .github/workflows/gh-pages.yml
Original file line number Diff line number Diff line change
@@ -1,48 +1,10 @@
name: GitHub Pages

on:
pull_request:
branches: [main]
push:
branches: [main]
# GH pages doesn't support PR previews yet but plans to add
# https://github.com/community/community/discussions/7730#discussioncomment-1885967
workflow_dispatch:

# set permissions of GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Check out repo
uses: actions/checkout@v3

- name: Set up node
uses: actions/setup-node@v3
with:
node-version: 18
cache: npm
cache-dependency-path: package.json

- name: Install dependencies
run: npm install --force

- name: Build site
run: npm run build

- name: Upload build artifact
uses: actions/upload-pages-artifact@v1
with:
path: build

deploy:
needs: build
runs-on: ubuntu-latest
steps:
- name: Deploy to GitHub Pages
uses: actions/deploy-pages@v1
uses: janosh/workflows/.github/workflows/nodejs-gh-pages.yml@main
42 changes: 1 addition & 41 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,44 +11,4 @@ on:

jobs:
tests:
runs-on: ubuntu-latest

steps:
- name: Check out repo
uses: actions/checkout@v3

- name: Set up node
uses: actions/setup-node@v3
with:
node-version: 18

- name: Install dependencies
run: |
npm install --force
npx playwright install chromium
- name: Run tests
id: tests
run: npm run test

release:
runs-on: ubuntu-latest
needs: tests
if: github.event_name == 'release' && needs.tests.result == 'success'
steps:
- name: Check out repo
uses: actions/checkout@v3

- name: Set up node
uses: actions/setup-node@v3
with:
node-version: 18
registry-url: https://registry.npmjs.org

- name: Build package and publish to NPM
run: |
npm install --force
npm run package
npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
uses: janosh/workflows/.github/workflows/npm-test-release.yml@main
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ repos:
- id: trailing-whitespace

- repo: https://github.com/pre-commit/mirrors-prettier
rev: v3.0.0-alpha.4
rev: v3.0.0-alpha.6
hooks:
- id: prettier
args: [--write] # edit files in-place
Expand All @@ -29,7 +29,7 @@ repos:
exclude: ^changelog.md|src/routes/.*\.json$

- repo: https://github.com/codespell-project/codespell
rev: v2.2.2
rev: v2.2.4
hooks:
- id: codespell
stages: [commit, commit-msg]
Expand Down
23 changes: 12 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,19 @@
},
"dependencies": {
"@iconify/svelte": "^3.1.0",
"@sveltejs/kit": "^1.13.0",
"@sveltejs/kit": "^1.15.0",
"d3-array": "^3.2.3",
"d3-color": "^3.1.0",
"d3-format": "^3.1.0",
"d3-interpolate-path": "^2.3.0",
"d3-scale": "^4.0.2",
"d3-scale-chromatic": "^3.0.0",
"d3-shape": "^3.2.0",
"svelte": "^3.57.0",
"svelte": "^3.58.0",
"svelte-multiselect": "^8.6.0"
},
"devDependencies": {
"@playwright/test": "^1.31.2",
"@playwright/test": "^1.32.1",
"@sveltejs/adapter-static": "2.0.1",
"@sveltejs/package": "^2.0.2",
"@types/d3-array": "^3.0.4",
Expand All @@ -44,30 +45,30 @@
"@types/d3-scale": "^4.0.3",
"@types/d3-scale-chromatic": "^3.0.0",
"@types/d3-shape": "^3.1.1",
"@typescript-eslint/eslint-plugin": "^5.56.0",
"@typescript-eslint/parser": "^5.56.0",
"@vitest/coverage-c8": "^0.29.7",
"eslint": "^8.36.0",
"@typescript-eslint/eslint-plugin": "^5.57.0",
"@typescript-eslint/parser": "^5.57.0",
"@vitest/coverage-c8": "^0.29.8",
"eslint": "^8.37.0",
"eslint-plugin-svelte3": "^4.0.0",
"hastscript": "^7.2.0",
"jsdom": "^21.1.1",
"mdsvex": "^0.10.6",
"mdsvexamples": "^0.3.3",
"prettier": "^2.8.6",
"prettier": "^2.8.7",
"prettier-plugin-svelte": "^2.10.0",
"rehype-autolink-headings": "^6.1.1",
"rehype-katex-svelte": "^1.1.2",
"rehype-slug": "^5.1.0",
"remark-math": "3.0.0",
"sharp": "^0.31.3",
"sharp": "^0.32.0",
"svelte-check": "^3.1.4",
"svelte-preprocess": "^5.0.3",
"svelte-toc": "^0.5.4",
"svelte-zoo": "^0.4.3",
"svelte2tsx": "^0.6.10",
"typescript": "5.0.2",
"typescript": "5.0.3",
"vite": "^4.2.1",
"vitest": "^0.29.7"
"vitest": "^0.29.8"
},
"keywords": [
"svelte",
Expand Down
34 changes: 25 additions & 9 deletions src/lib/ColorBar.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script lang="ts">
import { pretty_num } from '$lib/labels'
import * as d3 from 'd3-scale'
import * as d3sc from 'd3-scale-chromatic'
export let text: string | null = null
Expand All @@ -13,18 +13,31 @@
export let tick_side: 'top' | 'bottom' | 'center' = `bottom`
// TODO vertical not fully implemented yet
export let orientation: 'horizontal' | 'vertical' = `horizontal`
export let precision: number = 1
// snap ticks to pretty, more readable values
export let snap_ticks: boolean = true
// at how many equidistant points to sample the color scale
export let ramp_points: number = 10
// the new range of the color bar resulting from snapping ticks
// https://github.com/d3/d3-scale/issues/86
export let nice_range: [number, number] = range
$: if (
tick_labels?.length == 0 ||
typeof tick_labels == `number` ||
range?.length > 0
) {
const n_ticks = Array.isArray(tick_labels) ? 5 : tick_labels
tick_labels = [...Array(n_ticks).keys()].map((idx) => {
const x = idx / (n_ticks - 1)
return range[0] + x * (range[1] - range[0])
})
if (snap_ticks) {
const scale = d3.scaleLinear().domain(range).nice(n_ticks)
tick_labels = scale.ticks(n_ticks)
nice_range = scale.domain()
} else {
tick_labels = [...Array(n_ticks).keys()].map((idx) => {
const x = idx / (n_ticks - 1)
return range[0] + x * (range[1] - range[0])
})
}
}
$: if (color_scale === null || typeof color_scale == `string`) {
Expand All @@ -46,7 +59,9 @@
vertical: `to bottom`,
}[orientation]
$: ramped = [...Array(10).keys()].map((idx) => color_scale?.(idx / 10))
$: ramped = [...Array(ramp_points).keys()].map((idx) =>
color_scale?.(idx / ramp_points)
)
$: flex_dir = {
left: `row`,
right: `row-reverse`,
Expand All @@ -61,11 +76,12 @@
</script>

<div style:flex-direction={flex_dir} style={wrapper_style} class="colorbar">
{#if text}<span style={text_style}>{text}</span>{/if}
<!-- don't pass unsanitized user input into text! -->
{#if text}<span style={text_style}>{@html text}</span>{/if}
<div style:background="linear-gradient({grad_dir}, {ramped})" {style}>
{#each tick_labels || [] as tick_label, idx}
<span style="left: calc(100% * {idx} / {tick_labels?.length - 1}); {tick_pos}">
{pretty_num(tick_label, precision)}
{tick_label}
</span>
{/each}
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/lib/ElementTile.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
// at what background color lightness text color switches from black to white
export let text_color_threshold = 0.7
export let text_color: string | null = null
export let precision: number = 2
export let precision: string | null = null
type $$Events = PeriodicTableEvents // for type-safe event listening on this component
Expand Down
2 changes: 1 addition & 1 deletion src/lib/element-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3320,7 +3320,7 @@ export default [
period: 6,
phase: `Solid`,
spectral_img: null,
summary: `Tungsten, also known as wolfram, is a chemical element with symbol W and atomic number 74. The word tungsten comes from the Swedish language tung sten, which directly translates to heavy stone. Its name in Swedish is volfram, however, in order to distinguish it from scheelite, which in Swedish is alternatively named tungsten.`,
summary: `Tungsten, also known as wolfram, is a chemical element with symbol W and atomic number 74. The word tungsten comes from the Swedish language 'tung sten', which directly translates to heavy stone. Its name in Swedish is volfram, however, in order to distinguish it from scheelite, which in Swedish is alternatively named tungsten.`,
symbol: `W`,
shells: [2, 8, 18, 32, 12, 2],
electron_configuration: `1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d4`,
Expand Down
20 changes: 10 additions & 10 deletions src/lib/labels.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { get } from 'svelte/store'
import type { Category, ChemicalElement } from '.'
// .ts ext needed for Playwright to be able to resolve import
import { precision_store } from './stores.ts'
import { format } from 'd3-format'

// TODO add labels and units for all elemental properties
export const property_labels: Partial<
Expand Down Expand Up @@ -44,16 +43,17 @@ export const heatmap_labels: Partial<Record<string, keyof ChemicalElement>> =
})
)

export const pretty_num = (
num: number | null,
precision: number = get(precision_store)
) => {
// allow users to import default_precision and change it's items in place to
// set default number format globally
export const default_precision: [string, string] = [`,.3~s`, `.3~g`]

export const pretty_num = (num: number, precision?: string) => {
if (num === null) return ``
if ((Math.abs(num) < 0.01 && Math.abs(num) > 0) || num > 1e6) {
return num.toExponential(precision)
} else {
return parseFloat(num.toFixed(precision)).toLocaleString()
if (!precision) {
const [gt_1_fmt, lt_1_fmt] = default_precision
return format(Math.abs(num) >= 1 ? gt_1_fmt : lt_1_fmt)(num)
}
return format(precision)(num)
}

export const category_counts: Record<Category, number> = {
Expand Down
2 changes: 0 additions & 2 deletions src/lib/stores.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,3 @@ export const category_colors = session_store<Record<string, string>>(
`category-colors`,
{ ...default_category_colors }
)

export const precision_store = session_store<number>(`elementari-precision`, 2)
15 changes: 13 additions & 2 deletions src/routes/(demos)/color-bar/+page.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,22 @@ Here's a `ColorBar` with tick labels:
```svelte example stackblitz
<script>
import { ColorBar } from '$lib'
const bars = [
[`Viridis`, `top`, [0, 0.25, 0.5, 0.75, 1]],
[`Magma`, `center`, [], [100, 1631]],
[`Cividis`, `bottom`, [], [-99.9812, -10]],
]
</script>
{#each [[`Viridis`, `top`, [0, 0.25, 0.5, 0.75, 1]], [`Magma`, `center`, [], [100, 1000]], [`Cividis`, `bottom`, [], [-100, -10]]] as [color_scale, tick_side, tick_labels, range]}
{#each bars as [color_scale, tick_side, tick_labels, range]}
<ColorBar
text="{color_scale} (tick side={tick_side})"
text="{color_scale}<br>&bull; tick side={tick_side}<br>&bull; range={range}"
{color_scale}
{tick_side}
{tick_labels}
{range}
text_style="white-space: nowrap; padding-right: 1em;"
--cbar-width="100%"
--cbar-padding="2em"
/>
Expand Down Expand Up @@ -99,6 +106,7 @@ You can make fat and skinny bars:
? element_data.map((el) => el[heatmap_key])
: []
$: heat_range = [Math.min(...heatmap_values), Math.max(...heatmap_values)]
let cs_range = heat_range
</script>
<form>
Expand All @@ -110,13 +118,16 @@ You can make fat and skinny bars:
{heatmap_values}
style="margin: 2em auto 4em;"
bind:color_scale
color_scale_range={cs_range ?? heat_range}
links="name"
lanth_act_tiles={false}
>
<TableInset slot="inset" style="place-items: center; padding: 2em;">
<ColorBar
{color_scale}
range={heat_range}
bind:nice_range={cs_range}
tick_labels={5}
tick_side="bottom"
--cbar-width="100%"
--cbar-height="15pt"
Expand Down
22 changes: 22 additions & 0 deletions src/routes/(demos)/element-tile/+page.svx
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,25 @@
}
</style>
```

Displaying values instead of element names by passing the `value` prop.

```svelte example stackblitz code_above
<script>
import { ElementTile, element_data } from '$lib'
</script>

<ol>
{#each ['red', 'green', 'blue', 'yellow', 'cyan', 'magenta', 'black', 'white'] as bg_color, idx}
<ElementTile {bg_color} element={element_data[idx]} value={Math.random()} style="width: 4em; margin: 0;" active />
{/each}
</ol>

<style>
ol {
display: flex;
flex-wrap: wrap;
gap: 1em;
}
</style>
```
9 changes: 4 additions & 5 deletions tests/periodic-table.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,10 @@ test.describe(`Periodic Table`, () => {
const heatmap_val = pretty_num(random_element[heatmap_keys.at(-1)])

// make sure heatmap value is displayed correctly
const elem_tile = await page.$(
`text=${rand_idx + 1} ${random_element.symbol} ${heatmap_val}`,
{ strict: true }
)
expect(elem_tile).not.toBeNull()
const text = `${rand_idx + 1} ${random_element.symbol} ${heatmap_val}`
const elem_tile = await page.$(`text=${text}`, { strict: true })
await page.pause()
expect(elem_tile, `selector text=${text}`).not.toBeNull()
}
})
})
Expand Down
Loading

0 comments on commit a4edc93

Please sign in to comment.