Compare commits

..
Author SHA1 Message Date
Roy Zheng 96cb19c89b chore: CCIE-4984 conform to open sourcing guidelines 2025-08-11 22:52:38 +00:00
Justin Kiggins eb1dc8944f Update README.md (#2725)
CodeQL Scan / Analyze (javascript) (push) Has been cancelled
CodeQL Scan / Analyze (python) (push) Has been cancelled
Compatibility Tests / docker-build (push) Has been cancelled
Compatibility Tests / cxg:latest os: py:3.12 anndata:==0.10.9 (push) Has been cancelled
Compatibility Tests / cxg:latest os:macos-13 py:3.10 anndata:latest (push) Has been cancelled
Compatibility Tests / cxg:latest os:macos-13 py:3.11 anndata:latest (push) Has been cancelled
Compatibility Tests / cxg:latest os:macos-13 py:3.12 anndata:latest (push) Has been cancelled
Compatibility Tests / cxg:latest os:macos-latest py:3.10 anndata:latest (push) Has been cancelled
Compatibility Tests / cxg:latest os:macos-latest py:3.11 anndata:latest (push) Has been cancelled
Compatibility Tests / cxg:latest os:macos-latest py:3.12 anndata:latest (push) Has been cancelled
Compatibility Tests / cxg:latest os:ubuntu-latest py:3.10 anndata:latest (push) Has been cancelled
Compatibility Tests / cxg:latest os:ubuntu-latest py:3.11 anndata:latest (push) Has been cancelled
Compatibility Tests / cxg:latest os:ubuntu-latest py:3.12 anndata:latest (push) Has been cancelled
Compatibility Tests / cxg:main os:macos-13 py:3.10 anndata:latest (push) Has been cancelled
Compatibility Tests / cxg:main os:macos-13 py:3.11 anndata:latest (push) Has been cancelled
Compatibility Tests / cxg:main os:macos-13 py:3.12 anndata:latest (push) Has been cancelled
Compatibility Tests / cxg:main os:macos-latest py:3.10 anndata:latest (push) Has been cancelled
Compatibility Tests / cxg:main os:macos-latest py:3.11 anndata:latest (push) Has been cancelled
Compatibility Tests / cxg:main os:macos-latest py:3.12 anndata:latest (push) Has been cancelled
Compatibility Tests / cxg:main os:ubuntu-latest py:3.10 anndata:latest (push) Has been cancelled
Compatibility Tests / cxg:main os:ubuntu-latest py:3.11 anndata:latest (push) Has been cancelled
Compatibility Tests / cxg:main os:ubuntu-latest py:3.12 anndata:latest (push) Has been cancelled
Close inactive pull requests / close-issues (push) Has been cancelled
Trademark
2025-05-14 12:03:19 -07:00
29 changed files with 760 additions and 843 deletions
+3 -8
View File
@@ -7,10 +7,6 @@ on:
branches:
- main
# For debug - uncomment below to run on all PRs
pull_request:
branches: "*"
env:
JEST_ENV: prod
@@ -32,14 +28,13 @@ jobs:
strategy:
fail-fast: false
matrix:
# note: The `macos-latest` is latest Catalina version, and not Big Sur. So we explicitly ask for Big Sur (`macos-11`)
os: [ubuntu-latest, macos-latest, macos-13]
python-version: ["3.10", "3.11"]
python-version: ["3.10", "3.11", "3.12"]
cellxgene_build: [main, latest]
# add anndata pinned version test for subset of matrix configurations,
# in order to reduce matrix cross-product explosion
include:
- python-version: 3.11
- python-version: 3.12
cellxgene_build: latest
# TODO: dynamically use the literal version in requirements.txt,
# to avoid having to update this in manually in the future
@@ -100,7 +95,7 @@ jobs:
# keep same pip pkg versions as in the cxg release
sed -i'' -e 's/-r requirements.txt//' server/requirements-dev.txt
pip install -r server/requirements-dev.txt
pip install --force-reinstall numpy==2.0.1 numba>=0.60.0 pandas
pip install --force-reinstall numpy==2.0.1 numba>=0.60.0 pandas flatbuffers==2.0.7
- name: Install anndata version per matrix variable
run: pip install anndata${{ matrix.anndata_version }}
- name: Install node
+20
View File
@@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2017-2023 Chan Zuckerberg Initiative
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+9 -3
View File
@@ -1,4 +1,4 @@
![](https://github.com/chanzuckerberg/cellxgene/raw/main/docs/cellxgene-logo.png)
<img src="./docs/cellxgene-logo.png" width="300">
_an interactive explorer for single-cell transcriptomics data_
@@ -11,8 +11,7 @@ CZ CELLxGENE Annotate (pronounced "cell-by-gene") is an interactive data explore
Whether you need to visualize one thousand cells or one million, CELLxGENE Annotate helps you gain insight into your single-cell data.
![](https://github.com/chanzuckerberg/cellxgene/raw/main/docs/images/crossfilter.gif)
![](https://github.com/chanzuckerberg/cellxgene/raw/main/docs/images/category-breakdown.gif)
<img src="https://github.com/chanzuckerberg/cellxgene/raw/main/docs/images/crossfilter.gif" width="350" height="200" hspace="30"><img src="https://github.com/chanzuckerberg/cellxgene/raw/main/docs/images/category-breakdown.gif" width="350" height="200" hspace="30">
# Getting started
@@ -83,6 +82,13 @@ extension could be directly contributed, which would make it available for a wid
See the [CELLxGENE extensions](https://github.com/chanzuckerberg/cellxgene-documentation/blob/main/community-extensions.md) section of our documentation for examples of community use and CELLxGENE extensions.
### Trademarks
CZ CELLXGENE, CZ CELLXGENE DISCOVER, and CZ CELLXGENE ANNOTATE are trademarks of the Chan Zuckerberg Initiative. All rights reserved.
Use, reuse, modification, and re-distribution of the source code in this repository is subject to the terms of the applicable open source [license](LICENSE.txt). However, that license does not grant permission to use the trademarks without separate, express permission from the Chan Zuckerberg Initiative.
### Security
If you believe you have found a security issue, we would appreciate notification. Please send email to <security@chanzuckerberg.com>.
+2
View File
@@ -0,0 +1,2 @@
## Reporting Security Issues
If you believe you have found a security issue, please responsibly disclose by contacting us at [security@chanzuckerberg.com](mailto:security@chanzuckerberg.com).
+1 -1
View File
@@ -1,4 +1,4 @@
import * as ENV_DEFAULT from "Code/cellxgene/environment.default.json";
import * as ENV_DEFAULT from "../../../environment.default.json";
export const jestEnv = process.env.JEST_ENV || ENV_DEFAULT.JEST_ENV;
export const appUrlBase =
+1 -1
View File
@@ -5,8 +5,8 @@
*/
import { setDefaultOptions } from "expect-puppeteer";
import * as ENV_DEFAULT from "Code/cellxgene/environment.default.json";
import { isDebug, isDev } from "./config";
import * as ENV_DEFAULT from "../../../environment.default.json";
// (thuang): This is the max time a test can take to run.
// Since when debugging, we run slowMo and !headless, this means
+6 -6
View File
@@ -76,7 +76,7 @@ describe("PromiseLimit", () => {
const plimit = new PromiseLimit(1);
let finishOrder = 0;
const callback = async () => {
const callback = () => async () => {
await delay(100);
const result = finishOrder;
finishOrder += 1;
@@ -84,11 +84,11 @@ describe("PromiseLimit", () => {
};
const result = await Promise.all([
plimit.add(callback),
plimit.priorityAdd(4, callback),
plimit.priorityAdd(0, callback),
plimit.priorityAdd(1, callback),
plimit.priorityAdd(-1, callback),
plimit.add(callback()),
plimit.priorityAdd(4, callback()),
plimit.priorityAdd(0, callback()),
plimit.priorityAdd(1, callback()),
plimit.priorityAdd(-1, callback()),
]);
expect(result).toEqual([0, 4, 2, 3, 1]);
+1 -2
View File
@@ -82,14 +82,13 @@ module.exports = {
},
// Can't extend in overrides: https://github.com/eslint/eslint/issues/8813
// "extends": ["plugin:jest/recommended"]
plugins: ["jest", "no-floating-promise"],
plugins: ["jest"],
rules: {
"jest/no-disabled-tests": "warn",
"jest/no-focused-tests": "error",
"jest/no-identical-title": "error",
"jest/prefer-to-have-length": "warn",
"jest/valid-expect": "error",
"no-floating-promise/no-floating-promise": 2,
},
},
],
+647 -776
View File
File diff suppressed because it is too large Load Diff
+6 -7
View File
@@ -10,8 +10,8 @@
"dev": "npm run build -- configuration/webpack/webpack.config.dev.js",
"e2e": "jest --config __tests__/e2e/e2eJestConfig.json e2e/e2e.test.js",
"e2e-annotations": "jest --config __tests__/e2e/e2eJestConfig.json e2e/e2eAnnotations.test.js",
"fmt": "eslint --fix __tests__",
"lint": "eslint --fix __tests__",
"fmt": "eslint --fix src __tests__",
"lint": "eslint --fix src __tests__",
"prod": "npm run build -- configuration/webpack/webpack.config.prod.js",
"test": "jest --testPathIgnorePatterns e2e",
"prepare": "cd .. && husky install client/.husky"
@@ -92,7 +92,7 @@
"@babel/preset-react": "^7.13.13",
"@babel/register": "^7.13.16",
"@babel/runtime": "^7.13.16",
"@blueprintjs/eslint-plugin": "^6.1.4",
"@blueprintjs/eslint-plugin": "^0.3.0",
"@sentry/webpack-plugin": "^1.15.0",
"babel-jest": "^26.1.0",
"babel-loader": "^8.1.0",
@@ -104,16 +104,15 @@
"codecov": "^3.7.1",
"css-loader": "^5.2.4",
"css-minimizer-webpack-plugin": "^4.0.0",
"eslint": "^8.56.0",
"eslint-config-airbnb": "^19.0.4",
"eslint": "^7.24.0",
"eslint-config-airbnb": "^18.2.0",
"eslint-config-prettier": "^8.2.0",
"eslint-plugin-compat": "^4.2.0",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-filenames": "^1.3.2",
"eslint-plugin-import": "^2.24.2",
"eslint-plugin-jest": "^28.8.3",
"eslint-plugin-jest": "^24.3.5",
"eslint-plugin-jsx-a11y": "^6.3.1",
"eslint-plugin-no-floating-promise": "^2.0.0",
"eslint-plugin-react": "^7.23.2",
"eslint-plugin-react-hooks": "^4.0.8",
"expect-puppeteer": "^5.0.0",
@@ -1,8 +1,8 @@
import React from "react";
import * as globals from "../../globals";
function ErrorLoading({ displayName, zebra }) {
return <div
const ErrorLoading = ({ displayName, zebra }) => (
<div
style={{
backgroundColor: zebra ? globals.lightestGrey : "white",
fontStyle: "italic",
@@ -10,6 +10,6 @@ function ErrorLoading({ displayName, zebra }) {
>
<span>{`Failure loading ${displayName}`}</span>
</div>
}
);
export default ErrorLoading;
@@ -5,7 +5,7 @@ import * as d3 from "d3";
import maybeScientific from "../../util/maybeScientific";
import clamp from "../../util/clamp";
function Histogram({
const Histogram = ({
field,
fieldForId,
display,
@@ -18,7 +18,7 @@ function Histogram({
isColorBy,
selectionRange,
mini,
}) {
}) => {
const svgRef = useRef(null);
const [brush, setBrush] = useState(null);
@@ -186,6 +186,6 @@ function Histogram({
ref={svgRef}
/>
);
}
};
export default Histogram;
@@ -3,8 +3,12 @@ import { Button } from "@blueprintjs/core";
import * as globals from "../../globals";
function StillLoading({ zebra, displayName }) {
return <div
const StillLoading = ({ zebra, displayName }) =>
/*
Render a loading indicator for the field.
*/
(
<div
data-testclass="gene-loading-spinner"
style={{
padding: globals.leftSidebarSectionPadding,
@@ -33,6 +37,7 @@ function StillLoading({ zebra, displayName }) {
</div>
</div>
</div>
}
)
;
export default StillLoading;
@@ -71,7 +71,8 @@ class Category extends React.PureComponent {
const { metadataField, annotations, obsCrossfilter } = this.props;
return (
<AnnoDialog
<>
<AnnoDialog
isActive={
annotations.isAddingNewLabel &&
annotations.categoryAddingNewLabel === metadataField
@@ -104,6 +105,7 @@ class Category extends React.PureComponent {
/>
}
/>
</>
);
}
}
@@ -105,7 +105,8 @@ class AnnoDialogEditCategoryName extends React.PureComponent {
const { metadataField, annotations } = this.props;
return (
<AnnoDialog
<>
<AnnoDialog
isActive={
annotations.isEditingCategoryName &&
annotations.categoryBeingEdited === metadataField
@@ -140,6 +141,7 @@ class AnnoDialogEditCategoryName extends React.PureComponent {
/>
}
/>
</>
);
}
}
@@ -288,8 +288,11 @@ class Category extends React.PureComponent {
export default Category;
function StillLoading({ metadataField, checkboxID }) {
return <div
const StillLoading = ({ metadataField, checkboxID }) => (
/*
We are still loading this category, so render a "busy" signal.
*/
<div
style={{
maxWidth: globals.maxControlsWidth,
}}
@@ -332,8 +335,8 @@ function StillLoading({ metadataField, checkboxID }) {
</div>
</div>
</div>
}
function ErrorLoading({ metadataField, error }) {
);
const ErrorLoading = ({ metadataField, error }) => {
console.error(error); // log error to console as it is unexpected.
return (
<div style={{ marginBottom: 10, marginTop: 4 }}>
@@ -349,7 +352,7 @@ function ErrorLoading({ metadataField, error }) {
</span>
</div>
);
}
};
const CategoryHeader = React.memo(
({
@@ -162,7 +162,7 @@ class CategoryValue extends React.Component {
);
};
shouldComponentUpdate(nextProps, nextState) {
shouldComponentUpdate = (nextProps, nextState) => {
/*
Checks to see if at least one of the following changed:
* world state
+2 -2
View File
@@ -109,7 +109,7 @@ const loadAllEmbeddingCounts = async ({ annoMatrix, available }) => {
}));
};
function EmbeddingChoices({ onChange, annoMatrix, layoutChoice }) {
const EmbeddingChoices = ({ onChange, annoMatrix, layoutChoice }) => {
const { available } = layoutChoice;
const { data, error, isPending } = useAsync({
promiseFn: loadAllEmbeddingCounts,
@@ -149,4 +149,4 @@ function EmbeddingChoices({ onChange, annoMatrix, layoutChoice }) {
);
}
return null;
}
};
+2 -2
View File
@@ -1,7 +1,7 @@
import React from "react";
import icon from "../../images/icon.png";
function Logo(props) {
const Logo = (props) => {
const { size } = props;
return (
<img
@@ -11,6 +11,6 @@ function Logo(props) {
alt="CELLxGENE Annotate Logo"
/>
);
}
};
export default Logo;
@@ -53,7 +53,8 @@ class AddGeneToGenesetDialogue extends React.PureComponent {
const { genesToAdd } = this.state;
return (
<AnnoDialog
<>
<AnnoDialog
isActive={genesetsUI.isAddingGenesToGeneset === geneset}
inputProps={{ "data-testid": `${geneset}:create-label-dialog` }}
primaryButtonProps={{
@@ -80,6 +81,7 @@ class AddGeneToGenesetDialogue extends React.PureComponent {
handleSubmit={this.handleAddGeneToGeneSet}
handleCancel={this.disableAddGeneMode}
/>
</>
);
}
}
@@ -125,7 +125,8 @@ class CreateGenesetDialogue extends React.PureComponent {
const { genesetsUI, genesets } = this.props;
return (
<Dialog
<>
<Dialog
icon="tag"
title="Create gene set"
isOpen={genesetsUI.createGenesetModeActive}
@@ -209,6 +210,7 @@ class CreateGenesetDialogue extends React.PureComponent {
</div>
</form>
</Dialog>
</>
);
}
}
@@ -109,7 +109,8 @@ class RenameGeneset extends React.PureComponent {
} = this.props;
return (
<AnnoDialog
<>
<AnnoDialog
isActive={genesetsUI.isEditingGenesetName === originalGenesetName}
inputProps={{
"data-testid": `${genesetsUI.isEditingGenesetName}:rename-geneset-dialog`,
@@ -160,6 +161,7 @@ class RenameGeneset extends React.PureComponent {
handleSubmit={this.renameGeneset}
handleCancel={this.disableEditGenesetNameMode}
/>
</>
);
}
}
+10 -5
View File
@@ -935,7 +935,7 @@ class Graph extends React.Component {
}
}
function ErrorLoading({ displayName, error, width, height }) {
const ErrorLoading = ({ displayName, error, width, height }) => {
console.log(error); // log to console as this is an unepected error
return (
<div
@@ -949,10 +949,14 @@ function ErrorLoading({ displayName, error, width, height }) {
<span>{`Failure loading ${displayName}`}</span>
</div>
);
}
};
function StillLoading({ displayName, width, height }) {
return <div
const StillLoading = ({ displayName, width, height }) =>
/*
Render a busy/loading indicator
*/
(
<div
style={{
position: "fixed",
fontWeight: 500,
@@ -972,6 +976,7 @@ function StillLoading({ displayName, width, height }) {
<span style={{ fontStyle: "italic" }}>Loading {displayName}</span>
</div>
</div>
}
)
;
export default Graph;
@@ -167,7 +167,7 @@ class CentroidLabels extends PureComponent {
}
}
function Label({
const Label = ({
label,
dilatedValue,
coords,
@@ -177,7 +177,7 @@ function Label({
displayLabel,
onMouseEnter,
onMouseOut,
}) {
}) => {
/*
Render a label at a given coordinate.
*/
@@ -215,4 +215,4 @@ function Label({
</text>
</g>
);
}
};
+3 -1
View File
@@ -159,7 +159,8 @@ export default class LabelInput extends React.PureComponent {
};
const { queryResults } = this.state;
return (
<Suggest
<>
<Suggest
fill
inputValueRenderer={(i) => i.target}
items={queryResults}
@@ -171,6 +172,7 @@ export default class LabelInput extends React.PureComponent {
inputProps={inputProps}
onKeyDown={this.handleKeyDown}
/>
</>
);
}
}
+2 -2
View File
@@ -35,11 +35,11 @@ export default class MiniHistogram extends React.PureComponent {
}
};
componentDidMount() {
componentDidMount = () => {
this.drawHistogram();
};
componentDidUpdate(prevProps) {
componentDidUpdate = (prevProps) => {
const { obsOrVarContinuousFieldDisplayName, bins } = this.props;
if (
prevProps.obsOrVarContinuousFieldDisplayName !==
@@ -42,12 +42,12 @@ export default class MiniStackedBar extends React.PureComponent {
}
};
componentDidUpdate(prevProps) {
componentDidUpdate = (prevProps) => {
const { occupancy } = this.props;
if (occupancy !== prevProps.occupancy) this.drawStacks();
};
componentDidMount() {
componentDidMount = () => {
this.drawStacks();
};
+1 -1
View File
@@ -32,7 +32,7 @@ const SECOND_HALF_INNER_STYLE = {
right: 0,
};
export default function(props) {
export default (props) => {
const { children, isGenesetDescription, tooltipAddendum = "" } = props;
// Truncate only support a single child with a text child
+1 -1
View File
@@ -1,6 +1,6 @@
import { Colors } from "@blueprintjs/core";
import ENV_DEFAULT from "Code/cellxgene/environment.default.json";
import { dispatchNetworkErrorMessageToUser } from "./util/actionHelpers";
import ENV_DEFAULT from "../../environment.default.json";
/* overflow category values are created using this string */
export const overflowCategoryLabel = ": all other labels";