Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lazy scatterplot for Vector & Table #3655

Merged
merged 13 commits into from
Aug 23, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ class ScatterPlot extends Visualization {

constructor(data) {
super(data)
this.setPreprocessor('process_to_json_text', 'Standard.Visualization.Scatter_Plot')
this.bounds = null
this.limit = 32
JaroslavTulach marked this conversation as resolved.
Show resolved Hide resolved
this.updatePreprocessor()
this.dataPoints = []
this.axis = {
x: { scale: LINEAR_SCALE },
Expand All @@ -58,6 +60,14 @@ class ScatterPlot extends Visualization {
this.points = { labels: VISIBLE_POINTS }
}

updatePreprocessor() {
let fn = 'x -> process_to_json_text x limit=' + this.limit
Copy link
Member Author

@JaroslavTulach JaroslavTulach Aug 19, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CCing @4e6: Calling this.setPreprocessor repeatedly with different code snippet seems to work, but ideally we shall have a single snippet and just invoke it with different limit and bounds argument. I hope it will be possible to do something like that with hidden modules.

#3661 introduces this.setPreprocessor(module, method) - it shall also allow providing arguments somehow.

if (this.bounds) {
fn += ' bounds=[' + this.bounds.join(',') + ']'
}
this.setPreprocessor(fn, 'Standard.Visualization.Scatter_Plot')
}

/**
* Presents a scatterplot visualization after receiving `data`.
*/
Expand Down Expand Up @@ -377,6 +387,9 @@ class ScatterPlot extends Visualization {
let yMin = zoom.transformedScale.yScale.invert(extent[1][1])
let yMax = zoom.transformedScale.yScale.invert(extent[0][1])

this.bounds = [xMin, yMin, xMax, yMax]
this.updatePreprocessor()

zoom.transformedScale.xScale.domain([xMin, xMax])
zoom.transformedScale.yScale.domain([yMin, yMax])

Expand Down Expand Up @@ -726,7 +739,7 @@ class ScatterPlot extends Visualization {
addStyleToElem(
'button',
`
margin-left: 5px;
margin-left: 5px;
margin-bottom: 5px;
display: inline-block;
padding: 2px 10px;
Expand Down Expand Up @@ -806,6 +819,10 @@ class ScatterPlot extends Visualization {
zoom.transformedScale.yScale.domain(domainY)

self.zoomingHelper(zoom.transformedScale, boxWidth, scatter, points)

self.bounds = null
self.limit = 32
JaroslavTulach marked this conversation as resolved.
Show resolved Hide resolved
self.updatePreprocessor();
}

document.addEventListener('keydown', e => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ from Standard.Base import all
import Standard.Table.Data.Column
import Standard.Table.Data.Table
import Standard.Visualization.Helpers
from Standard.Base.Data.Index_Sub_Range import Sample

## PRIVATE

Expand Down Expand Up @@ -132,10 +133,26 @@ Table.Table.axes self =
if axes_obj.fields.size > 0 then axes_obj else Nothing

## PRIVATE
Vector.Vector.point_data : Vector -> Object
Vector.Vector.point_data self =
self.map_with_index <| i-> elem->
Json.from_pairs [[X.name,i],[Y.name,elem]]
Vector.Vector.point_data : Vector -> [Int]|Nothing -> Int|Nothing-> Object
Vector.Vector.point_data self bounds limit =
data = case bounds of
Nothing ->
self.map_with_index <| i-> elem->
Json.from_pairs [[X.name,i],[Y.name,elem]]
_ ->
minX = bounds.at 0
minY = bounds.at 1
maxX = bounds.at 2
maxY = bounds.at 3
pairs = self.map_with_index <| i-> elem->
if minX>i || i>maxX || minY>elem || elem>maxY then Nothing else
Json.from_pairs [[X.name,i],[Y.name,elem]]
pairs.filter case _ of
Nothing -> False
_ -> True
case limit of
Nothing -> data
n -> data.take (Sample n)
JaroslavTulach marked this conversation as resolved.
Show resolved Hide resolved

## PRIVATE
json_from_table : Table -> Json
Expand All @@ -146,8 +163,8 @@ json_from_table table =

## PRIVATE
json_from_vector : Vector Any -> Json
json_from_vector vec =
data = [data_field, vec.point_data]
json_from_vector vec bounds=Nothing limit=Nothing =
data = [data_field, vec.point_data bounds limit]
axes = [axis_field, Nothing]
Json.from_pairs [data, axes]

Expand All @@ -160,11 +177,11 @@ json_from_vector vec =
Arguments:
- value: the value to be visualized.
process_to_json_text : Any -> Text
process_to_json_text value =
process_to_json_text value bounds=Nothing limit=Nothing =
json = case value of
Column.Column _ -> json_from_table value.to_table
Table.Table _ -> json_from_table value
Vector.Vector _ -> json_from_vector value
Vector.Vector _ -> json_from_vector value bounds=bounds limit=limit
_ -> json_from_vector value.to_vector

json.to_text
Expand Down
21 changes: 19 additions & 2 deletions test/Visualization_Tests/src/Scatter_Plot_Spec.enso
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ import Standard.Test
import project

spec =
expect value axis_expected_text data_expected_text =
text = Scatter_Plot.process_to_json_text value
expect_text text axis_expected_text data_expected_text =
json = Json.parse text
json.fields.keys.should_equal ['axis','data']

Expand All @@ -20,6 +19,10 @@ spec =
expected_result = Json.from_pairs [expected_axis_labels, expected_data_pair]
json.should_equal expected_result

expect value axis_expected_text data_expected_text =
text = Scatter_Plot.process_to_json_text value
expect_text text axis_expected_text data_expected_text

index = Scatter_Plot.index_name
axis label = Json.from_pairs [['label',label]]
labels x y = Json.from_pairs [['x', axis x], ['y', axis y]] . to_text
Expand Down Expand Up @@ -96,6 +99,20 @@ spec =
vector = [0,10,20]
expect vector no_labels '[{"x":0,"y":0},{"x":1,"y":10},{"x":2,"y":20}]'

Test.specify "limit the number of elements" <|
vector = [0,10,20,30]
text = Scatter_Plot.process_to_json_text vector limit=2
json = Json.parse text
json.fields.keys.should_equal ['axis','data']
data = json.fields.get 'data'
data.unwrap.length . should_equal 2

Test.specify "filter the elements" <|
vector = [0,10,20,30]
bounds = [0,5,10,25]
text = Scatter_Plot.process_to_json_text vector bounds
expect_text text no_labels '[{"x":1,"y":10},{"x":2,"y":20}]'

Test.specify "using indices for x if given a column" <|
column = Column.from_vector 'some_col' [10,2,3]
expect column (labels 'index' 'some_col') '[{"x":0,"y":10},{"x":1,"y":2},{"x":2,"y":3}]'
Expand Down