Skip to main content
cancel
Showing results for 
Search instead for 
Did you mean: 

Earn the coveted Fabric Analytics Engineer certification. 100% off your exam for a limited time only!

Reply
az2451
Resolver I
Resolver I

How to draw a linear line by using a given slope

 

Hello there, i have an urgent problem here that i cant solve...

 

I'm trying to draw a linear line in a scatter plot to visualize a given slope-value.

 

First of all, this is how i calculate my "slope" by simply dividing each value from the x-axis with each value of the y-axis.

-> Btw: This will only change the color-values of the datapoints, not the actual datapoint-positions <-

 

Spoiler
function visualTransform(...) {

...

for (let i = 0; i < myCategory.values.length; i++) {

if((xAxisValues[i]/yAxisValues[i]>0.2){ colorVal = 'blue'; } else { colorVal = 'yellow'; }

}

...

}

 

 

For example, this is how the scatter plot looks like with a slope of 0.2 in comparison with a slope of 1

Screenshot (27).png

Screenshot (28).png

 

 

 

Now im looking for a solution for how to draw a linear line by using a given slope.

I tried that of course by creating a svg element and just rotating it by converting the slope-value in to degrees, like in this function (-> a slope of 0.2 is about 11.3 degrees)

 

Spoiler
function getAngleDeg(ax,ay) {
   var angleRad = Math.atan(ay/ax);
   var angleDeg = angleRad * 180 / Math.PI;
   return(angleDeg);

// if the slope is 0.2, this will be about 78.69 deg. But we have to subtract it from 90 as the line is in a 90 deg position, which makes 11.3

}

...

// Drawing the linear line:

             let sLine = this.g
                .append('g')
                .append('rect')
                .classed('sLine', true)
                .attr('x', x(0))
                .attr('y', y(30))
                .attr('width', 2)
                .attr('height', gHeight)
                .attr('transform', 'rotate(' + (getAngleDeg(0.2,1)) + ',' + x(0) + ',' + y(30) + ')')
                .style('fill-opacity', viewModel.settings.generalView.opacity/100); 

 

 

But unfortunately this only works partial for me.

As you can see in the picture, at a certain point it works fine:

 

Screenshot (25).png

But as i scale the visual smaller it looks totally wrong, because the datapoints begin to compress more and more. The line is not affected however:

 

Screenshot (26).png

I dont know how to fix this... My next idea was to subtract the degree-value by using a multiplier as the visual-sandbox size changes. Didnt worked either.

 

There must be an easier way!

 

Does anyone has a solution?

 

2 ACCEPTED SOLUTIONS
v-viig
Community Champion
Community Champion

The width and height are not supported by a line element.

It seems you should apply a color to this line.

 

Ignat Vilesov,

Software Engineer

 

Microsoft Power BI Custom Visuals

pbicvsupport@microsoft.com

View solution in original post

Thanks this worked for me:

 

               let sLine = this.g
               .append('g')
               .append('line') 
               .classed('sLine', true)
               .attr('x1', x(0))
               .attr('y1', y(0))
               .attr('x2', x(viewModel.dataMax * this.slopeVal[0]))
               .attr('y2', y(viewModel.dataMax))
               .attr('stroke', 'red');

 

View solution in original post

12 REPLIES 12
v-viig
Community Champion
Community Champion

The line is always rendered at the same position as you use fixed coordinates (.attr('x', x(0)) .attr('y', y(30))).

We'd recommned to use dynamic coordinates instead.

 

Ignat Vilesov,

Software Engineer

 

Microsoft Power BI Custom Visuals

pbicvsupport@microsoft.com

Thanks for your answer, i believe this is true but i dont have any idea how to define the coordinates dynamically.

 

Which variables i can use to realize this?

 

Any suggestions?

v-viig
Community Champion
Community Champion

I guess you would need to get a coordinate by point's value.

 

Ignat Vilesov,

Software Engineer

 

Microsoft Power BI Custom Visuals

pbicvsupport@microsoft.com

Well, i can set the y-axis by using the datapoints-value like so:

 

          let sLine = this.g
                .append('g')
                .append('rect')
                .classed('sLine', true)
                .attr('x', x(0))
                .attr('y', y(d3.max(viewModel.dataPoints, function(d) { return <number>d.yAxisValues; })))
                .attr('width', d3.min([height, width]) * BarChart.Config.weightMultiplier)
                .attr('height', (gHeight))
                .attr('transform', 'rotate(' + (7) + ',' + x(0) + ',' + y((d3.max(viewModel.dataPoints, function(d) { return <number>d.yAxisValues; }))) + ')')
                .style('fill-opacity', viewModel.settings.generalView.opacity/100); 

But thats still not solving the issue like in the pictures i showed before.

 

The x-axis needs to be always 0,  because the linear line should only rotate from 0

 

Im getting so frustated on this 🙂

v-viig
Community Champion
Community Champion

I think there're no need to use scaling to draw a line. You might use 0 instead of x(0).

 

Have you already tried such solution?

 

Ignat Vilesov,

Software Engineer

 

Microsoft Power BI Custom Visuals

pbicvsupport@microsoft.com

Thanks for your help Ignat,

 

the x-scale is needed because we also have negative values on the x-axis. When i set 0 instead of x(0) it will draw the line on the smallest value (-7 or so). It also doesnt solve the main problem unfortunately,

 

Do you want to check out my code so you will get a better picture of it? I uploaded my randomized dataset, my project folder and also the .pbix file for you and commented it as far as i could: https://drive.google.com/open?id=1g4u6AaQw-X8fdQqOT5Ela55HTJWzONlN

 

I would be glad if we can solve this problem together, im stuck on this final part for my visual.

 

v-viig
Community Champion
Community Champion

It seems this issue is related to scaling the main chart if we resize a visual.

I'm not sure what part of code applies scaling but it must be applied to the line as well.

 

Ignat Vilesov,

Software Engineer

 

Microsoft Power BI Custom Visuals

pbicvsupport@microsoft.com

This is what i thought about too earlier, but thats already the case! 🙂

 

The scaling is achieved by the x and y variables. Since the range is always the width/height of the sandbox (subtracted by margins).

So that means if i resize the graph it will call the update() method again and calculate the new x/y-scale by using the new width/height-values of the graph:

Spoiler
            // Scale of x-axis
            let x = d3.scale.linear()
                .range([0gWidth])
.domain([(d3.min(viewModel.dataPointsfunction(d) { return <number>d.gesamtKosten; }) - meanGesamtKosten),
(d3.max(viewModel.dataPointsfunction(d) { return <number>d.gesamtKosten; }) + meanGesamtKosten)]);

            // Scale of y-axis
            let y = d3.scale.linear()
                .range([gHeight0])
.domain([(d3.min(viewModel.dataPointsfunction(d) { return <number>d.anzahlKostenstellen; }) - meanAnzahlKostenstellen),
(d3.max(viewModel.dataPointsfunction(d) { return <number>d.anzahlKostenstellen; }) + meanAnzahlKostenstellen)]);

 

This is how the scaling works.

 

But i think the problem has something to do with the rotation of the line:

 

 // Create a SVG-Element (linear line)
            let sLine = this.g
                .append('g')
                .append('rect')
                .classed('sLine', true)
                .attr('x', x(0))
                .attr('y', y(d3.max(viewModel.dataPoints, function(d) { return <number>d.anzahlKostenstellen; }) + meanAnzahlKostenstellen))
                .attr('width', d3.min([height, width]) * BarChart.Config.weightMultiplier)
                .attr('height', (gHeight - (meanGesamtKosten * 2)))
                .attr('transform', 'rotate(' + (7) + ',' + x(0) + ',' + y((d3.min(viewModel.dataPoints, function(d) { return <number>d.anzahlKostenstellen; }) - meanAnzahlKostenstellen)) + ')')
                .style('fill-opacity', viewModel.settings.generalView.opacity/100); 

 

You can test it like this:

change the line to 0deg:

 .attr('transform', 'rotate(' + (0) + ',' + x(0) + ',' + y((d3.min(viewModel.dataPoints, function(d) { return <number>d.anzahlKostenstellen; }) - meanAnzahlKostenstellen)) + ')')

 

Now when you scale the graph, the line stays where it should be. The datapoints arent moving behind the line anymore.

 

Try it for yourself if you want.

 

 

 

EDIT: I changed from 0 degree to x(d3.min(xAxisValues))*0.2 (multiplied by slope-value):

 

.attr('transform', 'rotate(' + (x((d3.min(viewModel.dataPoints, function(d) { return <number>d.gesamtKosten; }))+meanGesamtKosten)*0.2) + ',' + x(0) + ',' + y((d3.min(viewModel.dataPoints, function(d) { return <number>d.anzahlKostenstellen; }) - meanAnzahlKostenstellen)) + ')')

Now it looks a little bit better. BUT only when i resize the graphs-width. When i resize the graph to its height, im still getting the same problem.

I tried playing with the y-scale, but couldnt figure it out much how to solve this.

 

I dont get it how a simple line can cause such big problems 🙂

 

 

 

v-viig
Community Champion
Community Champion

Do you really have to rotate a line (rect element)?

Have you tried to use line element isntead?

 

Ignat Vilesov,

Software Engineer

 

Microsoft Power BI Custom Visuals

pbicvsupport@microsoft.com

I tried that but i think line is not supported because nothing shows up at all

 

               let sLine = this.g
               .append('g')
               .append('line') // rect and circle works, but line doesnt however
               .classed('sLine', true)
               .attr('x1', x(0))
               .attr('y1', y(5))
               .attr('x2', x(10))
               .attr('y2', y(20))
               .attr('width', 2)
               .attr('height', 500);
v-viig
Community Champion
Community Champion

The width and height are not supported by a line element.

It seems you should apply a color to this line.

 

Ignat Vilesov,

Software Engineer

 

Microsoft Power BI Custom Visuals

pbicvsupport@microsoft.com

Thanks this worked for me:

 

               let sLine = this.g
               .append('g')
               .append('line') 
               .classed('sLine', true)
               .attr('x1', x(0))
               .attr('y1', y(0))
               .attr('x2', x(viewModel.dataMax * this.slopeVal[0]))
               .attr('y2', y(viewModel.dataMax))
               .attr('stroke', 'red');

 

Helpful resources

Announcements
April AMA free

Microsoft Fabric AMA Livestream

Join us Tuesday, April 09, 9:00 – 10:00 AM PST for a live, expert-led Q&A session on all things Microsoft Fabric!

March Fabric Community Update

Fabric Community Update - March 2024

Find out what's new and trending in the Fabric Community.

Top Solution Authors