Cytoscape session (.cys) ​
A Cytoscape session (.cys) is the file Cytoscape Desktop saves: a zip archive of every network open at the time, with their tables and views. It is the one binary format graph-io reads and writes, so always give it bytes, never text.
At a glance ​
| Import from | @graphty/graph-io/cys |
| Format name | cys |
| Extensions | .cys |
| MIME types | application/zip |
| Reads | yes |
| Writes | yes |
| Several graphs per file | yes (importAllGraphs) |
| Lists its graphs | yes (listGraphs) |
Loading and saving ​
import { readFile, writeFile } from "node:fs/promises";
import { checkExport, exportGraphToBytes, importGraph, listGraphs } from "@graphty/graph-io";
// A session is a zip file: always pass bytes, never text
const session = await readFile("networks.cys");
for (const g of (await listGraphs(session, { filename: "networks.cys" })) ?? []) {
console.log(`network ${g.index}: ${g.name}`);
}
const { snapshot } = await importGraph(session, { filename: "networks.cys", graphName: "Alpha" });
console.log(`Alpha: ${snapshot.nodeCount} nodes; node columns: ${snapshot.nodes.names().join(", ")}`);
// Write any graph as a session Cytoscape Desktop can open; session node ids are integers
const got = await importGraph(await readFile("got-network.graphml"), { filename: "got-network.graphml" });
const options = { sanitizeIds: "mangle" } as const;
console.log(checkExport(got.snapshot, "cys", options).map((n) => n.code));
await writeFile("got.cys", await exportGraphToBytes(got.snapshot, "cys", options));network 0: Beta
network 1: Alpha
Alpha: 4 nodes; node columns: graphics, name, position, z, selected, score, count, big, tags, flags, formula, note, shared name, species, count#SHARED_ATTRS, appScore, count#MYAPP, parent, xgmml.subgraph, position@2
[
'W_COLUMN_NAME_CHANGED',
'W_ID_MANGLED',
'W_EDGE_IDS_GENERATED',
'W_CYS_UNSET_AS_EMPTY_STRING',
'W_STORAGE_CLASS_CHANGED'
]A session usually holds several networks. listGraphs() names them, and graphName or graphIndex picks one; importAllGraphs() reads them all. The example's networks.cys holds two, Alpha and Beta. It is one of the sample files, and is also in the graph-io repository under graph-io/docs/samples/ for working offline.
How graph-io reads it ​
- The zip archive is read with no extra dependency. Encrypted archives and compression methods other than deflate are refused by name.
- Each network of the session is one graph. Without
graphIndexorgraphName, the first one is read. - Cytoscape 3 sessions: the network's topology, its node, edge and network tables as columns (including shared columns and the hidden columns apps add), positions from its first view (y pointing up; further views as
position@2, ...), and the view's per-element visual values in thegraphicscolumn. Cytoscape 2 sessions: one XGMML file per network, with the selection and hidden state incytoscape.selectedandcytoscape.hidden. - Node ids are Cytoscape's SUIDs, as text: in a session Cytoscape saved, the first node's id is something like
"21". A table'snamecolumn, the name Cytoscape shows, is the label (byRole("label")), and a network'sweightedge column is the weight. A session that graph-io saved withsanitizeIds: "mangle"gives back the graph's original ids instead. To match the nodes against other data by name, read the label column: thenodeIdFromoption does not apply to sessions. - Groups become a parent column; the members of a collapsed group are listed in
snapshot.meta.extra.cytoscape.groups. - Styles are not applied (
W_STYLES_NOT_IMPORTED). Apps, properties and images in the archive are skipped withW_CYS_ENTRY_SKIPPED. - Text input is refused (
E_CYS_NOT_ZIP). - To protect against zip bombs, an import stops (
E_TOO_LARGE) once it would inflate more thanmaxUncompressedBytes(2 GiB by default) or an entry is compressed more than 1000 to 1.
What a saved file keeps and loses ​
graph-io writes a session Cytoscape Desktop 3 opens, holding one network with its columns as tables and the label as name. It writes a view only when the graph has positions: graph-io does not compute a layout, so without positions you create the view in Cytoscape.
Opening a session in Cytoscape replaces everything open there. To add a network to an open session, save XGMML or CX2 instead.
What does not survive:
- Cytoscape identifies every node by a SUID, a positive integer, and keeps the node's id as text in its
nameandshared namecolumns. So the node ids of a graph you save must be positive integers, which become the SUIDs. Other ids needsanitizeIds: "mangle", which numbers the nodes and keeps the originals in agraphty:originalIdcolumn; graph-io restores them. - Number ids read back as text (
W_ID_TEXT_TYPE), because a session stores ids as text. - Cytoscape's tables have no empty text cell, so a text cell with no value reads back as
""(W_CYS_UNSET_AS_EMPTY_STRING). - List cells are joined with line breaks (
W_CYS_LIST_ITEMS), JSON values are written as text (W_CYS_JSON_AS_STRING), and text starting with=is a formula to Cytoscape (W_CYS_TEXT_AS_EQUATION). - A column named like one of Cytoscape's own (
SUID, anamethat is not text, or a name that differs from one only in case) is renamed<name>#2(W_COLUMN_NAME_CHANGED). - The per-element visual values of a session that graph-io read (the
graphicscolumn) are not written back as visual values. They are written as an ordinary table column of JSON text, and read back asgraphics#2, because the reader makes its owngraphicscolumn from the view (W_COLUMN_NAME_CHANGED). The same goes forcytoscape.nestedNetworkand the other columns the reader makes. So a session read and saved again by graph-io loses its per-element colors, shapes and sizes, and Cytoscape draws it with the session's style. - Edge ids are generated when the graph has none (
W_EDGE_IDS_GENERATED). - Groups, styles and time columns are not written.
- The archive is stored without compression, so it is larger than the same session saved by Cytoscape.
What a saved file can hold (the capabilities explain each row):
| Capability | Value |
|---|---|
mixedDirection | yes |
multiEdges | yes |
selfLoops | yes |
edgeIds | required |
idCharset | integer |
dtypes | string, dict, f64, i32, bool, list |
components | no |
lists | yes |
json | no |
defaults | no |
options | no |
hierarchy | no |
temporal | none |
graphAttributes | yes |
positions | yes |
viz | no |
Import options ​
These come on top of the options every importer takes. A file can hold several graphs: pick one with the graphIndex or graphName option of importGraph(), as Files that hold several graphs shows.
| Option | Type | Default |
|---|---|---|
zAs | "column" | "position" | "column" |
maxUncompressedBytes | number | 2147483648 |
zAs: Where Cytoscape'szvalue (a drawing order, not a depth) goes: "column" keeps it as a node attribute namedz; "position" makes it the third coordinate of the position.maxUncompressedBytes: The most bytes one import may unpack from the session archive, in total (2 GiB). A file that would unpack to more, or one compressed more than 1000 to 1, fails withE_TOO_LARGE.
Export options ​
These come on top of the options every exporter takes.
This format has no options of its own.
Import issue codes ​
The codes this format's import report can hold. They are also exported as CYS_ISSUE from @graphty/graph-io/cys, keyed by the code without its E_ / W_ and CYS_ prefixes.
E_EMPTY_INPUT(error): The input is empty.E_TOO_LARGE(error): The archive inflates beyond maxUncompressedBytes, or an entry beyond the ratio limit.W_ENCODING_FALLBACK(warning): A session XML entry that is not UTF-8 and declares no encoding was read as windows-1252.W_UNKNOWN_ENCODING(warning): A session XML entry declares an encoding the platform cannot decode; read as UTF-8.E_XML_SYNTAX(error): The XML is not well-formed; the message says where. The import stops.E_INVALID_UTF8(error): The input is not valid UTF-8. The import stops.E_INVALID_ENCODING(error): Some bytes are not valid in the encoding that was chosen (by a byte order mark, the file's own declaration or theencodingoption). The import stops.E_NO_GRAPH(error): The session holds no network.E_XGMML_VIEW_DOCUMENT(error): The file is a Cytoscape session view (cy:view="1"), which holds only view settings and no nodes or edges. The import stops.E_MISSING_ID(error): The element (node, attribute, key, ...) has no id where the format requires one.W_XGMML_ID_FROM_LABEL(warning): A node without an id; its label is used as the id.W_XGMML_ID_AND_HREF(warning): A node or edge with both an id and anxlink:href; it is read as the reference.E_MISSING_ENDPOINT(error): An edge has no source or no target.W_XGMML_LABEL_ALIAS(warning): Endpoints resolved through Cytoscape's"a (pp) b"label aliases; interactions filled from labels.W_DUPLICATE_NODE(warning): A node id declared twice; the second declaration merges into the first.W_XGMML_GROUP_DUPLICATE_EDGE(warning): Cytoscape 2.x writes each edge of a group a second time, inside the group. The repeats are dropped, so every edge is read once; nothing is lost.W_XGMML_BAD_DIRECTED(warning): Adirectedorcy:directedvalue other than 0 / 1.W_XGMML_DOCUMENT_VERSION(warning): AdocumentVersionthat does not parse; the dialect is chosen from the content.W_XGMML_NO_NAMESPACE(warning): A root<graph>with neither the XGMML namespace nor an XGMML DOCTYPE.W_XGMML_BAD_ATT(warning): A malformed<att>: a list with a value, a scalar with child atts, an att with no name.W_XGMML_AMPERSAND_REPAIRED(warning): A bare&read as&under repairBareAmpersands.W_XGMML_SURROGATE_PAIRED(warning): Two surrogate character references joined under pairSurrogateReferences.W_XGMML_EMPTY_LIST_TYPE(warning): An empty list whose element type nothing states; a list of strings is assumed.W_XGMML_RECORD_LIST(warning): An attribute holds a structure a single column cannot (a list of records, a list of lists, a Cytoscape 2.x map or XML from another tool). Its value is kept as a JSON value, which a save as XGMML writes back.W_XGMML_CROSS_FILE_REFERENCE(warning): A pointer into another file (file.xgmml#id); kept as text.W_XGMML_EDGE_NESTED_GRAPH(warning): A graph nested in an edge's att; there is no model for it.W_XGMML_ROOT_ONLY_ELEMENTS(warning): Some nodes or edges of a Cytoscape session belong to none of its networks (Cytoscape keeps group meta-edges and the members of collapsed groups this way). They are not read; the message counts them.E_BAD_VALUE(error): A value does not parse as its declared type; the cell is left unset.W_WIDENED(warning): An attribute's type was widened because a later value did not fit: an integer above 2^31 in an integer column, or two declared types for one attribute.W_PRECISION(warning): An integer beyond 2^53 was stored as the nearest 64-bit float; passlong: "string"to keep every digit.W_DANGLING_REFERENCE(warning): A view, table or network the session names but does not hold.W_DUPLICATE_ATTRIBUTE(warning): The same attribute twice on one element; one value is kept (the later, unless the format's specification says the first).E_UNKNOWN_PARENT(error): Apid/ parent reference names a node the document never declares.E_PARENT_CYCLE(error): A containment link would close a parent cycle; that one link is dropped.W_EQUATION_AS_TEXT(warning): A formula (Cytoscape's=ABS($x)) is kept as its text; it is never evaluated.W_UNKNOWN_ATTR_TYPE(warning): The declared type is not one the format defines; the column is kept as string.W_UNKNOWN_ELEMENT(warning): An element the format does not define at that place was skipped.W_STRAY_TEXT(warning): Text where the format allows only elements was ignored.W_MULTIPLE_GRAPHS(warning): The file holds several graphs and only the first was read. It is not added whengraphIndexorgraphNamechose the graph.importAllGraphs()reads every one.E_GRAPH_NOT_FOUND(error):graphIndexorgraphNamematches no network in the session. The import stops.E_AMBIGUOUS_GRAPH_NAME(error):graphNamematches several networks in the session. The import stops.W_COLUMN_RENAMED(warning): An attribute was renamed<name>#<suffix>because another attribute already has its name, for example a repeated column header.W_ROLE_TAKEN(warning): You read into a graph builder that already has an id, label or position attribute, so this file's one is kept as a plain attribute.W_ID_MERGED(warning): Two different id texts became the same number becauseidsis "number" (for example, "042" and "42"), so their nodes were merged.W_OPTION_IGNORED(warning): You set an option this format does not use; it had no effect. The message names the option.W_SINK_OPTION(warning): You read into your own graph builder, which was created with a differentaddMissingNodes,duplicateEdges,selfLoopsorweightDtypethan the option you passed; the builder's setting applies.W_DIRECTION_REFUSED(warning): You read into a graph builder that already holds edges (or whose direction is locked), and its direction differs from the file's, so the file is read with the builder's direction. A builder without edges takes the file's direction.W_DIRECTION_FORCED(warning):onMixedDirection("directed" or "undirected") made edges take a direction the file did not give them. It can appear twice in one report: once for the direction the file declares and once for the edges that declared their own.E_MIXED_DIRECTION(error): The graph has both directed and undirected edges andonMixedDirectionis "error". An import stops; a save to a format that holds one direction per file fails withE_DIRECTED. Pass "directed" or "undirected" to read or write it anyway.E_CYS_NOT_ZIP(error): The input is not a zip archive (or is text).E_CYS_CORRUPT(error): The archive is damaged: no end record, offsets outside the file, a bad CRC, truncated data.E_CYS_NOT_SESSION(error): A zip without a session marker (<x.y.z>.versionorcysession.xml).E_CYS_UNSUPPORTED(error): A zip feature the reader does not support: encryption, a compression method, split archives.E_CYS_VERSION(error): A session version graph-io cannot read: a major above 3, or the 2011 3.0 pre-release layout.E_CYS_TABLE(error): A table or a virtual column that cannot be read at all; it is skipped.W_CYS_TABLE_ROW(warning): Table rows with too few or too many cells, a repeated key, or a key matching no element.W_CYS_COLLAPSED_GROUP(warning): The members of a collapsed group are not in the network itself; they are listed insnapshot.meta.extra.W_CYS_ENTRY_SKIPPED(warning): Entries the importer does not read (apps, global tables, properties, images, thumbnails).W_CYS_DUPLICATE_ENTRY(warning): Two entries with one name; the first is read.W_CYS_SESSION_RECORD(warning): A cysession.xml network record without an id, or naming a file an earlier record names.W_STYLES_NOT_IMPORTED(warning): The session's styles are not applied.
Like every format, it can also record the codes for unreadable input and for elements the graph refuses: W_ENCODING_CONFLICT, W_CONTROL_CHARACTER, E_FOREIGN_FORMAT, W_ISSUES_SUPPRESSED, E_INVALID_ID, E_UNKNOWN_NODE, E_INVALID_WEIGHT, E_DUPLICATE_EDGE, E_SELF_LOOP, E_DUPLICATE_EDGE_ID.
Loss codes ​
The codes checkExport(snapshot, "cys", options) can return before a save, also exported as CYS_LOSS from @graphty/graph-io/cys. An E_ code means the save throws unless you change the graph or the options.
W_CYS_UNSET_AS_EMPTY_STRING(warning): CyCSV has no unset text cell: an unset cell of a text column reads back as "".W_CYS_LIST_ITEMS(warning): List cells CyCSV cannot hold exactly: an unset or empty list of text reads back as [""], an empty list of numbers or booleans reads back unset, trailing empty text items vanish, and an item holding a newline splits in two.W_CYS_TEXT_AS_EQUATION(warning): A text cell starting with "=" is a formula to Cytoscape (an error cell there); graph-io reads it back as text.W_CYS_JSON_AS_STRING(warning): A nested (json) column is written as a text column holding its JSON text.W_CYS_POSITION(warning): A position that cannot be written as it is: another shape, a non-finite coordinate, a z read back in the z column.W_COLUMN_NAME_CHANGED(warning): An attribute with a role (for example, the label) is written where the format keeps that role, and reads back under the name the format's importer gives it.W_ROLE_ASSUMED(warning): An attribute without a role is written where the format keeps a role (for example, anamecolumn as the label), and reads back with that role.W_MUTUAL_EXPANDED(warning): A mutual pair is written as two directed edges without its mark.W_ID_TEXT_TYPE(warning): Node ids that are numbers read back as their text.E_ID_TEXT_COLLISION(error, the save throws): Two node ids would be written as the same text (the number 5 and the text "5"); the save fails withE_INVALID_ID.E_ID_CHARSET(error, the save throws): Node ids the format cannot write, undersanitizeIds: "error"; the save fails withE_INVALID_ID. PasssanitizeIds: "mangle"to rewrite them.W_ID_MANGLED(warning): Node ids that are not positive integers under sanitizeIds "mangle": renumbered, originals kept.W_EDGE_IDS_GENERATED(warning): Edges without a usable id get generated SUIDs.W_DTYPE_UNSUPPORTED(warning): An attribute type Cytoscape stores as a wider one (a 32-bit float as Double, a byte as Integer), or a label that is not text and is written as text; it reads back with the Cytoscape type.W_EMPTY_COLUMN_DROPPED(warning): A column whose every cell is unset (and which is not text) vanishes.W_STORAGE_CLASS_CHANGED(warning): A text attribute reads back as a dictionary attribute, or the reverse, because the importer chooses by how often its values repeat. The values are the same.W_WEIGHT_KEY_CLASH(warning): A plainweightedge column reads back as the edge weight.W_HIERARCHY_DROPPED(warning): A parent / parents column: groups are not written.W_TEMPORAL_DROPPED(warning): A start / end / timestamp column: sessions have no time.W_ROLE_DROPPED(warning): An attribute with a role the format has no place for is written as a plain attribute; the role is lost.W_EXTENSION_TABLE_DROPPED(warning): An extension table the session cannot carry.
When the graph has something this format cannot hold, it can also return the shared loss codes: E_MIXED_DIRECTION, E_XML_ILLEGAL_CHAR, W_COLUMN_DROPPED, W_COMPONENTS_FLATTENED, W_DEFAULT_DROPPED, W_DYNAMIC_VALUES_DROPPED, W_EDGE_IDS_DROPPED, W_GRAPH_ATTRIBUTES_DROPPED, W_ID_RENUMBERED, W_INTEGRAL_F64_AS_I32, W_JSON_UNSUPPORTED, W_LIST_UNSUPPORTED, W_MIXED_DIRECTION, W_MULTI_EDGES, W_MUTUAL_AS_UNDIRECTED, W_NONFINITE_AS_NULL, W_OPEN_INTERVAL, W_OPTIONS_DROPPED, W_OPTIONS_GAINED, W_PARENTS_DROPPED, W_POSITIONS_DROPPED, W_SELF_LOOPS, W_SPELLS_DROPPED, W_TEMPORAL_TEXT_DROPPED, W_TEXT_INFERRED, W_VIZ_DROPPED, W_WEIGHTS_DROPPED.