Skip to content

Commit

Permalink
📦 scxa-marker-gene-heatmap 💬 Import package and update dependencies (#25
Browse files Browse the repository at this point in the history
)

* Initial commit containing application skeleton, Babel and Webpack setup, as well as Travis config.

* Added first version of a Highcharts heatmap that displays marker genes, with 2 Y axes showing gene IDs and the cluster where the gene is a marker.

* Added react-highcharts and lodash as dependencies.

* Refactored demo component.

* Added React Select dropdown to change the k value for which marker genes are displayed. Reusing the PlotSettingsDropdown component from scxa-experiment-page-tsne-plot-view, which should be extracted into a separate repo with common components.

* Added flask loading overlay (same as tsne plot component). Added flask svg image. Added svg loading in Webpack config and fixed small issue with public assets path.

* Added dependencies on react-select, styled components and Webpack file loader.

* Renamed FetchLoader component to HeatmapView. Added additional props for styling and heatmap size and marked the relevant props as required. Added default values for some props. Tweaked styling such that the loading overlay only covers the heatmap, rather than the whole page. Changed default value to have the label prefixed with k =. Initialised heatmap data with empty array rather than null, to prevent errors.

* Fixed prop type for chartHeight. Applying wrapperClassName to heatmap div. Changed demo HTML to wide layout.

* Added rounding to 3 decimals in the heatmap tooltip. Changed title, added styling (to match tsne plots) and added subtitle. Added title to plot legend.

* Tweaked colouring to use EMBL orange for legend marker and heatmap cell border.

* Added additional div with styling passed as prop to add padding to the component.

* Changed PlotSettingsDropdown such that the value is set instead of the default dropdown value. This allows the dropdown to be changed programatically.

* Changed heatmap cursor to crosshair to hint at its zoomable qualitites.

* Added heatmap size calculation based on desired row height in pixels. Added props to enable/disable dynamic height, and to pass in height values.

* Added plotlines and labels to indicate the separation between marker genes for each cluster. Added more p-value and cluster ID where gene is marker to tooltip. Removed secondary axis. Added plot background colour such that empty cell appear grey rather than white. Added explicit X axis categories.

* Ensuring selectedK is an int as it can be sent as a string from URL params.

* Fixed PropTypes. Adjusted heatmap coloraxis.

* Added message to display when there is no data in the heatmap. Added min value for color axis. Changed to fixed height when there is no data in the heatmap. Tweaked default heatmap height value.

* Added logic to disabled ks for which we don't have marker genes (list of valid ks is passed in as a prop).

* Updated dependencies.

* Moved all heatmap sizing calculation logic to the MarkerGeneHeatmap component itself. Disabled display of heatmap if data is loading. Disabled axes and legend if heatmap is empty.

* Added additional dropdown for the cluster ID, so that a user can filter the heatmap for a particular cluster ID. An additional filteredData object was added to the state, which keeps a copy of the data actually displayed in the heatmap. Removed x and y axis category calculation from inside the heatmap component. Added a max value for the colorAxis, such that all experiments have an absolute colour gradient.

* Added additional test data set to the demo page.

* Added disabling of cluster IDs without marker genes in the dropdown. Simplified option disabling logic for the k dropdown.

* Added additonal prop for the heatmap which indicates whether or not the data is filtered. If the data is filtered, then no plotlines/side labels are calculated and shown.

* Fixed bug where the first categories on the X axis weren't being shown if they had no expression data.

* Fixed logic for disabling dynamically sized heatmaps. Now counting the actual number of genes, rather than than the number of data points. Incresed threshold to 5 genes.

* Added styling to the label corresponding to the selected cluster when the heatmap is filtered.

* Reduced number of decimals for p-value in the tooltip.

* Fix loading overlay position.

* Disabled x axis title if there is no data.

* Reorganised content in Heatmap view to include a separate row for the dropdowns, and an additional row for the heatmap.

* Remove unnecessary keys.

* Changed default demo experiment. Fixed some issues related to prop types.

* Updated Highcharts and React select.

* Removed failing stub tests. Added tests for the LoadingOverlay component.

* Actually removing stubs now.

* Added better error handling for situations in which no data is retrieved from the backend. Adjusted styling for error message div. Improved definition of data object expected by Highcharts.

