Module 9.2 Lab: g:profiler Visualization
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License. This means that you are able to copy, share and modify the work, as long as the result is distributed under the same license.
By Gary Bader, Ruth Isserlin, Veronique Voisin
Goal of the exercise
Create an enrichment map and navigate through the network
During this exercise, you will learn how to create an enrichment map from gene-set enrichment results. The enrichment results chosen for this exercise are generated using
g:Profiler but an enrichment map can be created directly from output from:
GSEA,
Enrichr or
alternately from any gene-set tool using the generic enrichment results (GEM) format.
Data
The data used in this exercise is a differentially expressed gene set from palbociclib-resistant samples compared with parental samples from the breast cancer cell line MCF7 previous exercise.
EnrichmentMap
A circle (node) is a gene-set (pathway) enriched in genes that we used as input in g:Profiler (frequently mutated genes).
edges (lines) represent genes in common between 2 pathways (nodes).
A cluster of nodes represent overlapping and related pathways and may represent a common biological process.
Clicking on a node will display the genes included in each pathway.

Description of this exercise
We will create EnrichmentMaps from:
- Two g:Profiler results run on UP- and DOWN-regulated genes separately .
- fgsea results using the Baderlab gene set file .
An enrichment map represents the result of enrichment analysis as a network where significantly enriched gene-sets that share a lot of genes in common will form identifiable clusters. The visualization of the results as these biological themes will ease the interpretation of the results.
The goal of this exercise is to learn how to:
- Upload g:Profiler results into Cytoscape EnrichmentMap to create a map.
- Upload UP and DOWN regulated g:Profiler results at the same time to create one combined map.
- Create an EnrichmentMap from fgsea results using the Baderlab gene set file.
Start the exercise
To start the lab practical section, first create a gprofiler_files directory on your computer and download the files below.
Right click on link below and select “Save Link As…”.
Place it in the corresponding module directory of your CBW work directory.
Two input files are needed to generate all the enrichment results:
- Differential expression results: edgeR_resistant_vs_parental_all_genes.csv * Full edgeR output with columns: logFC, logCPM, F, PValue, FDR, gene, score
- Custom Baderlab gene set file: Human_GOBP_AllPathways_filtered_500orLessV2.gmt * Pre-filtered to gene sets with 500 or fewer genes
- enrichment_results_gprofiler_UPgenes.gem.txt — g:profiler UP genes results, GEM format for EnrichmentMap
- enrichment_results_gprofiler_DNgenes.gem.txt — g:profiler DOWN genes results, GEM format for EnrichmentMap
- gprofiler_full_hsapiens.name.gmt — downloaded from g:Profiler
The Baderlab custom GMT
(Human_GOBP_AllPathways_filtered_500orLessV2.gmt) is
pre-filtered to gene sets with 500 or fewer genes, which means the FDR
correction is applied only to those gene sets — giving more statistical
power than filtering after the fact.
evcodes = TRUE in the gost() call is
required to get the intersection column, which contains the
actual gene IDs from your query that overlap with each term. Despite the
name, this is not GO evidence codes — it is the intersecting gene
identifiers.
RCy3 Setup — run once before all exercises
library(RCy3)
library(httr)
library(jsonlite)
path_to_save_cytoscape = "/Users/risserlin/CBW_Workshop_results/Module9"
# Set base URL — adjust if not running from Docker
current_cytoscape_baseurl <- "http://localhost:1234/v1"
cytoscapePing(base.url = current_cytoscape_baseurl)
cytoscapeVersionInfo(base.url = current_cytoscape_baseurl)
# Helper: upload a local file to Cytoscape so EM can read it.
# EnrichmentMap's upload endpoint sits outside /v1.
upload_em_file <- function(localPath) {
bname <- basename(localPath)
base_no_v1 <- sub("/v1$", "", current_cytoscape_baseurl)
r <- httr::POST(
url = paste0(base_no_v1,
"/enrichmentmap/textfileupload?fileName=", bname),
config = list(),
body = list(file = httr::upload_file(localPath)),
encode = "multipart",
handle = NULL
)
jsonlite::fromJSON(rawToChar(r$content))$path
}
# Helper: convert fgsea CSV result to GEM format and write to disk.
# g:Profiler GEM files are already written by the prepare-enrichment-files chunk.
fgsea_csv_to_gem <- function(csv_path, gem_path) {
fs <- read.csv(csv_path, stringsAsFactors = FALSE)
gem <- data.frame(
Name = fs$pathway,
Description = fs$pathway,
pvalue = fs$pval,
qvalue = fs$padj,
phenotype = ifelse(fs$NES >= 0, 1, -1),
genes = fs$leadingEdge,
stringsAsFactors = FALSE
)
write.table(gem, file = gem_path, sep = "\t",
quote = FALSE, row.names = FALSE, col.names = TRUE)
invisible(gem_path)
}
# ── File paths (g:Profiler GEMs written by prepare-enrichment-files chunk) ───
data_dir <- "./Module9/gprofiler/data"
up_gem <- file.path(data_dir, "enrichment_results_gprofiler_UPgenes.gem.txt")
dn_gem <- file.path(data_dir, "enrichment_results_gprofiler_DNgenes.gem.txt")
fgsea_csv <- file.path(data_dir, "fgsea_resistant_vs_parental.csv")
fgsea_gem <- file.path(data_dir, "fgsea_report_for_list.tsv")
gmt_gprofiler <- file.path(data_dir, "gprofiler_full_hsapiens.name.gmt")
gmt_baderlab <- file.path(data_dir, "Human_GOBP_AllPathways_filtered_500orLessV2.gmt")
rnk_file <- file.path(data_dir, "resistant_vs_parental.rnk")
message("Setup complete. All GEM files ready in: ", data_dir)Exercise 1a - compare UP and DOWN regulated g:Profiler results
Step 1
Launch Cytoscape and open the EnrichmentMap App
1a. Double click on Cytoscape icon
1b. Open EnrichmentMap App
In the Cytoscape top menu bar:
Click on Apps -> EnrichmentMap

