I'm working on a regression model visualizer and my current bottleneck has to do with plotting continuous functions.
How the program works is that it loads data from a file containing (x, y) values, does the math for the regression model with matrices and then gives the regression models points to ScatterChart
for plotting.
A single plot point for the regression model is determined by the coefficients of the model and a step
which acts as a dx between two original data points.
Essentially, if the dx is set to be 0.1 and x1 = 0, x2 = 10, we will have 98 model points between x1 and x2. If you are interested here's the math for the model: https://newonlinecourses.science.psu.edu/stat501/node/382/
The PolynomialGraph
shown in the code is essentially a regression model.
It knows how to give original data points until a max value and how to calculate models plot points to that maximum value. All the values are (Double, Double)
tuples.
My problem has to do with the fact that depending on how many plot points I calculate, the plot drawn might not be continuous all the way. This is due to the fact that a single plot point has a constant size (determined in CSS), so if the ScatterChart
has large width
and the dx between two plot points (x1, y1) and (x2, y2) is too large relative to the endpoint of the x axis there will be visible spaces in the plot. The size and shape of original and model's points are in the CSS code below.
An example could be that (x1, y1) = (0, 10) and (x2, y2) = (100, 110) and dx = 100. Now zero points are drawn between (x1, y1) and (x2, y2).
Is there a reasonable way to fix this problem? I've tried my best with ScalaFX and JavaFX API. But I want to believe that there is a better fix than somehow calculating how many plot points will approximately be in a single pixel and that way determining how many points need to be drawn.
Other way could be to find the intervals where dy is the greatest and somehow that way determine how many points is needed.
Other than that I really don't have a clue to fix this problem dynamically. I can always set the dx be around 10E-9
but that doesn't scale well at all.
If the range of values in the x axis is massive, we can easily set the dx be even 100. While if the maximum value happens to be one, we may need the dx be around the 10E-9
.
package regression
import scalafx.scene.chart.ScatterChart
import scalafx.collections.ObservableBuffer
import scalafx.scene.chart.XYChart
import scalafx.scene.chart.NumberAxis
object Plotter {
def drawGraph(xName: String, yName: String, graph: PolynomialGraph): ScatterChart[Number, Number] = {
val xAxis = NumberAxis()
val yAxis = NumberAxis()
val pData = XYChart.Series[Number, Number](
xName,
ObservableBuffer(graph.dataPointsUntilMaxX().map(z => XYChart.Data[Number, Number](z._2, z._1)): _*)) //Values have to be in order x, y
val model = XYChart.Series[Number, Number](
yName,
ObservableBuffer(graph.calculatePlotPoints().map(z => XYChart.Data[Number, Number](z._1, z._2)): _*))
val temp = new ScatterChart(xAxis, yAxis, ObservableBuffer(model, pData))
temp
}
}
.default-color0.chart-symbol {
-fx-background-color: blue;
-fx-background-radius: 0.5px;
-fx-opacity: 1.0;
-fx-padding: 1px;
}
.default-color1.chart-symbol {
-fx-background-color: red, white;
-fx-background-insets: 0, 2;
-fx-background-radius: 2px;
-fx-padding: 3px;
}
Maximum x value of the original data is 23.5
First image shown has a dx of 0.001, meaning that 23500 points are calculated for the models plot.
Second image shown has a dx of 0.1. Now only 235 points are calculated for the plot and there is visible space between any two points in the curve.