File

projects/web-mev/src/app/d3/components/gsea/gsea/gsea.component.ts

Description

FGSEA Component

Used for GSEA analysis

Implements

OnInit

Metadata

changeDetection ChangeDetectionStrategy.Default
selector mev-gsea
styleUrls ./gsea.component.scss
templateUrl ./gsea.component.html

Index

Properties
Methods
Inputs

Constructor

constructor(analysesService: AnalysesService, dialog: MatDialog, metadataService: MetadataService)
Parameters :
Name Type Optional
analysesService AnalysesService No
dialog MatDialog No
metadataService MetadataService No

Inputs

outputs

Methods

initializeResource
initializeResource()
Returns : void
loadPathwaysPage
loadPathwaysPage()

Function to load pathway list by page, filter and sorting settings specified by a user

Returns : void
ngAfterViewInit
ngAfterViewInit()
Returns : void
ngOnChanges
ngOnChanges()
Returns : void
ngOnInit
ngOnInit()
Returns : void
onCreateFeatureSet
onCreateFeatureSet(row)

Function that is triggered when the user clicks the "Create a custom sample" button

Parameters :
Name Optional
row No
Returns : void
onSubmit
onSubmit()

Function is triggered when submitting the form with table filters

Returns : void

Properties

allowedFilters
Type : object
Default value : { padj: { defaultValue: '', hasOperator: true, operatorDefaultValue: 'lte' } }
dataSource
Type : PathwayDataSource
defaultPageIndex
Type : number
Default value : 0
defaultPageSize
Type : number
Default value : 10
defaultSorting
Type : object
Default value : { field: 'pathway', direction: 'asc' }
Public dialog
Type : MatDialog
displayedColumns
Type : []
Default value : ['pathway', 'ranks', 'pval', 'padj', 'NES', 'actions']
filterForm
Default value : new FormGroup({})
gseaResourceId
operators
Type : []
Default value : [ { id: 'eq', name: ' = ' }, { id: 'gte', name: ' >=' }, { id: 'gt', name: ' > ' }, { id: 'lte', name: ' <=' }, { id: 'lt', name: ' < ' }, { id: 'absgt', name: 'ABS(x) > ' }, { id: 'abslt', name: 'ABS(x) < ' } ]
paginator
Type : MatPaginator
Decorators :
@ViewChild(MatPaginator)
sort
Type : MatSort
Decorators :
@ViewChild(MatSort)
import {
  Component,
  OnInit,
  ChangeDetectionStrategy,
  Input,
  ViewChild
} from '@angular/core';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { MatDialog } from '@angular/material/dialog';
import { DataSource } from '@angular/cdk/table';
import { BehaviorSubject, Observable, merge } from 'rxjs';
import { AnalysesService } from '@app/features/analysis/services/analysis.service';
import { finalize, tap } from 'rxjs/operators';
import { FormGroup, FormControl } from '@angular/forms';
import { MetadataService } from '@app/core/metadata/metadata.service';
import { AddSampleSetComponent } from '../../dialogs/add-sample-set/add-sample-set.component';
import { CustomSetType } from '@app/_models/metadata';

/**
 * FGSEA Component
 *
 * Used for GSEA analysis
 */
@Component({
  selector: 'mev-gsea',
  templateUrl: './gsea.component.html',
  styleUrls: ['./gsea.component.scss'],
  changeDetection: ChangeDetectionStrategy.Default
})
export class GseaComponent implements OnInit {
  @Input() outputs;
  dataSource: PathwayDataSource; // datasource for MatTable
  gseaResourceId;

  @ViewChild(MatPaginator) paginator: MatPaginator;
  @ViewChild(MatSort) sort: MatSort;

  /* Table settings */
  displayedColumns = ['pathway', 'ranks', 'pval', 'padj', 'NES', 'actions'];

  operators = [
    { id: 'eq', name: ' = ' },
    { id: 'gte', name: ' >=' },
    { id: 'gt', name: ' > ' },
    { id: 'lte', name: ' <=' },
    { id: 'lt', name: ' < ' },
    { id: 'absgt', name: 'ABS(x) > ' },
    { id: 'abslt', name: 'ABS(x) < ' }
  ];

  defaultPageIndex = 0;
  defaultPageSize = 10;
  defaultSorting = { field: 'pathway', direction: 'asc' };

  /* Table filters */
  allowedFilters = {
    padj: {
      defaultValue: '',
      hasOperator: true,
      operatorDefaultValue: 'lte'
    }
  };

  filterForm = new FormGroup({});

  constructor(
    private analysesService: AnalysesService,
    public dialog: MatDialog,
    private metadataService: MetadataService
  ) {
    this.dataSource = new PathwayDataSource(this.analysesService);

    // adding form controls depending on the tables settings (the allowedFilters property)
    for (const key in this.allowedFilters) {
      if (this.allowedFilters.hasOwnProperty(key)) {
        // TSLint rule
        const defaultValue = this.allowedFilters[key].defaultValue;
        this.filterForm.addControl(key, new FormControl(defaultValue));
        if (this.allowedFilters[key].hasOperator) {
          const operatorDefaultValue = this.allowedFilters[key]
            .operatorDefaultValue;
          this.filterForm.addControl(
            key + '_operator',
            new FormControl(operatorDefaultValue)
          );
        }
      }
    }
  }

  ngOnInit() {
    this.initializeResource();
  }

  ngAfterViewInit() {
    this.sort.sortChange.subscribe(
      () => (this.paginator.pageIndex = this.defaultPageIndex)
    );
    this.dataSource.connect().subscribe(() => {});

    merge(this.sort.sortChange, this.paginator.page)
      .pipe(
        tap(() => {
          this.loadPathwaysPage();
        })
      )
      .subscribe();
  }

  ngOnChanges(): void {
    this.initializeResource();
  }

  initializeResource(): void {
    this.gseaResourceId = this.outputs.pathway_results;
    const sorting = {
      sortField: this.defaultSorting.field,
      sortDirection: this.defaultSorting.direction
    };
    this.dataSource.loadPathways(
      this.gseaResourceId,
      {},
      sorting,
      this.defaultPageIndex,
      this.defaultPageSize
    );
  }

  /**
   * Function is triggered when submitting the form with table filters
   */
  onSubmit() {
    this.paginator.pageIndex = this.defaultPageIndex;
    this.loadPathwaysPage();
  }

  /**
   * Function that is triggered when the user clicks the "Create a custom sample" button
   */
  onCreateFeatureSet(row) {
    const features = row.leadingEdge.map(elem => ({
      id: elem
    }));

    const dialogRef = this.dialog.open(AddSampleSetComponent, {
      data: { type: CustomSetType.FeatureSet, name: row.pathway }
    });

    dialogRef.afterClosed().subscribe(customSetData => {
      if (customSetData) {
        const customSet = {
          name: customSetData.name,
          type: CustomSetType.FeatureSet,
          elements: features,
          multiple: true
        };

        this.metadataService.addCustomSet(customSet);
      }
    });
  }

  /**
   * Function to load pathway list by page, filter and sorting settings specified by a user
   */
  loadPathwaysPage() {
    const formValues = this.filterForm.value; // i.e. {name: "asdfgh", pvalue: 3, pvalue_operator: "lte", log2FoldChange: 2, log2FoldChange_operator: "lte"}
    const paramFilter = {}; // has values {'log2FoldChange': '[absgt]:2'};
    for (const key in this.allowedFilters) {
      if (
        formValues.hasOwnProperty(key) &&
        formValues[key] !== '' &&
        formValues[key] !== null
      ) {
        if (formValues.hasOwnProperty(key + '_operator')) {
          paramFilter[key] =
            '[' + formValues[key + '_operator'] + ']:' + formValues[key];
        } else {
          paramFilter[key] = '[eq]:' + formValues[key];
        }
      }
    }

    const sorting = {
      sortField: this.sort.active,
      sortDirection: this.sort.direction
    };

    this.dataSource.loadPathways(
      this.gseaResourceId,
      paramFilter,
      sorting,
      this.paginator.pageIndex,
      this.paginator.pageSize
    );
  }
}

export interface Pathway {
  pathway: string;
  pval: number;
  padj: number;
  log2err: number;
  ES: number;
  NES: number;
  size: number;
  ranks: number[];
}

export class PathwayDataSource implements DataSource<Pathway> {
  public pathwaysSubject = new BehaviorSubject<Pathway[]>([]);
  public pathwaysCount = 0;
  private loadingSubject = new BehaviorSubject<boolean>(false);
  public loading$ = this.loadingSubject.asObservable();

  constructor(private analysesService: AnalysesService) {}

  loadPathways(
    resourceId: string,
    filterValues: object,
    sorting: object,
    pageIndex: number,
    pageSize: number
  ) {
    this.loadingSubject.next(true);

    this.analysesService
      .getResourceContent(
        resourceId,
        pageIndex + 1,
        pageSize,
        filterValues,
        sorting
      )
      .pipe(finalize(() => this.loadingSubject.next(false)))
      .subscribe(response => {
        this.pathwaysCount = response.count;
        return this.pathwaysSubject.next(response.results);
      });
  }

  connect(): Observable<Pathway[]> {
    return this.pathwaysSubject.asObservable();
  }

  disconnect(): void {
    this.pathwaysSubject.complete();
    this.loadingSubject.complete();
  }
}
<mat-card class="analysis-card">
  <mat-card-header>
    <div mat-card-avatar class="analysis-card__img"></div>
    <mat-card-title>FGSEA: {{ outputs?.job_name }}</mat-card-title>
  </mat-card-header>
  <mat-card-content class="analysis-card__main">
    <p class="analysis-card__instruction">
      Use the table pagination component at the bottom of the table to navigate
      between a set of table and chart results. <br>
      You can sort data in alphabetical and numerical order,
      or use filters to hide data you don't want to see.
    </p>
    <mat-divider [inset]="true"></mat-divider>
    <div class="analysis-card__content">
      <section class="filter-section">
        <form [formGroup]="filterForm" (ngSubmit)="onSubmit()">
          <div class="filter">
            <span class="label">
              P-value adjusted:
            </span>
            <mat-form-field class="form-control form-control__small" color="accent">
              <mat-select formControlName="padj_operator">
                <mat-option *ngFor="let operator of operators" [value]="operator.id">
                  {{ operator.name }}
                </mat-option>
              </mat-select>
            </mat-form-field>
            <mat-form-field class="form-control">
              <input matInput formControlName="padj" type=number step=any min=0>
            </mat-form-field>
          </div>

          <button type="submit" [disabled]="!filterForm.valid" mat-raised-button color="accent">Apply filters</button>
        </form>

      </section>

      <div class="mat-elevation-z8">
        <mat-table class="deseq-table" [dataSource]="dataSource" matSort [matSortActive]="defaultSorting.field"
          [matSortDirection]="defaultSorting.direction" matSortDisableClear>

          <ng-container matColumnDef="pathway">
            <mat-header-cell *matHeaderCellDef>Pathway</mat-header-cell>
            <mat-cell *matCellDef="let row">{{row.pathway}}</mat-cell>
          </ng-container>

          <ng-container matColumnDef="NES">
            <mat-header-cell *matHeaderCellDef>NES</mat-header-cell>
            <mat-cell class="description-cell" *matCellDef="let row">{{row.NES}}</mat-cell>
          </ng-container>

          <ng-container matColumnDef="padj">
            <mat-header-cell *matHeaderCellDef mat-sort-header>P-value adjusted</mat-header-cell>
            <mat-cell class="description-cell" *matCellDef="let row">{{row.padj}}</mat-cell>
          </ng-container>

          <ng-container matColumnDef="pval">
            <mat-header-cell *matHeaderCellDef mat-sort-header>P-value</mat-header-cell>
            <mat-cell class="description-cell" *matCellDef="let row">{{row.pval}}</mat-cell>
          </ng-container>

          <ng-container matColumnDef="ranks">
            <mat-header-cell *matHeaderCellDef mat-sort-header>Gene ranks</mat-header-cell>
            <mat-cell class="description-cell" *matCellDef="let row">
              <mev-rug-plot [plotData]="row.ranks"></mev-rug-plot>
            </mat-cell>
          </ng-container>

          <ng-container matColumnDef="actions">
            <mat-header-cell *matHeaderCellDef></mat-header-cell>

            <mat-cell *matCellDef="let row; let i=index;">
              <button mat-raised-button color="accent" title="Create feature set" 
                (click)="onCreateFeatureSet(row)">
                Create feature set
              </button>
              <!-- <button mat-raised-button color="accent" title="Show top genes" 
                (click)="onShowTopGenes(row)">
                Show top genes
              </button> -->
            </mat-cell>
          </ng-container>

          <!-- <ng-container matColumnDef="topGeneView">
            <mat-header-cell *matHeaderCellDef class="file-table-header"></mat-header-cell>
            <mat-cell *matCellDef="let row; let i=index;">
              
            </mat-cell>
          </ng-container> -->



          <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
          <mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>

        </mat-table>


        <mat-paginator [length]="dataSource.pathwaysCount" [pageSize]="10" [pageSizeOptions]="[10, 25, 50]">
        </mat-paginator>
      </div>

      <!-- <div class="button-panel">
          <button mat-raised-button color="accent" (click)="onCreateCustomFeatureSet()">
            <mat-icon>add</mat-icon>
            Save as a feature set
          </button>
          <mev-download-button [containerId]="containerId" [imageName]="imageName"></mev-download-button>  
        </div>       -->


    </div>

  </mat-card-content>

</mat-card>

./gsea.component.scss

.analysis-card__img {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' aria-hidden='true' focusable='false' width='1em' height='1em' style='-ms-transform: rotate(360deg); -webkit-transform: rotate(360deg); transform: rotate(360deg);' preserveAspectRatio='xMidYMid meet' viewBox='0 0 24 24'%3E%3Cpath d='M4 2h2v2c0 1.44.68 2.61 1.88 3.78c.86.83 2.01 1.63 3.21 2.42l-1.83 1.19C8.27 10.72 7.31 10 6.5 9.21C5.07 7.82 4 6.1 4 4V2m14 0h2v2c0 2.1-1.07 3.82-2.5 5.21c-1.41 1.38-3.21 2.52-4.96 3.63c-1.75 1.12-3.45 2.21-4.66 3.38C6.68 17.39 6 18.56 6 20v2H4v-2c0-2.1 1.07-3.82 2.5-5.21c1.41-1.38 3.21-2.52 4.96-3.63c1.75-1.12 3.45-2.21 4.66-3.38C17.32 6.61 18 5.44 18 4V2m-3.26 10.61c.99.67 1.95 1.39 2.76 2.18C18.93 16.18 20 17.9 20 20v2h-2v-2c0-1.44-.68-2.61-1.88-3.78c-.86-.83-2.01-1.63-3.21-2.42l1.83-1.19M7 3h10v1l-.06.5H7.06L7 4V3m.68 3h8.64c-.24.34-.52.69-.9 1.06l-.51.44H9.07l-.49-.44c-.38-.37-.66-.72-.9-1.06m1.41 10.5h5.84l.49.44c.38.37.66.72.9 1.06H7.68c.24-.34.52-.69.9-1.06l.51-.44m-2.03 3h9.88l.06.5v1H7v-1l.06-.5z' fill='%2337474f'/%3E%3C/svg%3E");
  background-size: 30px;
  background-position: top center;
  background-repeat: no-repeat;
}

.analysis-card__content {
  padding-top: 1rem;
}

.filter-section {
  font-size: 14px;
}

.filter {
  margin-right: 25px;
  display: inline;
}

.form-control {
  margin-right: 10px;
}

.form-control__small {
  width: 80px;
}

.button-panel {
  margin-top: 30px;
}

.mat-column-pathway,
.mat-column-ranks {
  word-wrap: break-word !important;
  white-space: unset !important;
  flex: 0 0 20% !important;
  width: 20% !important;
  overflow-wrap: break-word;
  word-wrap: break-word;
  word-break: break-word;
  -ms-hyphens: auto;
  -moz-hyphens: auto;
  -webkit-hyphens: auto;
  hyphens: auto;
}

.mat-column-actions {
  flex-direction: row;
  flex-wrap: wrap;

  button {
    margin: 5px;
  }
}

mev-rug-plot {
  width: 100% !important;
}
Legend
Html element
Component
Html element with directive

result-matching ""

    No results matching ""