- A ‘Create Enrichment Map’ window is now opened.
Step 2
Create an enrichment map from the UP and DOWN g:Profiler result files.
2a. In the ‘Create Enrichment Map’ window, drag and drop the 2 enrichment files enrichment_results_gprofiler_UPgenes.gem.txt and enrichment_results_gprofiler_DNgenes.gem.txt.

2b. In the white box, click on “enrichment_results_gprofiler_UPgenes (Generic/gProfiler)”
2c. On the right side, go to the GMT field, click on the 3 radio button (…) and locate the file gprofiler_full_hsapiens.name.gmt that you have saved on your computer to upload it.

2d. In the white box, click on “enrichment_results_gprofiler_DNgenes (Generic/gProfiler)”
2e. On the right side, go to the GMT field, click on the 3 radio button (…) and locate the file gprofiler_full_hsapiens.name.gmt that you have saved on your computer to upload it.
2f. Locate the FDR q-value cutoff field and set the value to 0.01
2g. Select the Connectivity slide bar to sparse.

Instead of specifying the gmt file for each dataset separately, if all the datasets in your analysis use the same gmt file, you can specify a common gmt file to be used by all datasets.
-
Click +Add… and select Add Common Files
- On the right side, go to the GMT file field, click on the 3 radio button (…) and locate the file gprofiler_full_hsapiens.name.gmt that you have saved on your computer to upload it.
This can also be done for a shared expression file.
2h. Click on Build.
If you have specified common files this info box will appear
* Click on Continue to build
- A status bar should pop up showing progress of the Enrichment map build.
There might be multiple messages that appear when you first create an enrichment map. You can choose to silence them if you want (Although the yfiles message will continue to appear every two weeks).
* Click on OK
* Click on OK
Step 3: Explore the results:
In the EnrichmentMap control panel located at the left:
- Select the 2 Data Sets (checked by default)
- Set Chart Data to Color by Data Set
- Select Publication Ready to remove gene-set label to have a global view of the map.
un-select Publication Ready when you explore the map in more detail to see the gene-set names.
On the map, a node that is coloured both green and blue is a gene-set that is found in both the UP and DOWN g:Profiler result sets.
- A node that is blue is a gene-set that is found only in the DOWN-regulated results (enrichment_results_gprofiler_DNgenes).
- A node that is green is a gene-set that is found only in the UP-regulated results (enrichment_results_gprofiler_UPgenes).
- A blue edge represents genes that overlap between gene-sets found in the DOWN-regulated results.
- A green edge represents genes that overlap between gene-sets found in the UP-regulated results.