* Extracted the CalloutAlert component into a separate file to ease testing.

* Added test for plot line creation in the MarkerGeneHeatmap component. Added test for unsuccessful API request in HeatmapView component.

* Enabled coveralls. Added fetch-mock as dependency.

* Added additional tests.

* Changed jest environment to jsdom.

* Fixed issue where heatmap remains in filtered mode when you change k values.

* Code cleanup following PR comments.

* Updated snapshots.

* Enabled image exporting. Renamed Highcharts modules to follow JS naming convention.

* Replaced value with defaultValue for PlotSettingsDropdown, as it no longer needs to be set programmatically.

* Reverted change to ReactSelect element, now using value rather than defaultValue. Renamed PlotSettingsDropdown prop to minimise confusion.

* Replaced native array generation with lodash equivalent. Changed k dropdown label.

* Added build badges to readme file.

* Fix linter warnings

* Small first instead of medium

* Update dependencies and polyfill tests that need fetch

* Update build badge link to travis-ci.com

* 1.0.0

* Add export-data module for heatmap data and change

json payload parameter `name` into `geneName` to avoid confusion between gene name and x-axis name.

* Define the exporting options explicitly without ..

viewdata and highchart cloud

* Add a module to correct heatmap export data shape

* Transpose matrix data to align with heatmap

* Rename highcharts module

* Correct error name property

* Ignore test for highcharts module and update lock

* Add a test for highcharts data export options

* Rename highcharts module in jest setup

* 1.1.0

* Update to latest dependencies

* 1.1.1

* Fix tests for Highcharts 7 and official wrapper

* 1.2.0

