npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

gramene-anatomogram

v3.0.0

Published

React 18 anatomogram (tissue SVGs) for Expression Atlas heatmaps. Gramene fork of @ebi-gene-expression-group/anatomogram 2.4.0

Readme

gramene-anatomogram

Gramene's fork of @ebi-gene-expression-group/anatomogram 2.4.0, published on npm as gramene-anatomogram. It draws the Expression Atlas tissue SVGs next to the heatmaps of gramene-atlas-heatmap in Gramene sites (SorghumBase first).

What is different from 2.4.0:

  • React 18, as a peer dependency, with no React deprecation warnings: recompose, react-svg, styled-components, ReactDOM.render and function-component defaultProps are gone.
  • The SVGs and icons are bundled. Each SVG is its own lazily imported chunk, so only the species/view on screen is fetched, from wherever the host serves its bundle. There is no atlasUrl, publicPath or webpack-only require(), so it builds with Parcel, Vite and webpack alike.
  • Each SVG is injected once per species/view. Changing showIds/highlightIds/selectIds repaints the tissues in place instead of re-injecting the SVG.
  • ESM only. The code keeps upstream's module layout; see Fork maintenance.

Install

npm install gramene-anatomogram react@^18.2 react-dom@^18.2

Usage

import Anatomogram, { isSupportedSpecies } from 'gramene-anatomogram'

{isSupportedSpecies(species) &&                // e.g. 'sorghum_bicolor' or 'Sorghum bicolor'
  <Anatomogram
    species={species}
    showIds={['PO_0025034', 'PO_0009005']}
    highlightIds={highlighted}
    onMouseOver={(ids) => setHighlighted(ids)}  // ids: string[]
    onMouseOut={() => setHighlighted([])}
  />}

Without React in the host page:

import { render } from 'gramene-anatomogram'

const root = render({ species: 'sorghum_bicolor', highlightIds: ['PO_0025034'] }, 'target') // element id or element
render({ species: 'sorghum_bicolor', highlightIds: [] }, 'target')  // updates the same root
root.unmount()

Props

| Prop | Type | Default | Notes | |---|---|---|---| | species | string | required | An id such as sorghum_bicolor, or a name such as Sorghum bicolor (see normaliseSpecies). Unsupported species render nothing | | showIds, highlightIds, selectIds | string[] | [] | Ontology ids to paint. Compared by value, so new arrays with the same ids do not repaint. Select > highlight > show | | showColour, highlightColour, selectColour | string | grey, red, purple | | | showOpacity, highlightOpacity, selectOpacity | number | 0.4 | +0.2 while the mouse is over a tissue; shown tissues hover in the highlight colour | | onMouseOver, onMouseOut, onClick | (ids: string[]) => void | no-op | All the ids of the tissue under the mouse (several ids can share a shape through <use>). The latest function is always called; a new identity does not re-register listeners | | onInjected | (error, svg) => void | no-op | (null, svgElement) once per injected SVG, after painting; (error) when the SVG cannot be loaded | | linkTarget | string | null | '_blank' | target of the links in the SVG (the EBI licence attribution); _blank adds rel="noopener noreferrer". null leaves them untouched | | loadSvg | (species, view) => Promise<string> | bundled SVGs | SVG text from somewhere else, e.g. hosted or trimmed files. view is null for single-view species. Results are cached per function, so pass a stable one. Trusted sources only: <script>, <foreignObject>, on* attributes and javascript: URLs are removed, but this is not a sanitiser | | atlasUrl | string | | Deprecated, ignored. Accepted so that 2.x callers keep working |

The ids of each SVG are listed in src/json/svgsMetadata.json (also exported as svgsMetadata).

Exports