Are there pathways enriched in both the UP and DOWN gene lists? What might this mean biologically?
Explore Detailed results
- In the Cytoscape menu bar, select ‘View” and ’Show Graphic Details’ to display node labels.
Make sure you have unselected “Publication Ready” in the EnrichmentMap control panel.
Zoom in to be able to read the labels and navigate the network using the bird eye view (blue rectangle).
Select a node and visualize the Table Panel
Click on a node
For this example the node “MET_activates” has been selected.
you can type it in the search bar, quotes are important.

When the node is selected, it is highlighted in yellow.
In table panel, we can see the genes included in the gene-set.
A green colored box indicates that the gene is in the gene-set(pathway) and in our gene list.
A gray colored box indicated that the gene is in the gene-set but not in our gene list.

Equivalent RCy3 code — Exercise 1a: Build EM from UP and DOWN g:Profiler results
# Upload GEM files to Cytoscape
up_gem_cyto <- upload_em_file(up_gem)
dn_gem_cyto <- upload_em_file(dn_gem)
gmt_cyto <- upload_em_file(gmt_baderlab)
# Build the EnrichmentMap with both datasets
em1a_command <- paste(
"enrichmentmap build",
"analysisType=generic",
paste0("enrichmentsDataset1=", up_gem_cyto),
paste0("gmtFile=", gmt_cyto),
paste0("enrichmentsDataset2=", dn_gem_cyto),
"qvalue=0.01",
"pvalue=1.0",
"coefficients=JACCARD",
"similaritycutoff=0.35",
sep = " "
)
commandsRun(em1a_command, base.url = current_cytoscape_baseurl)
# Get the newly created network
em1a_suid <- getNetworkSuid(base.url = current_cytoscape_baseurl)
message("Exercise 1a EM SUID: ", em1a_suid)
existing_names <- getNetworkList(base.url = current_cytoscape_baseurl)
new_name <- "EM_UP_vs_DN_gprofiler"
if (new_name %in% existing_names) {
new_name <- paste0(sample(1000:9999, 2),"_",new_name )
}
renameNetwork(new_name,
network = getNetworkSuid(base.url = current_cytoscape_baseurl),
base.url = current_cytoscape_baseurl)
message("Network renamed to: ", new_name)
# Apply a layout
layoutNetwork("force-directed defaultSpringCoefficient=0.00004 defaultSpringLength=5",
network = em1a_suid, base.url = current_cytoscape_baseurl)
# Search for a specific node (e.g. "MET activates") and select it
selectNodes(nodes = "MET ACTIVATES PTK2 SIGNALING%REACTOME DATABASE ID RELEASE 97%8874081", by.col = "name",
network = em1a_suid, base.url = current_cytoscape_baseurl)
# View the node table for the selected node
selected_node_table <- getTableColumns(
table = "node",
network = em1a_suid,
base.url = current_cytoscape_baseurl
)
# Filter to the selected node
selected_nodes <- getSelectedNodes(network = em1a_suid,
base.url = current_cytoscape_baseurl)
print(selected_node_table[selected_node_table$name %in% selected_nodes, ])Exercise 1b - create EM from fgsea results using Baderlab genesets
Create an enrichment map from fgsea results run using the custom Baderlab gene-set file.
Using a pre-filtered pathway database (max 250 genes per set) means the FDR is calculated only on these gene-sets, giving a more focused and interpretable result compared to filtering after the fact.
For this exercise, we will use:
fgsea result file: fgsea_report_for_list.tsv
Filtered gmt file: Human_GOBP_AllPathways_filtered_500orLessV2.gmt.
To create an enrichment map of these results:
Go to Control Panel and select the EnrichmentMap tab.
Click on the “+” sign to re-open the Create Enrichment Map window.

