Load a table of embedding coordinates (one row per cell).
Columns like UMAP_1 / UMAP_2 or tSNE_1 / tSNE_2 are auto-detected,
plus a cluster / cell-type column to color by.
Use Browse file, drop a CSV / TSV, or click Demo Data.
Load a table of embedding coordinates (one row per cell).
Columns like UMAP_1 / UMAP_2 or tSNE_1 / tSNE_2 are auto-detected,
plus a cluster / cell-type column to color by.
Use Browse file, drop a CSV / TSV, or click Demo Data.
What this tool does
This is a viewer for precomputed 2D embeddings. It plots coordinates you already generated (UMAP, t-SNE, PHATE, or any two numeric columns). It does not run the embedding itself. Compute the embedding in Scanpy, Seurat, or scikit-learn, then plot and style it here.
Input format
CSV, TSV or semicolon-separated text with one row per cell/point. Include two coordinate columns (e.g. UMAP_1, UMAP_2) and any metadata columns. Quoted fields may contain commas and line breaks, and any line ending (Windows, Unix or old Mac) works. Numbers must be plain decimals (1.5, -2, 3e-4); text such as 0x10 stays text. In a tab- or semicolon-separated file, a column written entirely with decimal commas (1,5) is read as 1.5 and the tool says so; a column with numbers like 1.234 gets a note, because the dot may be a thousands separator. Numbers written like 1.234,5 (dot for thousands, comma for decimals) are not converted: the column is read as text and the tool says so, so rewrite them as plain numbers. Repeated column names get " (2)", " (3)" added, so every column name is unique. If fewer than two numeric columns are found, the tool shows an error instead of a plot.
Empty cells and NA, NaN, N/A, #N/A, NULL, None, <NA> and NaT (any capitalization) count as missing in every column. In a number column, Inf and -Inf are also treated as missing, and the tool says how many. If a number column contains other text, those cells are shown as missing and the tool tells you how many. A column of whole-number cluster codes that also contains text labels (for example "doublet") is treated as categories, so no label is lost.
Point IDs
Tooltips and copied points are named after a text column that has a different value on every row, preferring a column named like an ID (cell_id, barcode). If no column is unique, points are named "Row N", where N is the data row in the file (1 is the first row below the header; blank lines are not counted).
Coordinates
The X and Y columns are auto-detected from common names (UMAP, tSNE, PHATE, dim1/dim2, x/y). Override them with the Coordinates selectors.
Color
Color by a categorical column (cluster, cell type) for a discrete legend, or by a numeric column (gene expression, QC metric) for a continuous colormap with a colorbar. Text columns are categories. Numeric columns use a color scale, except whole-number columns whose name ends in a grouping word (cluster, leiden, louvain, seurat_clusters, cell type, sample, batch, group, condition, stage, orig.ident and similar), which start as categories. Resolution tags, ids, names and method names at the end of the header are ignored, so Clusters_res1, seurat_clusters_res0.8, leiden_scVI and Sample_Name start as categories. Names that read as counts or measurements keep a color scale: anything starting with n, num, total, count or mean, anything containing "per", and names ending in another word, such as sample_size, batch_count, cells_per_cluster or n_clusters. Use "As" to switch any column to the other reading. The column chosen automatically for Color by is never the point ID column. A note under "As" gives the reason; use "As" to switch. Constant columns are listed with "(constant)" and color every point with the lowest color.
Groups are listed and colored in natural order ("Cluster 2" before "Cluster 10"), so colors do not depend on the order of rows in the file. The default palette follows Scanpy: matplotlib's tab10 for up to 10 groups, Scanpy's default_20 up to 20, default_28 up to 28, default_102 up to 102, and grey for every group beyond that (with a note). A palette you pick is used whenever it has enough colors; if not, Scanpy's choice is used and a note under the palette menu says so. Points with no value are drawn underneath the others and get a "(no value)" legend entry. A group none of whose points can be drawn is marked "(not drawn)".
All color statistics (group counts, percentiles, minimum, maximum, missing values) use only the rows that have both coordinates, as Scanpy and Seurat do. For continuous coloring, the color range is clipped to the chosen percentiles to tame outliers; the colorbar then marks its ends with ≥ and ≤. If both percentiles are equal (common for a sparse gene that is mostly zero), the full range of values is used instead, and the figure legend and Statistics say so. Colormaps match matplotlib's.
Draw order
File order (the default, as in Scanpy and Seurat) paints points in the order of the rows. Random (seeded) shuffles them the same way every time, which avoids one group covering another just because it comes last in the file. "Small groups / high values on top" paints the largest groups first, or low values first on a color scale. Missing values are always painted first. The screen, PNG and SVG use the same order, and the figure legend states it.
Opacity is applied to each run of consecutive points of the same color as a whole, so overlapping points in a run do not get darker. Opacity is a styling choice here, not a way to show point density.
Cluster labels
With categorical coloring, group names are drawn at each group's median position. Toggle with "Show cluster labels".
Zoom, pan, and select
Scroll to zoom, drag to pan, and use ⟳ to reset the view. Hover a point to inspect it; click to select. A selection stays on the same points when you change the color column, the color mode or the clip; selected points that are no longer drawn are removed and the status line says so. Changing X, Y or Draw all points clears the selection. Click a group's dot in the Groups panel to hide or show that cluster.
Large datasets
Up to 500,000 points are held in the browser. Files larger than that are randomly subsampled on load, and the Points count then reads "500,000 (sample of …)". For responsiveness the plot draws a seeded subsample of 150,000 of the points that have coordinates; tick "Draw all points" to render every one. With categorical coloring the subsample is stratified by group: every group of up to 500 points is drawn in full, so rare populations never vanish, and larger groups are sampled in proportion to their size. With very many groups, 500 points per group would use more than half of the 150,000 drawn points, so the limit is lowered to fit; the figure legend states the exact number used. Otherwise it is a uniform random subsample. Each sample has its own fixed seed, so the same file always gives the same plot. Rows without both coordinates are not drawn and are counted in Statistics. When you zoom in, the figure legend says how many of the shown points are inside the frame.
Equal aspect ratio
Embedding axes share one scale, so the plot keeps a 1:1 aspect ratio by default. Turn it off to stretch the plot to fill the canvas.
Export
PNG honors the DPI selector (300 is publication standard) and records it in the file, so it opens at the right physical size. SVG draws the same points, shapes, order, opacity and stepped colorbar as the screen. Up to 20,000 points are written as editable vector shapes; denser scatters embed the points as a raster layer at the chosen DPI while axes, labels, legend, and colorbar stay editable vector. Copy puts a PNG on the clipboard. Exports capture the current zoom/pan view. Hover and selection only pick points inside the plot frame. Copy selected points gives the file's exact coordinates and color values.
Third-party notices
The plot uses colormaps and palettes made by others, reproduced under their licences:
Copyright (c) 2017, Battelle Memorial Institute 1. Battelle Memorial Institute (hereinafter Battelle) hereby grants permission to any person or entity lawfully obtaining a copy of this software and associated documentation files (hereinafter "the Software") to redistribute and use the Software in source and binary forms, with or without modification. Such person or entity may use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and may permit others to do so, subject to the following conditions: + Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimers. + Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + Other than as used herein, neither the name Battelle Memorial Institute or Battelle may be used in any form whatsoever without the express written consent of Battelle. 2. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BATTELLE OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
BSD 3-Clause License Copyright (c) 2025 scverse® Copyright (c) 2017 F. Alexander Wolf, P. Angerer, Theis Lab All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
If this tool was useful in your work, please cite it as:
EuropaDX, Inc. (2026). UMAP / t-SNE Plotter. EuropaXp OmicsCloud Bioinformatics Toolkit. Available at https://europadx.com/tools/umap/The plotter runs entirely client-side and holds up to ~500,000 points in the browser. Larger datasets are randomly subsampled on load, which may hide rare populations.
EuropaXp OmicsCloud handles datasets of any size with full single-cell pipelines, persistent workspaces, and reproducible reports.