| Export | | |---|---| | default | The component | | render(options, target) | Renders into target (an element id or an element) with createRoot, one root per container; returns the root | | anatomogramSpecies, supportedSpecies | The 20 species with an SVG (the same array) | | normaliseSpecies(name) | Lower-cases and turns each run of whitespace into _: 'Sorghum bicolor' → 'sorghum_bicolor' | | isSupportedSpecies(name) | supportedSpecies.includes(normaliseSpecies(name)) | | getAnatomogramViews(species), getDefaultView(species) | Views of a species (['whole_plant', 'flower_parts']), []/null for single-view species, undefined for unsupported ones | | svgsMetadata | [{filename, species, view, ids}] for the 31 SVGs |

How the assets load

  • dist/gramene-anatomogram.js (~75 kB) is the entry. Each of the 31 SVGs is a chunk in dist/svg/ that exports the file's text; the entry reaches it with a plain import(). The host's bundler emits the chunks next to its own bundle and loads them relative to it, so nothing is fetched from EBI or from an atlasUrl. Only the species/view on screen is loaded, so the animal SVGs cost nothing at runtime. The SVGs total 13.5 MB (5 MB gzipped as a tarball).
  • The view switcher icons are data: URLs inside the entry: a host Content-Security-Policy needs img-src data:.
  • ESM only: a CommonJS copy would duplicate the SVG strings. Node ≥20.19 or ≥22.12 can require() it (require(esm)); Jest's module loader cannot.
  • The package deliberately has no source or browser field: Parcel would then compile src/, whose import.meta.glob only Vite understands.
  • <use> caveat (animal SVGs only, as upstream): tissues such as UBERON_0000178 are <use xlink:href="#CL_0000738"> elements. Two instances showing the same animal SVG put duplicate ids in the page. Plant SVGs have no <use>.

Migrating from @ebi-gene-expression-group/anatomogram 2.x

  • Change the package name. React 18 and an ESM-aware bundler are required.
  • Drop atlasUrl and any hosting of the SVG/PNG files.
  • render() now uses createRoot, returns the root and accepts an element as well as an id.
  • Callbacks receive an array of ids. They always did; the upstream README said a single string.
  • DOM: div.gxa-anatomogram > (div.gxa-anatomogram-switcher > img[role=button], div.gxa-anatomogram-svg > svg.injected-svg). The svg is one wrapper shallower than react-svg's div > div > svg, and there are no styled-components classes: all styles are inline and no global CSS is injected.
  • normaliseSpecies replaces every run of whitespace, not only the first run of spaces.

Development

npm install
npm test               # vitest + jsdom; any console.error/warn fails the test unless it calls allowConsole()
npm run build          # dist/, then scripts/check-dist.mjs
npm run lint:pkg       # publint
npm run pack:local     # build, then gramene-anatomogram-3.0.0.tgz
npm run dev            # playground (html/) on http://localhost:5176

The playground starts on sorghum and lists plants first. It has an event log (also written to the console as [anatomogram] …), a two-instance switch, a remount button, a linkTarget selector and a switch that passes the display name (Sorghum bicolor). URL parameters: ?species=<id> and ?strict=1 (StrictMode). From a workstation: ssh -L 5176:localhost:5176 <host>.

To try an unpublished build in a consumer, install the tarball rather than npm link (a symlink would load a second React):

npm run pack:local
cd ../atlas-heatmap && npm install --no-save ../anatomogram/gramene-anatomogram-3.0.0.tgz
# gramene-search: npm install --no-save ../anatomogram/gramene-anatomogram-3.0.0.tgz ../atlas-heatmap/gramene-atlas-heatmap-6.0.0.tgz && rm -rf .parcel-cache*

Until the package is published, every npm install in the consumer must repeat the tarball(s); otherwise npm fails with E404 or prunes them.

After editing an SVG (see the authoring guidelines in src/svg/README.md), run npm run parseSvgs to regenerate src/json/svgsMetadata.json. The build does not run it, but a test fails when the JSON is stale. fast-xml-parser stays pinned to 3.14.0 as upstream had it (3.15 broke its validation). npm audit flags that version; it is a development dependency only.