* Add a highcharts module to include html icon in .. (#3)

* Add a highcharts module to include html icon in ..

export button text and enlarge the font size

* Resize fontSize of button text and add code source

* Ignore highchartsExportStyle in Jest test

* Remove space in download button and add a test

* Restyle download button and update test, snapshot

* 1.2.1

* Update to latest dependencies

* 1.3.0

* Change TPM to CPM (#4)

* Bugfix #166502072 download button style (#5)

* Remove export module and update download button

* Update test

* 1.3.1

* Remove print option from heatmap download button (#7)

* - Remove print option from heatmap download button

* - Update test for export options on heatmap

* Update to latest dependencies

* Fix test

* 1.4.0

* Correct yAxis based on marker gene and cluster (#6)

* Correct yAxis based on marker gene and cluster

* Don’t use heredoc-like string templates for tooltip HTML snippets
They introduce many blanks without good reason

* yAxis shouldn’t be an array
The fact that it was working is surprising!

* Update to latest dependencies

* const what doesn’t need to be let

* CPM has a maximum of 1,000,000

* Use same color axis as t-SNE gene expression plot

* Row labels based on pairs of gene symbol/ID and cluster ID where the gene is a marker, instead of only gene symbol/ID

* Use Lodash better

* Add a meatier demo experiment

* Lower case test names

* 1.5.0

* Lerna post-import maintenance

Co-authored-by: Monica Jianu <monica@ebi.ac.uk>
Co-authored-by: lingyun1010 <zhaolingyun1010@gmail.com>
Co-authored-by: Lingyun Zhao <33519183+lingyun1010@users.noreply.github.com>
Co-authored-by: Haider Iqbal <haideri@ebi.ac.uk>
  • Loading branch information
5 people committed Mar 6, 2020
1 parent d5ad6c0 commit e716857
Show file tree
Hide file tree
Showing 31 changed files with 14,784 additions and 0 deletions.
3 changes: 3 additions & 0 deletions packages/scxa-marker-gene-heatmap/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"presets": ["@babel/preset-react", "@babel/preset-env"]
}
6 changes: 6 additions & 0 deletions packages/scxa-marker-gene-heatmap/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
serve.config.js
webpack.config.js
coverage/
__mocks__/
lib/
dist/
3 changes: 3 additions & 0 deletions packages/scxa-marker-gene-heatmap/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "eslint-config-gene-expression"
}
67 changes: 67 additions & 0 deletions packages/scxa-marker-gene-heatmap/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# IntelliJ IDEA project files
.idea/

# https://github.com/github/gitignore/blob/master/Node.gitignore

# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# Typescript v1 declaration files
typings/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env

# Build files
dist/
lib/
6 changes: 6 additions & 0 deletions packages/scxa-marker-gene-heatmap/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Ignore everything
*
.*

# But the build files...
!lib/**
3 changes: 3 additions & 0 deletions packages/scxa-marker-gene-heatmap/.travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
language: node_js
node_js:
- "8"
14 changes: 14 additions & 0 deletions packages/scxa-marker-gene-heatmap/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Single Cell Expression Atlas marker gene heatmap
[![Build Status](https://travis-ci.com/ebi-gene-expression-group/scxa-marker-gene-heatmap.svg?branch=master)](https://travis-ci.com/ebi-gene-expression-group/scxa-marker-gene-heatmap) [![Coverage Status](https://coveralls.io/repos/github/ebi-gene-expression-group/scxa-marker-gene-heatmap/badge.svg?branch=master)](https://coveralls.io/github/ebi-gene-expression-group/scxa-marker-gene-heatmap?branch=master)

## Installing dependencies
In order to run the application, you must first install the dependencies using `npm`:
```
npm install
```

## Try it out
Use [webpack-dev-server](https://github.com/webpack/webpack-dev-server) to run the application in your browser:
```
npx webpack-dev-server -d
```
1 change: 1 addition & 0 deletions packages/scxa-marker-gene-heatmap/__mocks__/fileMock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = 'test-file-stub'
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
global.requestAnimationFrame = function(callback) {
setTimeout(callback, 0)
}
1 change: 1 addition & 0 deletions packages/scxa-marker-gene-heatmap/__mocks__/styleMock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = {}
31 changes: 31 additions & 0 deletions packages/scxa-marker-gene-heatmap/__test__/CalloutAlert.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React from 'react'
import Enzyme from 'enzyme'
import renderer from 'react-test-renderer'
import { shallow } from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'

import CalloutAlert from '../src/CalloutAlert'

Enzyme.configure({ adapter: new Adapter() })

describe(`CalloutAlert`, () => {
const props = {
error: {
description: `A human-readable description of the error, hopefully useful to the user`,
name: `Error name`,
message: `Error message`
}
}

it(`prints all the relevant error information`, () => {
const wrapper = shallow(<CalloutAlert {...props} />)
expect(wrapper.text()).toMatch(props.error.description)
expect(wrapper.text()).toMatch(props.error.name)
expect(wrapper.text()).toMatch(props.error.message)
})

it(`matches snapshot`, () => {
const tree = renderer.create(<CalloutAlert {...props} />).toJSON()
expect(tree).toMatchSnapshot()
})
})
30 changes: 30 additions & 0 deletions packages/scxa-marker-gene-heatmap/__test__/HeatmapView.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react'
import Enzyme from 'enzyme'
import {shallow} from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'

import '@babel/polyfill'
import fetchMock from 'fetch-mock'

import HeatmapView from '../src/HeatmapView'
import CalloutAlert from '../src/CalloutAlert'

Enzyme.configure({ adapter: new Adapter() })

describe(`HeatmapView`, () => {
beforeEach(() => {
fetchMock.restore()
})

const props = {
host: `foo/`,
resource: `bar`,
ks: [1, 2, 3, 4],
selectedK: `1`
}

test(`renders error if API request is unsuccessful`, () => {
const wrapper = shallow(<HeatmapView {...props} />)
expect(wrapper.exists(CalloutAlert)).toBe(true)
})
})
14 changes: 14 additions & 0 deletions packages/scxa-marker-gene-heatmap/__test__/LoadingOverlay.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react'
import { mount } from 'enzyme'

import LoadingOverlay from '../src/LoadingOverlay'

describe(`LoadingOverlay`, () => {
test(`matches snapshot when shown`, () => {
expect(mount(<LoadingOverlay show={true}/>)).toMatchSnapshot()
})

test(`matches snapshot when hidden`, () => {
expect(mount(<LoadingOverlay show={false}/>)).toMatchSnapshot()
})
})
109 changes: 109 additions & 0 deletions packages/scxa-marker-gene-heatmap/__test__/MarkerGeneHeatmap.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import React from 'react'
import Enzyme from 'enzyme'
import {shallow} from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'

import '@babel/polyfill'
import MarkerGeneHeatmap from '../src/MarkerGeneHeatmap'

Enzyme.configure({ adapter: new Adapter() })

describe(`MarkerGeneHeatmap`, () => {
test(`creates plotlines for every cluster if data isn't filtered`, () => {
const wrapper = shallow(<MarkerGeneHeatmap
data={[
{
x: 0,
y: 0,
geneName: `foo`,
value: 13,
clusterIdWhereMarker: 1
},
{
x: 1,
y: 1,
geneName: `bar`,
value: 2,
clusterIdWhereMarker: 2
},
{
x: 2,
y: 2,
geneName: `foobar`,
value: 1,
clusterIdWhereMarker: 3
}
]}
xAxisCategories={[`1`, `2`, `3`]}
yAxisCategories={[`a`, `b`, `c`]}
chartHeight={200}
isDataFiltered={false}
heatmapRowHeight={20}
hasDynamicHeight={false} />)

const chartOptions = wrapper.find(`t`).props().options

expect(chartOptions.yAxis.plotLines).toHaveLength(3)
})

test(`doesn't create plotlines if data is filtered`, () => {
const wrapper = shallow(<MarkerGeneHeatmap
data={[
{
x: 0,
y: 0,
geneName: `foo`,
value: 13,
clusterIdWhereMarker: 1
}
]}
xAxisCategories={[`1`, `2`, `3`]}
yAxisCategories={[`a`, `b`, `c`]}
chartHeight={200}
isDataFiltered={true}
heatmapRowHeight={20}
hasDynamicHeight={false} />)

const chartOptions = wrapper.find(`t`).props().options

expect(chartOptions.yAxis.plotLines).toHaveLength(0)
})

test(`does have data export options and a styled button`, () => {
const wrapper = shallow(<MarkerGeneHeatmap
data={[
{
x: 0,
y: 0,
geneName: `foo`,
value: 13,
clusterIdWhereMarker: 1
}
]}
xAxisCategories={[`1`, `2`, `3`]}
yAxisCategories={[`a`, `b`, `c`]}
chartHeight={200}
isDataFiltered={true}
heatmapRowHeight={20}
hasDynamicHeight={false} />)

const chartOptions = wrapper.find(`t`).props().options

expect(chartOptions.exporting.buttons.contextButton.text).toEqual(
`Download`)

expect(chartOptions.exporting.buttons.contextButton.symbol).toEqual(`download`)

expect(chartOptions.exporting.buttons.contextButton.menuItems).toEqual(
[
`downloadPNG`,
`downloadJPEG`,
`downloadPDF`,
`downloadSVG`,
`separator`,
`downloadCSV`,
`downloadXLS`
]
)
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React from 'react'
import renderer from 'react-test-renderer'

import Enzyme from 'enzyme'
import {mount} from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'

import Select from 'react-select'

import PlotSettingsDropdown from '../src/PlotSettingsDropdown'

Enzyme.configure({ adapter: new Adapter() })

describe(`PlotSettingsDropdown`, () => {
test(`with no data matches snapshot`, () => {
const onSelect = () => {}

const tree = renderer
.create(<PlotSettingsDropdown onSelect={onSelect} options={[]}/>)
.toJSON()

expect(tree).toMatchSnapshot()
})

test(`contains Select component and label`, () => {
const onSelect = () => {}

const options = [
{
value: `hello`,
label: `hello`
},
{
value: `world`,
label: `world`
}
]

const wrapper =
mount(<PlotSettingsDropdown
labelText={`Test dropdown`}
defaultValue={
{
value: `world`,
label: `world`
}
}
options={options}
onSelect={onSelect}/>)

expect(wrapper.find(`label`).text()).toBe(`Test dropdown`)
expect(wrapper.find(Select).length).toBe(1)
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`CalloutAlert matches snapshot 1`] = `
<div
className="row"
>
<div
className="columns large-9 large-centered"
>
<div
className="callout alert small"
>
<h5>
Oops!
</h5>
<p>
A human-readable description of the error, hopefully useful to the user
<br />
If the error persists, in order to help us debug the issue, please copy the URL and this message and send it to us via
<a
href="https://www.ebi.ac.uk/support/gxasc"
>
the EBI Support & Feedback system
</a>
:
</p>
<code>
Error name: Error message
</code>
</div>
</div>
</div>
`;
Loading

0 comments on commit e716857

Please sign in to comment.