question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Line chart - color of given points in series

See original GitHub issue

I’m submitting a … (check one with “x”)

[ ] bug report => search github for a similar issue or PR before submitting
[x] feature request
[ ] support request => Please do not submit support request here

Current behavior The “point” color is the same as the line color and can’t be customized.

Expected behavior That would be great if series could have one more parameter to represent given point’s color, like in the attachment.

image

What is the motivation / use case for changing the behavior? More flexibility. An example use case: One may like to present server’s response times in a period of time, and whenever the response code is not HTTP-200, he would like the point to be red (when highlighting/hoovering).

Issue Analytics

  • State:open
  • Created 6 years ago
  • Reactions:11
  • Comments:6

github_iconTop GitHub Comments

2reactions
delsnercommented, Dec 7, 2017

Actually, I found an easy workaround by simply extending the existing line-chart and circle-series. See line-chart and circle-series for the code of the parent components. In case this issue gets more attention I might put more thought into this and create a PR, but I think for a lot of cases it’s easier to extend and customize the existing components.

// custom-chart.component.ts

@Component({
    selector: 'custom-line-chart',
    template: `
        <ngx-charts-chart
            [view]="[width, height]"
            [showLegend]="legend"
            [legendOptions]="legendOptions"
            [activeEntries]="activeEntries"
            [animations]="animations"
            (legendLabelClick)="onClick($event)"
            (legendLabelActivate)="onActivate($event)"
            (legendLabelDeactivate)="onDeactivate($event)">
            <svg:defs>
                <svg:clipPath [attr.id]="clipPathId">
                    <svg:rect
                        [attr.width]="dims.width + 10"
                        [attr.height]="dims.height + 10"
                        [attr.transform]="'translate(-5, -5)'"/>
                </svg:clipPath>
            </svg:defs>
            <svg:g [attr.transform]="transform" class="line-chart chart">
                <svg:g ngx-charts-x-axis
                       *ngIf="xAxis"
                       [xScale]="xScale"
                       [dims]="dims"
                       [showGridLines]="showGridLines"
                       [showLabel]="showXAxisLabel"
                       [labelText]="xAxisLabel"
                       [tickFormatting]="xAxisTickFormatting"
                       (dimensionsChanged)="updateXAxisHeight($event)">
                </svg:g>
                <svg:g ngx-charts-y-axis
                       *ngIf="yAxis"
                       [yScale]="yScale"
                       [dims]="dims"
                       [showGridLines]="showGridLines"
                       [showLabel]="showYAxisLabel"
                       [labelText]="yAxisLabel"
                       [tickFormatting]="yAxisTickFormatting"
                       [referenceLines]="filteredReferenceLines"
                       [showRefLines]="showRefLines"
                       [showRefLabels]="showRefLabels"
                       (dimensionsChanged)="updateYAxisWidth($event)">
                </svg:g>
                <svg:g [attr.clip-path]="clipPath">
                    <svg:g *ngFor="let series of results; trackBy:trackBy" [@animationState]="'active'">
                        <svg:g ngx-charts-line-series
                               [xScale]="xScale"
                               [yScale]="yScale"
                               [colors]="colors"
                               [data]="series"
                               [activeEntries]="activeEntries"
                               [scaleType]="scaleType"
                               [curve]="curve"
                               [rangeFillOpacity]="rangeFillOpacity"
                               [hasRange]="hasRange"
                               [animations]="animations"
                        />
                    </svg:g>

                    <svg:g *ngIf="!tooltipDisabled" (mouseleave)="hideCircles()">
                        <svg:g ngx-charts-tooltip-area
                               [dims]="dims"
                               [xSet]="xSet"
                               [xScale]="xScale"
                               [yScale]="yScale"
                               [results]="results"
                               [colors]="colors"
                               [tooltipDisabled]="tooltipDisabled"
                               [tooltipTemplate]="seriesTooltipTemplate"
                               (hover)="updateHoveredVertical($event)"
                        />

<!-- ############### START NEW PART ############### -->
                        <svg:g *ngIf="customSeries">
                            <svg:g custom-circle-series
                                   [xScale]="xScale"
                                   [yScale]="yScale"
                                   [colors]="colors"
                                   [data]="customSeries"
                                   [scaleType]="scaleType"
                                   [visibleValue]="hoveredVertical"
                                   [activeEntries]="activeEntries"
                                   [tooltipDisabled]="true"
                                   (select)="onClick($event, customSeries)"
                                   (activate)="onActivate($event)"
                                   (deactivate)="onDeactivate($event)"
                            />
                        </svg:g>
<!-- ############### END  ############### -->

                        <svg:g *ngFor="let series of results">
                            <svg:g ngx-charts-circle-series
                                   [xScale]="xScale"
                                   [yScale]="yScale"
                                   [colors]="colors"
                                   [data]="series"
                                   [scaleType]="scaleType"
                                   [visibleValue]="hoveredVertical"
                                   [activeEntries]="activeEntries"
                                   [tooltipDisabled]="tooltipDisabled"
                                   [tooltipTemplate]="tooltipTemplate"
                                   (select)="onClick($event, series)"
                                   (activate)="onActivate($event)"
                                   (deactivate)="onDeactivate($event)"
                            />
                        </svg:g>

                    </svg:g>
                </svg:g>
            </svg:g>
            <svg:g ngx-charts-timeline
                   *ngIf="timeline && scaleType === 'time'"
                   [attr.transform]="timelineTransform"
                   [results]="results"
                   [view]="[timelineWidth, height]"
                   [height]="timelineHeight"
                   [scheme]="scheme"
                   [customColors]="customColors"
                   [scaleType]="scaleType"
                   [legend]="legend"
                   (onDomainChange)="updateDomain($event)">
                <svg:g *ngFor="let series of results; trackBy:trackBy">
                    <svg:g ngx-charts-line-series
                           [xScale]="timelineXScale"
                           [yScale]="timelineYScale"
                           [colors]="colors"
                           [data]="series"
                           [scaleType]="scaleType"
                           [curve]="curve"
                           [hasRange]="hasRange"
                           [animations]="animations"
                    />
                </svg:g>
            </svg:g>
        </ngx-charts-chart>
    `,
    encapsulation: ViewEncapsulation.None,
    styleUrls: ['./custom-chart.component.scss'],
    changeDetection: ChangeDetectionStrategy.OnPush,
    animations: [
        trigger('animationState', [
            transition(':leave', [
                style({
                    opacity: 1,
                }),
                animate(500, style({
                    opacity: 0
                }))
            ])
        ])
    ]
})
export class CustomChartComponent extends LineChartComponent {
    @Input() customSeries: any;
    // ...
}
// custom-circle-series.component.ts

@Component({
    selector: 'g[custom-circle-series]',
    template: `
        <svg:g *ngFor="let circle of circles">
            <defs>
                <svg:g ngx-charts-svg-linear-gradient
                       orientation="vertical"
                       [name]="gradientId"
                       [stops]="circle.gradientStops"
                />
            </defs>
            <svg:g ngx-charts-circle
                   class="circle"
                   [cx]="circle.cx"
                   [cy]="circle.cy"
                   [r]="circle.radius"
                   [fill]="circle.color"
                   [class.active]="true"
                   [pointerEvents]="circle.value === 0 ? 'none': 'all'"
                   [data]="circle.value"
                   [classNames]="circle.classNames"
                   (select)="onClick($event, circle.label)"
                   (activate)="activateCircle()"
                   (deactivate)="deactivateCircle()"
                   ngx-tooltip
                   [tooltipDisabled]="true"
                   [tooltipPlacement]="'top'"
                   [tooltipType]="'tooltip'"
                   [tooltipTitle]="tooltipTemplate ? undefined : getTooltipText(circle)"
                   [tooltipTemplate]="tooltipTemplate"
                   [tooltipContext]="circle.data"
            />
        </svg:g>
    `,
    changeDetection: ChangeDetectionStrategy.OnPush,
    animations: [
        trigger('animationState', [
            transition(':enter', [
                style({
                    opacity: 0,
                }),
                animate(250, style({opacity: 1}))
            ])
        ])
    ]
})
export class CustomCircleSeriesComponent extends CircleSeriesComponent {

    getCircles(): any[] {
        if (!this.data || !this.data.name) {
            return [];
        }
        const seriesName = this.data.name;

        return this.data.series.map((d, i) => {
            const value = d.value;
            const label = d.name;
            const tooltipLabel = formatLabel(label);

            if (value) {
                let cx;
                if (this.scaleType === 'time') {
                    cx = this.xScale(label);
                } else if (this.scaleType === 'linear') {
                    cx = this.xScale(Number(label));
                } else {
                    cx = this.xScale(label);
                }

                const cy = this.yScale(this.type === 'standard' ? value : d.d1);
                const radius = 5;
                const height = this.yScale.range()[0] - cy;

                let opacity = 1;
                if (label && this.visibleValue && label.toString() === this.visibleValue.toString()) {
                    opacity = 1;
                }

                let color;
                if (this.colors.scaleType === 'linear') {
                    if (this.type === 'standard') {
                        color = this.colors.getColor(value);
                    } else {
                        color = this.colors.getColor(d.d1);
                    }
                } else {
                    color = this.colors.getColor(seriesName);
                }

                const data = {
                    series: seriesName,
                    value,
                    name: label
                };

                return {
                    classNames: [`circle-data-${i}`],
                    value,
                    label,
                    data,
                    cx,
                    cy,
                    radius,
                    height,
                    tooltipLabel,
                    color,
                    opacity,
                    seriesName,
                    gradientStops: this.getGradientStops(color),
                    min: d.min,
                    max: d.max
                };
            }
        }).filter((circle) => circle !== undefined);
    }
}
0reactions
sachinkondanacommented, Sep 23, 2022

I kind of used one different approach to achieve something similar, In my case i need to highlight few points of line chart in red and few in green,

What i did was,

this._values = [...data, highlightSeries]

Yes, i created one extra line series with only the highlight points. And i use some conditions in my line chart to not to draw line for this extra series.

const createHighlightSeries =  () => {
        const series = []

        data.forEach((lineData) => {
            lineData.series.forEach((d) => {
                if (d.hasFav) {
                    series.push({
                        name: d.name,
                        value: d.value,
                    })
                }
            })
        })

        return {
            name: 'no_line',
            series: series,
        }

}

<ngx-charts-line-chart
        #chart
        [results]=[...values, createHighlightSeries()]
        ...
    >
    </ngx-charts-line-chart>
    

And here https://github.com/swimlane/ngx-charts/issues/467#issuecomment-645795010, i made few changes to not to display line in svg for this new series

import { Injectable } from '@angular/core';
@Injectable()
export class CustomLinerChartService {
	/**
	 * custom: override SVG to have the dots display all the time over the liner chart
	 * since it's not supported anymore from ngx chart
	 */

	showDots(chart) {
		let index = 0;
		const paths = chart.chartElement.nativeElement.getElementsByClassName(
			'line-series'
		);
		const color = chart.chartElement.nativeElement.getElementsByClassName(
			'line-highlight'
		);
no_line_index = 2
		for (let path of paths) {
			const chrtColor = color[index].getAttribute('ng-reflect-fill');
			const pathElement = path.getElementsByTagName('path')[0];
			const pathAttributes = {
			         ...(no_line_index===index ? { stroke: 'none' } : {}),
				'marker-start': `url(#dot${index})`,
				'marker-mid': `url(#dot${index})`,
				'marker-end': `url(#dot${index})`
			};
			this.createMarker(chart, no_line_index===index ? chrtColor : 'red', index);
			this.setAttributes(pathElement, pathAttributes);
			index += 1;
		}
	}

	/**
	 * create marker
	 *
	 */

	createMarker(chart, color, index) {
		const svg = chart.chartElement.nativeElement.getElementsByTagName('svg');
		var marker = document.createElementNS(
			'http://www.w3.org/2000/svg',
			'marker'
		);
		var circle = document.createElementNS(
			'http://www.w3.org/2000/svg',
			'circle'
		);
		svg[0].getElementsByTagName('defs')[0].append(marker);
		marker.append(circle);
		const m = svg[0].getElementsByTagName('marker')[0];
		const c = svg[0].getElementsByTagName('circle')[0];

		const markerAttributes = {
			id: `dot${index}`,
			viewBox: '0 0 10 10',
			refX: 5,
			refY: 5,
			markerWidth: 5,
			markerHeight: 5
		};

		const circleAttributes = {
			cx: 5,
			cy: 5,
			r: 5,
			fill: color
		};
		m.append(circle);

		this.setAttributes(m, markerAttributes);
		this.setAttributes(c, circleAttributes);
	}

	/**
	 * set multiple attributes
	 */
	setAttributes(element, attributes) {
		for (const key in attributes) {
			element.setAttribute(key, attributes[key]);
		}
	}
}
Read more comments on GitHub >

github_iconTop Results From Across the Web

Vary the colors of same-series data markers in a chart
Set varying colors of data markers (bars, columns, lines, pie or doughnut slices, dots, and other shapes) automatically in an Office chart.
Read more >
A Complete Guide to Line Charts | Tutorial by Chartio
Line charts are a fundamental chart type generally used to show change in values across time. Learn how to best use this chart...
Read more >
Excel Multi-colored Line Charts - My Online Training Hub
The chart below contains 3 lines; red, yellow and green. They are sitting on top of one another to give the appearance of...
Read more >
How to Change the Color of Line in Excel Line Graph - YouTube
In this video, you will learn how to change the color of the line in an excel line graph.How to Change the Color...
Read more >
JavaScript Point Line Chart - LightningChart
As it was mentioned before, the series accepts points in format { x: number, y: number: color: Color } with specified IndividualPointFill to...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found