Fork maintenance

  • Remotes: origin is warelab/anatomogram, upstream is ebi-gene-expression-group/anatomogram.

  • Branches: master mirrors upstream and is never committed to. gramene is the default branch, cut from upstream's v2.4.0 tag; releases are tagged vX.Y.Z on it.

  • Edit upstream files in place without reformatting them. Leave src/svg/, src/img/, src/json/, src/Assets.js and wiki/ byte-identical to upstream, apart from SVG changes made on purpose. Make focused commits.

  • Review what the fork changes:

    git fetch upstream --tags
    git diff -M --stat upstream/master...gramene -- . ':(exclude)package-lock.json'
    git diff -M upstream/master...gramene -- src html scripts __test__
    git diff --stat upstream/master -- src/svg src/img src/json src/Assets.js wiki   # empty
  • Taking upstream changes: git merge upstream/master (or cherry-pick) into gramene, then npm test and npm run build.

  • Releasing: bump version, add a CHANGELOG.md entry, npm run pack:local and try the tarball in the consumers, then tag and npm publish (prepublishOnly runs the tests, the build with check-dist, and publint).

Upstream README (2.4.0)

Expression Atlas Anatomogram

Build Status Coverage Status License License: CC BY 4.0

This is an anatomogram for Expression Atlas that we use to illustrate the experiments.

See demo here.

The ontology IDs are sourced from Uberon, EFO and Plant Ontology.

To install:

npm install --save @ebi-gene-expression-group/anatomogram

You can use it as a React component:

import Anatomogram from '@ebi-gene-expression-group/anatomogram'

...

<Anatomogram .../>

Alternatively, if you don’t use React we’re providing a convenience render method:

import {render} from '@ebi-gene-expression-group/anatomogram'

...

render(options, target)

Where options are the props passed as an object, and target is an ID of the DOM element that will contain the anatomogram.

For example code, have a look at the demo component and how we use it in our Expression Atlas Heatmap. If you want to see it in action, go to an organism part experiment in Atlas or a search that returns organism part experiments.

Props

| Name | Type | Default value | Description | |------------------|----------|:--------------:|----------------------------------------------------------------------| | species | string | - | This is the only required attribute of the anatomogram | | showIds | array | [] | | | highlightIds | array | [] | | | selectIds | array | [] | | | showColour | string | grey | | | highlightColour | string | red | | | selectColour | string | purple | | | showOpacity | number | 0.4 | | | highlightOpacity | number | 0.4 | | | selectOpacity | number | 0.4 | | | onMouseOver | function | () => {} | Callback invoked when the mouse is hovered on a tissue | | onMouseOut | function | () => {} | Callback invoked when the mouse is hovered off a tissue | | onClick | function | () => {} | Callback invoked when a tissue is clicked | | onInjected | function | () => {} | Callback invoked when SVG is injected |

For a list of available species and IDs have a look at src/json/svgsMetadata.json. The file is generated with npm run parseSvgs (Gramene fork: no longer on every publish; a test checks it is up to date).

All three callbacks take a single argument, the array of IDs of the tissue affected by the mouse event (several IDs can share a shape through <use> elements). (Gramene fork: corrected; this README used to say a single string.)

The state of a tissue is either not shown, shown, highlighted or selected. On mouseover the opacity is increased by 0.2. You can read a more technically inclined description of the anatomogram behaviour in the repository wiki.

Building

(Gramene fork: the webpack build and atlasUrl/--output-public-path setup are gone. The SVGs and icons are bundled with the code; see How the assets load.)

Contribute

Read carefully our authoring guidelines before adding new tissues or updating IDs in an existing anatomogram or adding a new SVG.

Run npm run parseSvgs to parse the updated IDs. When you are finished run a local copy of the demo page:

npm run dev

Go to localhost:5176 and see that the tissues show up like you want them to.

Licence

Code is distributed under the Apache License version 2.0. All images, anatomograms and switcher icons, are distributed under the Creative Commons Attribution 4.0 International license. See LICENSE and NOTICE.