Commit 6846c6c8 authored by Laura Morel's avatar Laura Morel
Browse files

Add heatmap cluster annotation on rows

Add annotation field to Angular form and add seaborn options form group.

Rework the form by grouping figure size with the other seaborn options. Figure size
made optional (default: 10) for both ClusteredMap (Django) and the Angular form group.

Changed metadata dataframe to only have string in order to avoid compatibility issues
with the GET request and the seaborn annotation.
parent 20915166
<h1>VizFaDa</h1>
<ngx-spinner
bdColor = "rgba(51, 51, 51, 0.8)"
size = "medium"
color = "#fff"
type = "ball-clip-rotate"></ngx-spinner>
<app-controller></app-controller>
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { NgMultiSelectDropDownModule } from 'ng-multiselect-dropdown';
import { ColorPickerModule } from 'ngx-color-picker';
import { NgxSpinnerModeule } from "ngx-spinner";
import { AppComponent } from './app.component';
import { ControllerComponent } from './controller/controller.component';
......@@ -29,6 +30,7 @@ import { HighlightComponent } from './highlight/highlight.component';
ColorPickerModule,
],
providers: [],
bootstrap: [AppComponent]
bootstrap: [AppComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule { }
......@@ -7,12 +7,6 @@
<option *ngFor="let sp of SPECIES" [ngValue]="sp">{{sp}}</option>
</select>
<label for="size">Size : </label>
<select id="size" formControlname="size" (change)="changeSize($event)">
<option value="">-- choose size --</option>
<option *ngFor="let sz of SIZES" [ngValue]="sz">{{sz}}</option>
</select>
<div formArrayName="filters">
<p>Filters :</p>
<div *ngFor="let control of formFilters.controls; let i = index">
......@@ -33,9 +27,23 @@
<button type="button" (click)="addHighlight()">Add Highlight</button>
</div>
<label for="annotated">Annotate : </label>
<select id="annotated" formControlname="annotated" (change)="changeAnnotation($event)">
<option value="">-- choose field --</option>
<option *ngFor="let f of fields" [ngValue]="f">{{f}}</option>
</select>
<label for="size">Size : </label>
<select id="size" formControlname="options" (change)="changeSize($event)">
<option value="">-- choose size --</option>
<option *ngFor="let sz of SIZES" [ngValue]="sz">{{sz}}</option>
</select>
<button type="submit">Submit</button>
</form>
</ng-container>
<app-heatmap></app-heatmap>
import { Component, ViewChild, OnInit, Input} from '@angular/core';
import { Validators, FormGroup, FormArray, FormBuilder } from '@angular/forms';
import { Validators, FormGroup, FormArray, FormBuilder, FormControl } from '@angular/forms';
import { NgxSpinnerService } from "ngx-spinner";
import { HeatmapComponent } from '../heatmap/heatmap.component';
import { FilterComponent } from '../filter/filter.component';
......@@ -17,23 +19,25 @@ export class ControllerComponent implements OnInit {
public SIZES = ["10", "15", "20"];
public METADATA: Object;
public fields: string[];
public img;
public formGroup: FormGroup;
constructor(private builder: FormBuilder, private dataService: DataService) { }
constructor(private builder: FormBuilder,
private dataService: DataService,
private spinner: NgxSpinnerService) { }
ngOnInit(): void {
let newForm = this.builder.group({
species: ["", [Validators.required]],
size: ["", [Validators.required]],
filters: this.builder.array([]),
highlights: this.builder.array([]),
options: this.builder.array([])
annotated: "",
options: this.builder.group({})
});
console.log(newForm)
this.formGroup = newForm;
}
......@@ -64,7 +68,7 @@ export class ControllerComponent implements OnInit {
getMetadata(): void {
console.log(this.formGroup.value);
this.dataService.get_fields(this.formGroup.value)
.subscribe(meta => {this.METADATA = meta});
.subscribe(meta => {this.METADATA = meta; this.fields = Object.keys(meta)});
}
get formFilters() {return <FormArray>this.formGroup.get('filters')}
......@@ -86,8 +90,19 @@ export class ControllerComponent implements OnInit {
changeSize(e) {
console.log("Changing size")
this.formGroup.controls['size'].setValue(e.target.value);
this.getMetadata()
const s = e.target.value;
let optionsControl = <FormGroup>this.formGroup.controls['options'];
try {
optionsControl.controls['figsize'].setValue(`(${s}, ${s})`);
} catch (error) {
optionsControl.addControl('figsize', new FormControl(`(${s}, ${s})`));
}
this.formGroup.controls['options'] = optionsControl;
}
changeAnnotation(e) {
console.log("Changing annotated field");
this.formGroup.controls['annotated'].setValue(e.target.value);
}
onSubmit(): void {
......
<ng-container *ngIf="src; else elseTemplate">
<img id="heatmap" [src]="src" />
</ng-container>
<ng-template #elseTemplate>
<p> No heatmap </p>
</ng-template>
<ng-container *ngIf="src==='no_heatmap'; else loadingTemplate">
<ng-template #elseTemplate>
<p> No heatmap </p>
</ng-template>
<ng-template #loadingTemplate>
<p> Loading... </p>
</ng-template>
</ng-container>
......@@ -10,7 +10,7 @@ import { DataService } from '../data.service';
})
export class HeatmapComponent implements OnInit {
public src: String = "";
public src: String = "no_heatmap";
constructor(private dataService: DataService, private sanitizer: DomSanitizer) { }
......
......@@ -9,6 +9,7 @@ import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns
from distinctipy import distinctipy
from data.models import Correlation
......@@ -32,18 +33,15 @@ DEFAULT_SNS_OPTIONS = {"cmap": "rocket_r"}
class ClusteredHeatmap:
def __init__(self, species: str, size: str) -> None:
def __init__(self, species: str, seaborn_options: dict) -> None:
self.species = species
if size != '':
self.size = size
else:
self.size = '10'
self._load_data()
self.correlation = self.ALL_CORRELATION
self.metadata = self.ALL_METADATA
self.filters = {}
self.highlights = {}
self.seaborn_options = DEFAULT_SNS_OPTIONS
self.seaborn_options.update(seaborn_options)
self.fig = None
self.highlighted = None
self.get_fields()
......@@ -52,7 +50,10 @@ class ClusteredHeatmap:
print("Filtering metadata with filters %s" % (str(filters)))
m = self.metadata
for f, v in filters.items():
m = m[m[f].isin(v)]
try:
m = m[m[f].isin(v)]
except KeyError:
return pd.DataFrame()
print("Keeping %d samples" % (m.shape[0]))
return m
......@@ -101,10 +102,33 @@ class ClusteredHeatmap:
def _draw_heatmap(self) -> None:
print("Drawing heatmap...")
self.fig = sns.clustermap(self.correlation, figsize=(
int(self.size), int(self.size)), **self.seaborn_options)
self.fig = sns.clustermap(self.correlation,
**self.seaborn_options)
if self.annotated:
for label, color in self.annotated.items():
self.fig.ax_col_dendrogram.bar(0, 0, color=color, label=label, linewidth=0)
self.fig.ax_col_dendrogram.legend(loc="center", ncol=4)
self.highlighted = self.fig
def _annotate(self, field: str) -> None:
print("Annotating heatmap..")
try:
values = self.fields[field]
except KeyError:
return None
match = dict(zip(values, distinctipy.get_colors(len(values))))
print(self.fields[field])
print(match)
print(self.metadata[field])
row_colors = self.metadata[field].map(match)
self.seaborn_options.update({"row_colors": row_colors})
self.annotated = match
def annotate_field(self, field: str) -> None:
self.get_fields()
self._annotate(field)
def add_filters(self, filters: Filters) -> None:
if not filters == {}:
print("Adding filters...")
......
......@@ -23,6 +23,7 @@ def fill_db(verbose=False):
correlation = pd.read_csv(correlation, sep=",", header=0, index_col=0)
c = Correlation(species=sp, correlation=spDir +
"/corPickle", metadata=spDir + "/metaPickle")
metadata.applymap(str)
c.pickle(correlation, "correlation")
c.pickle(metadata, "metadata")
c.save()
......
......@@ -19,7 +19,7 @@ def index(request):
def query_handler(request):
q = request.GET.dict()['q']
params = eval(q)
params['options'] = {} # TODO: Change when seaborn options implemented in front-end
# TODO: Change when seaborn options implemented in front-end
filters = {}
highlights = {}
for dict in params['filters']:
......@@ -29,10 +29,12 @@ def query_handler(request):
if dict['field'] != '':
color = "#%s" % dict['color']
highlights.setdefault(color, {}).update({dict["field"]: dict["values"]})
heatmap = ClusteredHeatmap(params["species"], params["size"])
heatmap.seaborn_options.update(params['options'])
options = {opt: eval(val) for opt, val in params["options"].items()}
heatmap = ClusteredHeatmap(params["species"], options)
heatmap.add_filters(filters)
heatmap.add_highlights(highlights)
if params["annotated"] != "":
heatmap.annotate_field(params["annotated"])
return heatmap
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment