Skip to content

Instantly share code, notes, and snippets.

@oeway
Created May 14, 2021 19:39
Show Gist options
  • Save oeway/3031960cca4747c7a22e5f53aa449929 to your computer and use it in GitHub Desktop.
Save oeway/3031960cca4747c7a22e5f53aa449929 to your computer and use it in GitHub Desktop.
<docs>
[TODO: write documentation for this plugin.]
</docs>
<config lang="json">
{
"name": "HPA-UMAP-Nucleolus",
"type": "web-worker",
"tags": [],
"ui": "",
"version": "0.1.2",
"cover": "",
"description": "Displaying the HPA UMAP with the ImJoy Chart Editor",
"icon": "extension",
"inputs": null,
"outputs": null,
"api_version": "0.1.8",
"env": "",
"permissions": [],
"requirements": ["https://cdn.jsdelivr.net/npm/papaparse@5.2.0/papaparse.min.js"],
"dependencies": []
}
</config>
<script lang="javascript">
function loadCSV(url) {
return new Promise((resolve, reject) => {
Papa.parse(url, {
download: typeof url === "string" && url.startsWith('http'),
header: true,
dynamicTyping: true,
skipEmptyLines: true,
error: (err, file, inputElem, reason) => {
alert("Falied to load the table: " + reason.toString());
reject(reason);
},
complete: (results) => {
resolve(transpose(results.data));
},
});
});
}
function transpose(data) {
let result = {};
for (let row of data) {
for (let [key, value] of Object.entries(row)) {
result[key] = result[key] || [];
result[key].push(value);
}
}
return result;
}
async function convertUniprot2Ensembl(query){
const url = 'https://www.uniprot.org/uploadlists/'
const params = {
'from': 'ID',
'to': 'ENSEMBL_ID',
'format': 'tab',
'query': query.join('\t')
}
const formData = [];
for(let k in params){
formData.push(`${k}=${encodeURIComponent(params[k])}`)
}
const response = await fetch(url, {method: "POST", headers: {'Content-Type': 'application/x-www-form-urlencoded'}, body: formData.join('&') })
const data = await response.text()
const ret = []
for(let line of data.split('\n').slice(1)){
if(line.length>0)
ret.push(line.split('\t'))
}
const mapping = Object.fromEntries(ret);
return query.map(u=> mapping[u])
}
async function insertQueryData(data, queryFile){
await api.showMessage('Parsing file '+ queryFile.name)
const queryFull = await loadCSV(queryFile);
if(queryFull.Uniprot) queryFull.Ensembl = await convertUniprot2Ensembl(queryFull.Uniprot)
if(!queryFull.Ensembl){
const matchingColumn = await api.prompt(`Please select a maching column name (options: ${JSON.stringify(Object.keys(queryFull))})`, "")
if(matchingColumn){
if(!queryFull[matchingColumn]){
await api.alert(`Column ${matchingColumn} not found`)
return
}
queryFull.Ensembl = queryFull[matchingColumn]
}
else{
return
}
}
await api.showMessage('Merging columns...')
for(let col in queryFull){
data[col] = []
}
for(let i=0;i<data['gene_ensembl_id'].length;i++){
const id = data['gene_ensembl_id'][i]
if(id){
const index = queryFull.Ensembl.indexOf(id)
if(index>=0){
for(let col in queryFull){
data[col][i] = queryFull[col][index]
}
}
}
}
await api.showMessage('New columns are ready!')
}
class ImJoyPlugin {
async setup() {
await api.showMessage("Loading data...")
this.data = await loadCSV("https://dl.dropbox.com/s/k9ekd4ff3fyjbfk/umap_results_fit_all_transform_all_sorted_20190422.csv");
await api.log('initialized')
}
async loadDataHandler(file){
await insertQueryData(this.data, file)
debugger
await this.editor.loadDataSource(this.data)
}
async run(ctx) {
const editor = await api.createWindow({src: 'https://chart.imjoy.io',
name: 'HPA UMAP Studio',
fullscreen: true,
config:{_rintf: true, loadDataHandler: this.loadDataHandler.bind(this)}}) // 'https://imjoy-team.github.io/imjoy-chart-editor/', name: 'HPA UMAP Studio', fullscreen: true})
this.editor = editor;
await editor.loadDataSource(this.data)
await api.showMessage("Data loaded.")
await editor.addWidget({
type:'html',
name: 'Details',
body: ''
})
await editor.addWidget({
type:'html',
name: 'Overview',
body: ''
})
await editor.addListener({_rintf: true, event:'plotly_hover', callback: async (points)=>{
const metadata = points[0].customdata;
const id = metadata.id
const image_base_url = id.includes('_')?'https://images.proteinatlas.org/' + id.split('_')[0] + '/' + id.split('_')[1] +'_' + id.split('_')[2] + '_'+ id.split('_')[3] : null
const thumbnail_url = image_base_url && image_base_url + '_blue_red_green_yellow_thumb.jpg'
await editor.updateWidget({
type:'html',
name: 'Overview',
body: `<p>Gene: ${metadata.gene}</p> <p>Location: ${metadata.location}</p> <br> <img style="width:100px" src="${thumbnail_url}"></img>`
})
}})
await editor.addListener({_rintf: true, event:'plotly_click', callback: async (points)=>{
const metadata = points[0].customdata;
const id = metadata.id
const image_base_url = id.includes('_')?'https://images.proteinatlas.org/' + id.split('_')[0] + '/' + id.split('_')[1] +'_' + id.split('_')[2] + '_'+ id.split('_')[3] : ''
const full_url = image_base_url + '_blue_red_green.jpg'
await editor.updateWidget({
type:'html',
name: 'Details',
body: `<p>ID: ${metadata.id}</p> <p>Gene: ${metadata.gene}</p> <p>Location: ${metadata.location}</p> <br> <a target="_blank" href="${full_url}"><img style="width:100%" src="${full_url}"></img></a>
<br><a target="_blank" href="https://www.proteinatlas.org/${metadata.gene_ensembl_id}-${metadata.gene}/cell/">Open HPA Page</a>`
})
}})
}
}
api.export(new ImJoyPlugin())
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment