7

Can anybody say how to use extendTraces functionality of Plotly.js in Angular 2+ wrapper (https://github.com/plotly/angular-plotly.js) for plotly.js? I cannot figure this out from the docs given in the url.

Related to issue: Plotly update data

**** solution **** Below I have changed my original post code to show the working solution. Methods addPoint and addPoint2 (add a new individual data point to an exsisting series) Method addRandomLine() adds the new trace (i.e. a whole new data series):

<button (click)="addRandomLine()" class="button">Add random line</button>
<button (click)="addPoint()" class="button">Add point to 1. series</button>
<button (click)="addPoint2()" class="button">Add point with extendTrace to 1. series</button>

<plotly-plot 
    #chart
    id="plotlyChart"
    [data]="data" 
    [layout]="layout">
</plotly-plot>


import { Component, ViewChild } from '@angular/core';
import { PlotlyService } from '../../shared/plotly.service';

export class LinearChartsComponent {

@ViewChild('chart') el: any;

    public data: any[] = [
        { x: [1, 2, 3, 4], y: [10, 15, 13, 17], type: 'bar',  mode: 'markers', name: 'Bar' },
        { x: [2, 3, 4, 1], y: [16, 5, 11, 9], type: 'scattergl', mode: 'lines', name: 'Lines' },
        { x: [1, 2, 3, 4], y: [12, 9, 15, 12], type: 'markers', mode: 'lines+markers', name: 'Scatter + Lines' },
    ];

constructor(public plotly: PlotlyService) {
}


    public layout: any = {
        title: 'Adding Names to Line and Scatter Plot',
    };

    public addRandomLine() {
        const line: any = { x: [], y: [], mode: 'lines', name: 'Line ' + this.data.length };

        line.x = [1, 2, 3, 4].map(i => Math.round(Math.random() * 10));
        line.y = [1, 2, 3, 4].map(i => Math.round(Math.random() * 20));
        line.mode = ['markers', 'lines', 'lines+markers'][Math.floor(Math.random() * 3)] as any;

        this.data.push(line);
    }


// adds point with relayout-method
addPoint() {

    const line: any = this.data[1];
    line.x.push(line.x.length + 1);
    line.y.push(Math.round(Math.random() * 20));
    this.data[1] = line;

    const update = {
        title: 'New Title',
        data: this.data
    }
    this.plotly.getPlotly().relayout(this.el.plotEl.nativeElement, update);

}

// adds point with extendTraces-method
addPoint2() {
    this.plotly.getPlotly().extendTraces(
        this.el.plotEl.nativeElement,
        { y: [[Math.random()*10]] }, [1]
    );
    this.plotly.getPlotly().extendTraces(
        this.el.plotEl.nativeElement,
        { x: [[this.data[1].x.length + 1]] }, [1]
    );
}

}
M.Y.
  • 549
  • 1
  • 3
  • 23
  • can you give a stack blitz with the issue replication? – Naren Murali Feb 07 '19 at 13:27
  • I am trying but installing dependecies given https://github.com/plotly/angular-plotly.js/blob/master/README.md (i.e. angular-plotly.js plotly.js) leads all the time to the hanging of stackblitz.com in Starting dev server process. Not know how to solve. Any ideas? – M.Y. Feb 07 '19 at 14:00
  • Here is the link to codesandbox.io https://codesandbox.io/s/4jqp11wz9 where I was able to make it work. – M.Y. Feb 07 '19 at 14:20
  • So i've been checking the code, the `angular plotly` directive cant detect the change, so I cant help you, would suggest you create a github issue for this and get it checked what should be the proper solution, Thanks and sorry! – Naren Murali Feb 07 '19 at 17:21
  • 1
    Thank for your check - I came to the same conclusion. I consider creating github issue about this. – M.Y. Feb 07 '19 at 18:24
  • You're welcome! please do :) its better to have a `subject` which can be used to update the plot, since this change detection is not perfect! – Naren Murali Feb 07 '19 at 18:24
  • I found finally that there is already support for updating angular plotly, see: https://github.com/plotly/angular-plotly.js/issues/14, where I posted also the required changes to the code. I could not update the above given CodeSandbox example, because system seems to be incapable of updating the needed peer dependency to the required later version. – M.Y. Feb 08 '19 at 12:50
  • I also updating my original code above to demonstrate now the working example – M.Y. Feb 08 '19 at 13:04
  • Thanks, once you get a solution post it here! – Naren Murali Feb 08 '19 at 13:48
  • I already did, by changing the original code right above – M.Y. Feb 08 '19 at 14:03

1 Answers1

0

The OP has provided a solution by editing the original question. Rather than undo those edits and post the complete solution here, I will just add the OP's plotly-service upon which this solution depends.

import { Injectable } from '@angular/core';
import { Plotly } from './plotly.interface';


@Injectable({
    providedIn: 'root'
})
export class PlotlyService {
    protected static instances: Plotly.PlotlyHTMLElement[] = [];
    protected static _plotly?: any = undefined;

    public static setPlotly(plotly: any) {
        PlotlyService._plotly = plotly;
    }

    public static insert(instance: Plotly.PlotlyHTMLElement) {
        const index = PlotlyService.instances.indexOf(instance);
        if (index === -1) {
            PlotlyService.instances.push(instance);
        }
        return instance;
    }

    public static remove(div: Plotly.PlotlyHTMLElement) {
        const index = PlotlyService.instances.indexOf(div);
        if (index >= 0) {
            PlotlyService.instances.splice(index, 1);
        }
    }

    public getInstanceByDivId(id: string): Plotly.PlotlyHTMLElement | undefined {
        for (const instance of PlotlyService.instances) {
            if (instance && instance.id === id) {
                return instance;
            }
        }
        return undefined;
    }

    public getPlotly() {
        if (typeof PlotlyService._plotly === 'undefined') {
            throw new Error(`Peer dependency plotly.js isn't installed`);
        }

        return PlotlyService._plotly;
    }

    protected waitFor(fn: () => boolean): Promise<void> {
        return new Promise((resolve) => {
            const localFn = () => {
                fn() ? resolve() : setTimeout(localFn, 10);
            };

            localFn();
        });
    }

    public async newPlot(div: HTMLDivElement, data: Plotly.Data[], layout?: Partial<Plotly.Layout>, config?: Partial<Plotly.Config>) {
        await this.waitFor(() => this.getPlotly() !== 'waiting');
        return this.getPlotly().newPlot(div, data, layout, config).then(() => PlotlyService.insert(div as any)) as Promise<any>;
    }

    public plot(div: Plotly.PlotlyHTMLElement, data: Plotly.Data[], layout?: Partial<Plotly.Layout>, config?: Partial<Plotly.Config>) {
        return this.getPlotly().plot(div, data, layout, config) as Promise<any>;
    }

    public update(div: Plotly.PlotlyHTMLElement, data: Plotly.Data[], layout?: Partial<Plotly.Layout>, config?: Partial<Plotly.Config>) {
        return this.getPlotly().react(div, data, layout, config) as Promise<any>;
    }

    public resize(div: Plotly.PlotlyHTMLElement): void {
        return this.getPlotly().Plots.resize(div);
    }
}

intotecho
  • 4,925
  • 3
  • 39
  • 54