Click on Reset to reset the Enrichment map panel
Drag the fgsea GEM file fgsea_report_for_list.tsv and the filtered gmt file Human_GOBP_AllPathways_filtered_500orLessV2.gmt into the Datasets box on Enrichment map panel.
In the white box, select the “fgsea_resistant_vs_parental (Generic/gProfiler)” file
Locate the GMT field and upload the file “Human_GOBP_AllPathways_filtered_500orLessV2.gmt”.
Set the FDR q-value cutoff to 0.01 and set the Connectivity slide bar to second level.

Explore the results:

SAVE YOUR CYTOSCAPE SESSION (.cys) FILE !
Equivalent RCy3 code — Exercise 1b: Build EM from fgsea results with Baderlab GMT
# Upload the fgsea GEM and Baderlab GMT to Cytoscape
fgsea_gem_cyto <- upload_em_file(fgsea_gem)
rnk_cyto <- upload_em_file(rnk_file)
gmt_bader_cyto <- upload_em_file(gmt_baderlab)
# Build the EnrichmentMap from fgsea results
em1b_command <- paste(
"enrichmentmap build",
"analysisType=GSEA",
paste0("enrichmentsDataset1=", fgsea_gem_cyto),
paste0("gmtFile=", gmt_bader_cyto),
paste0("ranksDataset1=", rnk_cyto),
"qvalue=0.05",
"pvalue=1.0",
"coefficients=COMBINED",
"similaritycutoff=0.5", # second-level connectivity
sep = " "
)
commandsRun(em1b_command, base.url = current_cytoscape_baseurl)
existing_names <- getNetworkList(base.url = current_cytoscape_baseurl)
new_name <- "EM_fgsea_Baderlab"
if (new_name %in% existing_names) {
new_name <- paste0(sample(1000:9999, 2),"_",new_name )
}
renameNetwork(new_name,
network = getNetworkSuid(base.url = current_cytoscape_baseurl),
base.url = current_cytoscape_baseurl)
message("Network renamed to: ", new_name)
em1b_suid <- getNetworkSuid(base.url = current_cytoscape_baseurl)
message("Exercise 1b fgsea EM SUID: ", em1b_suid)
layoutNetwork("force-directed defaultSpringCoefficient=0.00004 defaultSpringLength=5",
network = em1b_suid, base.url = current_cytoscape_baseurl)
# Save the Cytoscape session
saveSession(filename = file.path(path_to_save_cytoscape,"module9_gprofiler_session.cys"),
base.url = current_cytoscape_baseurl)
message("Session saved.")Exercise 1c (optional) - investigate individual pathways in GeneMANIA or String
** This requires that you install additional Cytoscape Apps - GeneMania and String **
Each node in the Enrichment map represents a biological process or pathway. It consists of a collection of genes. Often we want to know how the genes in that group interact. There are many different ways you can investigate the underlying interactions for the given group. Some involve searching online databases and others are directly integrated into cytoscape.
- GeneMANIA - an integrative database of gene connections including co-expression, protein interactions, genetic interactions, pathways and more. Cytoscape App
- String - an integrative database of gene connections including co-expression, protein interactions, genetic interactions, pathways and more. Cytoscape App
- Pathway Commons - a intergrative database of pathways. (There is a beta feature in EM to show your pathway in the painter app, a pathway common web page that overlays your expression data on the given pathway. Still in beta testing and requires expression data to work correctly so won’t work for this example)
GeneMANIA
- Navigate to the enrichment map that you created using the fgsea Baderlab results (Exercise 1b)
- Click on Network Tab and navigate to the third network (it should be the third network if you followed the above examples - name: fgsea_resistant_vs_parental_gem)
- or in the Enrichment map panel in the top drop down select the network named fgsea_resistant_vs_parental_gem
- In the cytoscape search bar enter “MET activates”
If you can’t see the selected nodes, click on “Fit Selected” to focus
on the selected node.
Right click on the node “MET activates” and Select Apps –> Enrichmemt Map - Show in GeneMANIA

A GeneMANIA Query Panel will pop up.
Select Select leading edge to reduce the query set to just the genes found to influence the expression of this pathway.
Click on OK

A GeneMANIA network will show up with the connections between the genes found in your query set and the pathway “MET activates”

We will go more in depth into GeneMANIA in module 5
Equivalent RCy3 code — Exercise 1c: Select a node and query GeneMANIA via the command interface
Caveat - there is no way to selected just the leading edge through RCy3 because it is a functionality that is only present in the interface. The network you get from code will be larger.
# Navigate to the fgsea EM network
setCurrentNetwork(network = em1b_suid, base.url = current_cytoscape_baseurl)
# Select the "MET activates" node
selectNodes(nodes = "MET ACTIVATES PTK2 SIGNALING%REACTOME DATABASE ID RELEASE 97%8874081", by.col = "name",
network = em1b_suid, base.url = current_cytoscape_baseurl)
# Fit the view to the selected node
fitContent(selected.only = TRUE, base.url = current_cytoscape_baseurl)
# Get the genes in this pathway from the node table
node_tbl <- getTableColumns(table = "node", network = em1b_suid,
base.url = current_cytoscape_baseurl)
met_row <- node_tbl[grepl("MET activates", node_tbl$name,
ignore.case = TRUE), ]
# The EnrichmentMap::Genes column holds the genes in the leading edge /
# gene-set intersection — extract them to use as the GeneMANIA query
met_genes <- unlist(met_row[["EnrichmentMap::Genes"]][1])
met_genes <- met_genes[met_genes != ""]
message("Genes in 'met activates': ", paste(met_genes, collapse = ", "))
# Query GeneMANIA via its Cytoscape app command
# (requires GeneMANIA Cytoscape app to be installed)
genemania_command <- paste0(
"genemania search genes=\"",
paste(met_genes, collapse = "|"),
"\" organism=Homo sapiens"
)
commandsRun(genemania_command, base.url = current_cytoscape_baseurl)String
- Navigate to the enrichment map that you created using the fgsea Baderlab results (Exercise 1b)
- Click on Network Tab and navigate to the third network (it should be the third network if you followed the above examples - name: fgsea_resistant_vs_parental_gem)
- or in the Enrichment map panel in the top drop down select the network named fgsea_resistant_vs_parental_gem
- In the cytoscape search bar enter “MET activates”
If you can’t see the selected nodes, click on “Fit Selected” to focus
on the selected node.
Right click on the node “MET activates” and Select Apps –> Enrichmemt Map - Show in String

A String Query Panel will pop up.
Select Select genes with expression to reduce the query set to just the genes in the given that pathway that was in your original dataset (for example we search for a set of 127 genes in g:profiler but the given pathway has 233 genes associated with it of which only 10 genes are found in our original query set )
Click on OK

A String network will show up with the connections between the genes found in your query set and the pathway “MET activates”

Equivalent RCy3 code — Exercise 1c: Query String for genes in a selected pathway
Caveat - there is no way to selected just the leading edge through RCy3 because it is a functionality that is only present in the interface. The network you get from code will be larger.
# Using the met_genes vector extracted above, query String via its app command
# (requires STRINGapp Cytoscape app to be installed)
string_command <- paste0(
"string protein query",
" query=\"", paste(met_genes, collapse = ","), "\"",
" species=\"Homo sapiens\"",
" limit=0", # only return queried proteins, no additional interactors
" cutoff=0.4"
)
commandsRun(string_command, base.url = current_cytoscape_baseurl)
Explore the features and data of each Cytoscape app.
What sort of
information does each tell you?
What is the main difference between
the two resulting networks?