Skip to content

Commit 99df9dd

Browse files
committed
[SPARK-45120][SPARK-45150][UI] Upgrade d3 from v3 to v7(v7.8.5) and apply api changes in UI
### What changes were proposed in this pull request? This PR is a follow-up of SPARK-45120 to cover the missing cases, and then fix test failures reported by SPARK-45150 It also brings back #42879 ### Why are the changes needed? bugfix ### Does this PR introduce _any_ user-facing change? no ### How was this patch tested? tested with the excluded CI tests bellow ``` [info] ChromeUISeleniumSuite: Starting ChromeDriver 117.0.5938.62 (25a7172909a4cba7355365cf424d7d7eb35231f4-refs/branch-heads/5938{#1146}) on port 12624 Only local connections are allowed. Please see https://chromedriver.chromium.org/security-considerations for suggestions on keeping ChromeDriver safe. ChromeDriver was started successfully. [info] - SPARK-31534: text for tooltip should be escaped (1 second, 979 milliseconds) [info] - SPARK-31882: Link URL for Stage DAGs should not depend on paged table. (683 milliseconds) [info] - SPARK-31886: Color barrier execution mode RDD correctly (304 milliseconds) [info] - Search text for paged tables should not be saved (1 second, 307 milliseconds) [info] Run completed in 6 seconds, 702 milliseconds. [info] Total number of tests run: 4 [info] Suites: completed 1, aborted 0 [info] Tests: succeeded 4, failed 0, canceled 0, ignored 0, pending 0 [info] All tests passed. ```` ### Was this patch authored or co-authored using generative AI tooling? no Closes #42907 from yaooqinn/SPARK-45150. Authored-by: Kent Yao <[email protected]> Signed-off-by: Kent Yao <[email protected]>
1 parent b6190a3 commit 99df9dd

File tree

9 files changed

+88
-114
lines changed

9 files changed

+88
-114
lines changed

LICENSE

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,6 @@ BSD 3-Clause
229229
python/lib/py4j-*-src.zip
230230
python/pyspark/cloudpickle/*.py
231231
python/pyspark/join.py
232-
core/src/main/resources/org/apache/spark/ui/static/d3.min.js
233232

234233
The CSS style for the navigation sidebar of the documentation was originally
235234
submitted by Óscar Nájera for the scikit-learn project. The scikit-learn project
@@ -248,6 +247,11 @@ docs/js/vendor/anchor.min.js
248247
docs/js/vendor/jquery*
249248
docs/js/vendor/modernizer*
250249

250+
ISC License
251+
-----------
252+
253+
core/src/main/resources/org/apache/spark/ui/static/d3.min.js
254+
251255

252256
Creative Commons CC0 1.0 Universal Public Domain Dedication
253257
-----------------------------------------------------------

LICENSE-binary

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,6 @@ org.jdom:jdom2
461461
python/lib/py4j-*-src.zip
462462
python/pyspark/cloudpickle.py
463463
python/pyspark/join.py
464-
core/src/main/resources/org/apache/spark/ui/static/d3.min.js
465464

466465
The CSS style for the navigation sidebar of the documentation was originally
467466
submitted by Óscar Nájera for the scikit-learn project. The scikit-learn project
@@ -498,6 +497,11 @@ docs/js/vendor/anchor.min.js
498497
docs/js/vendor/jquery*
499498
docs/js/vendor/modernizer*
500499

500+
ISC License
501+
-----------
502+
503+
core/src/main/resources/org/apache/spark/ui/static/d3.min.js
504+
501505

502506
Common Development and Distribution License (CDDL) 1.0
503507
------------------------------------------------------

core/src/main/resources/org/apache/spark/ui/static/d3.min.js

Lines changed: 2 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/src/main/resources/org/apache/spark/ui/static/spark-dag-viz.js

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -249,9 +249,9 @@ function renderDagVizForJob(svgContainer) {
249249
// existing ones, taking into account the position and width of the last stage's
250250
// container. We do not need to do this for the first stage of this job.
251251
if (i > 0) {
252-
var existingStages = svgContainer.selectAll("g.cluster.stage");
253-
if (!existingStages.empty()) {
254-
var lastStage = d3.select(existingStages[0].pop());
252+
var existingStages = svgContainer.selectAll("g.cluster.stage").nodes();
253+
if (existingStages.length > 0) {
254+
var lastStage = d3.select(existingStages.pop());
255255
var lastStageWidth = toFloat(lastStage.select("rect").attr("width"));
256256
var lastStagePosition = getAbsolutePosition(lastStage);
257257
var offset = lastStagePosition.x + lastStageWidth + VizConstants.stageSep;
@@ -346,7 +346,7 @@ function preprocessGraphLayout(g, forJob) {
346346
* This assumes that all outermost elements are clusters (rectangles).
347347
*/
348348
function resizeSvg(svg) {
349-
var allClusters = svg.selectAll("g.cluster rect")[0];
349+
var allClusters = svg.selectAll("g.cluster rect").nodes();
350350
var startX = -VizConstants.svgMarginX +
351351
toFloat(d3.min(allClusters, function(e) {
352352
return getAbsolutePosition(d3.select(e)).x;
@@ -380,14 +380,12 @@ function resizeSvg(svg) {
380380
function interpretLineBreak(svg) {
381381
svg.selectAll("tspan").each(function() {
382382
var node = d3.select(this);
383-
var original = node[0][0].innerHTML;
384-
if (original.indexOf("\\n") != -1) {
383+
var original = node.html();
384+
if (original.indexOf("\\n") !== -1) {
385385
var arr = original.split("\\n");
386386
var newNode = this.cloneNode(this);
387-
388-
node[0][0].innerHTML = arr[0];
389-
newNode.innerHTML = arr[1];
390-
387+
node.html(arr[0])
388+
newNode.html(arr[1]);
391389
this.parentNode.appendChild(newNode);
392390
}
393391
});
@@ -433,7 +431,7 @@ function getAbsolutePosition(d3selection) {
433431
while (!obj.empty()) {
434432
var transformText = obj.attr("transform");
435433
if (transformText) {
436-
var translate = d3.transform(transformText).translate;
434+
var translate = transformText.substring("translate(".length, transformText.length - 1).split(",")
437435
_x += toFloat(translate[0]);
438436
_y += toFloat(translate[1]);
439437
}
@@ -497,7 +495,7 @@ function connectRDDs(fromRDDId, toRDDId, edgesContainer, svgContainer) {
497495
];
498496
}
499497

500-
var line = d3.svg.line().interpolate("basis");
498+
var line = d3.line().curve(d3.curveBasis);
501499
edgesContainer.append("path").datum(points).attr("d", line);
502500
}
503501

core/src/main/resources/org/apache/spark/ui/static/streaming-page.js

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -100,16 +100,15 @@ function registerTimeline(minY, maxY) {
100100
// Register a histogram graph. All histogram graphs should be register before calling any
101101
// "drawHistogram" so that we can determine the max X value for histograms.
102102
function registerHistogram(values, minY, maxY) {
103-
var data = d3.layout.histogram().range([minY, maxY]).bins(histogramBinCount)(values);
104-
// d.x is the y values while d.y is the x values
105-
var maxX = d3.max(data, function(d) { return d.y; });
103+
var data = d3.bin().domain([minY, maxY]).thresholds(histogramBinCount)(values);
104+
var maxX = d3.max(data, (d) => d.length);
106105
maxXForHistogram = maxX > maxXForHistogram ? maxX : maxXForHistogram;
107106
}
108107
/* eslint-enable no-unused-vars */
109108

110109
// Draw a line between (x1, y1) and (x2, y2)
111110
function drawLine(svg, xFunc, yFunc, x1, y1, x2, y2) {
112-
var line = d3.svg.line()
111+
var line = d3.line()
113112
.x(function(d) { return xFunc(d.x); })
114113
.y(function(d) { return yFunc(d.y); });
115114
var data = [{x: x1, y: y1}, {x: x2, y: y2}];
@@ -141,10 +140,10 @@ function drawTimeline(id, data, minX, maxX, minY, maxY, unitY, batchInterval) {
141140
var width = 500 - margin.left - margin.right;
142141
var height = 150 - margin.top - margin.bottom;
143142

144-
var x = d3.scale.linear().domain([minX, maxX]).range([0, width]);
145-
var y = d3.scale.linear().domain([minY, maxY]).range([height, 0]);
143+
var x = d3.scaleLinear().domain([minX, maxX]).range([0, width]);
144+
var y = d3.scaleLinear().domain([minY, maxY]).range([height, 0]);
146145

147-
var xAxis = d3.svg.axis().scale(x).orient("bottom").tickFormat(function(d) {
146+
var xAxis = d3.axisBottom(x).tickFormat(function(d) {
148147
var formattedDate = timeFormat[d];
149148
var dotIndex = formattedDate.indexOf('.');
150149
if (dotIndex >= 0) {
@@ -154,10 +153,9 @@ function drawTimeline(id, data, minX, maxX, minY, maxY, unitY, batchInterval) {
154153
return formattedDate;
155154
}
156155
});
157-
var formatYValue = d3.format(",.2f");
158-
var yAxis = d3.svg.axis().scale(y).orient("left").ticks(5).tickFormat(formatYValue);
156+
var yAxis = d3.axisLeft(y).ticks(5).tickFormat(yValueFormat);
159157

160-
var line = d3.svg.line()
158+
var line = d3.line()
161159
.x(function(d) { return x(d.x); })
162160
.y(function(d) { return y(d.y); });
163161

@@ -213,7 +211,7 @@ function drawTimeline(id, data, minX, maxX, minY, maxY, unitY, batchInterval) {
213211
.attr("cy", function(d) { return y(d.y); })
214212
.attr("r", function(d) { return isFailedBatch(d.x) ? "2" : "3";})
215213
.on('mouseover', function(d) {
216-
var tip = formatYValue(d.y) + " " + unitY + " at " + timeTipStrings[d.x];
214+
var tip = yValueFormat(d.y) + " " + unitY + " at " + timeTipStrings[d.x];
217215
showBootstrapTooltip(d3.select(this).node(), tip);
218216
// show the point
219217
d3.select(this)
@@ -252,13 +250,19 @@ function drawHistogram(id, values, minY, maxY, unitY, batchInterval) {
252250
var width = 350 - margin.left - margin.right;
253251
var height = 150 - margin.top - margin.bottom;
254252

255-
var x = d3.scale.linear().domain([0, maxXForHistogram]).range([0, width - 50]);
256-
var y = d3.scale.linear().domain([minY, maxY]).range([height, 0]);
253+
var x = d3
254+
.scaleLinear()
255+
.domain([0, maxXForHistogram])
256+
.range([0, width - 50]);
257+
var y = d3
258+
.scaleLinear()
259+
.domain([minY, maxY])
260+
.range([height, 0]);
257261

258-
var xAxis = d3.svg.axis().scale(x).orient("top").ticks(5);
259-
var yAxis = d3.svg.axis().scale(y).orient("left").ticks(0).tickFormat(function(d) { return ""; });
262+
var xAxis = d3.axisTop(x).ticks(5);
263+
var yAxis = d3.axisLeft(y).ticks(0).tickFormat(function(d) { return ""; });
260264

261-
var data = d3.layout.histogram().range([minY, maxY]).bins(histogramBinCount)(values);
265+
var data = d3.bin().domain([minY, maxY]).thresholds(histogramBinCount)(values);
262266

263267
var svg = d3.select(id).append("svg")
264268
.attr("width", width + margin.left + margin.right)
@@ -285,13 +289,13 @@ function drawHistogram(id, values, minY, maxY, unitY, batchInterval) {
285289
.data(data)
286290
.enter()
287291
.append("g")
288-
.attr("transform", function(d) { return "translate(0," + (y(d.x) - height + y(d.dx)) + ")";})
292+
.attr("transform", (d, i) => "translate(0," + (height - (i + 1) * (y(d.x0) - y(d.x1))) + ")")
289293
.attr("class", "bar").append("rect")
290-
.attr("width", function(d) { return x(d.y); })
291-
.attr("height", function(d) { return height - y(d.dx); })
292-
.on('mouseover', function(d) {
293-
var percent = yValueFormat(d.y * 100.0 / values.length) + "%";
294-
var tip = d.y + " batches (" + percent + ") between " + yValueFormat(d.x) + " and " + yValueFormat(d.x + d.dx) + " " + unitY;
294+
.attr("width", (d) => x(d.length))
295+
.attr("height", (d) => y(d.x0) - y(d.x1))
296+
.on('mouseover', function(event, d) {
297+
var percent = yValueFormat(d.length / values.length) + "%";
298+
var tip = d.length + " batches (" + percent + ") between " + yValueFormat(d.x0) + " and " + yValueFormat(d.x1) + " " + unitY;
295299
showBootstrapTooltip(d3.select(this).node(), tip);
296300
})
297301
.on('mouseout', function() {

core/src/main/resources/org/apache/spark/ui/static/structured-streaming-page.js

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -39,37 +39,30 @@ function drawAreaStack(id, labels, values, minX, maxX, minY, maxY) {
3939

4040
var data = values;
4141

42-
var parse = d3.time.format("%H:%M:%S.%L").parse;
42+
var parse = d3.timeParse("%H:%M:%S.%L");
4343

4444
// Transpose the data into layers
45-
var dataset = d3.layout.stack()(labels.map(function(fruit) {
45+
var dataset = d3.stack()(labels.map(function(fruit) {
4646
return data.map(function(d) {
4747
return {_x: d.x, x: parse(d.x), y: +d[fruit]};
4848
});
4949
}));
5050

5151
// Set x, y and colors
52-
var x = d3.scale.ordinal()
52+
var x = d3.scaleOrdinal()
5353
.domain(dataset[0].map(function(d) { return d.x; }))
5454
.rangeRoundBands([10, width-10], 0.02);
5555

56-
var y = d3.scale.linear()
56+
var y = d3.scaleLinear()
5757
.domain([0, d3.max(dataset, function(d) { return d3.max(d, function(d) { return d.y0 + d.y; }); })])
5858
.range([height, 0]);
5959

6060
var colors = colorPool.slice(0, labels.length);
6161

6262
// Define and draw axes
63-
var yAxis = d3.svg.axis()
64-
.scale(y)
65-
.orient("left")
66-
.ticks(7)
67-
.tickFormat( function(d) { return d } );
63+
var yAxis = d3.axisLeft(y).ticks(7).tickFormat( function(d) { return d } );
6864

69-
var xAxis = d3.svg.axis()
70-
.scale(x)
71-
.orient("bottom")
72-
.tickFormat(d3.time.format("%H:%M:%S.%L"));
65+
var xAxis = d3.axisBottom(x).tickFormat(d3.timeFormat("%H:%M:%S.%L"));
7366

7467
// Only show the first and last time in the graph
7568
var xline = [];
@@ -118,9 +111,9 @@ function drawAreaStack(id, labels, values, minX, maxX, minY, maxY) {
118111
.on('mouseout', function() {
119112
hideBootstrapTooltip(d3.select(this).node());
120113
})
121-
.on("mousemove", function(d) {
122-
var xPosition = d3.mouse(this)[0] - 15;
123-
var yPosition = d3.mouse(this)[1] - 25;
114+
.on("mousemove", (event, d) => {
115+
var xPosition = d3.pointer(event)[0] - 15;
116+
var yPosition = d3.pointer(event)[1] - 25;
124117
tooltip.attr("transform", "translate(" + xPosition + "," + yPosition + ")");
125118
tooltip.select("text").text(d.y);
126119
});
@@ -144,9 +137,9 @@ function drawAreaStack(id, labels, values, minX, maxX, minY, maxY) {
144137
.on('mouseout', function() {
145138
hideBootstrapTooltip(d3.select(this).node());
146139
})
147-
.on("mousemove", function(d) {
148-
var xPosition = d3.mouse(this)[0] - 15;
149-
var yPosition = d3.mouse(this)[1] - 25;
140+
.on("mousemove", (event, d) => {
141+
var xPosition = d3.pointer(event)[0] - 15;
142+
var yPosition = d3.pointer(event)[1] - 25;
150143
tooltip.attr("transform", "translate(" + xPosition + "," + yPosition + ")");
151144
tooltip.select("text").text(d.y);
152145
});
Lines changed: 13 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,13 @@
1-
Copyright (c) 2010-2015, Michael Bostock
2-
All rights reserved.
3-
4-
Redistribution and use in source and binary forms, with or without
5-
modification, are permitted provided that the following conditions are met:
6-
7-
* Redistributions of source code must retain the above copyright notice, this
8-
list of conditions and the following disclaimer.
9-
10-
* Redistributions in binary form must reproduce the above copyright notice,
11-
this list of conditions and the following disclaimer in the documentation
12-
and/or other materials provided with the distribution.
13-
14-
* The name Michael Bostock may not be used to endorse or promote products
15-
derived from this software without specific prior written permission.
16-
17-
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18-
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19-
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20-
DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT,
21-
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22-
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23-
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
24-
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25-
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26-
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1+
Copyright 2010-2023 Mike Bostock
2+
3+
Permission to use, copy, modify, and/or distribute this software for any purpose
4+
with or without fee is hereby granted, provided that the above copyright notice
5+
and this permission notice appear in all copies.
6+
7+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
8+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
9+
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
10+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
11+
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
12+
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
13+
THIS SOFTWARE.

licenses/LICENSE-d3.min.js.txt

Lines changed: 13 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,13 @@
1-
Copyright (c) 2010-2015, Michael Bostock
2-
All rights reserved.
3-
4-
Redistribution and use in source and binary forms, with or without
5-
modification, are permitted provided that the following conditions are met:
6-
7-
* Redistributions of source code must retain the above copyright notice, this
8-
list of conditions and the following disclaimer.
9-
10-
* Redistributions in binary form must reproduce the above copyright notice,
11-
this list of conditions and the following disclaimer in the documentation
12-
and/or other materials provided with the distribution.
13-
14-
* The name Michael Bostock may not be used to endorse or promote products
15-
derived from this software without specific prior written permission.
16-
17-
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18-
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19-
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20-
DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT,
21-
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22-
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23-
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
24-
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25-
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26-
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1+
Copyright 2010-2023 Mike Bostock
2+
3+
Permission to use, copy, modify, and/or distribute this software for any purpose
4+
with or without fee is hereby granted, provided that the above copyright notice
5+
and this permission notice appear in all copies.
6+
7+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
8+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
9+
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
10+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
11+
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
12+
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
13+
THIS SOFTWARE.

sql/core/src/main/resources/org/apache/spark/sql/execution/ui/static/spark-sql-viz.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ function preprocessGraphLayout(g) {
121121
* This assumes that all outermost elements are clusters (rectangles).
122122
*/
123123
function resizeSvg(svg) {
124-
var allClusters = svg.selectAll("g rect")[0];
124+
var allClusters = svg.selectAll("g rect").nodes();
125125
var startX = -PlanVizConstants.svgMarginX +
126126
toFloat(d3.min(allClusters, function(e) {
127127
return getAbsolutePosition(d3.select(e)).x;
@@ -169,7 +169,7 @@ function getAbsolutePosition(d3selection) {
169169
while (!obj.empty()) {
170170
var transformText = obj.attr("transform");
171171
if (transformText) {
172-
var translate = d3.transform(transformText).translate;
172+
var translate = transformText.substring("translate(".length, transformText.length - 1).split(",")
173173
_x += toFloat(translate[0]);
174174
_y += toFloat(translate[1]);
175175
}

0 commit comments

Comments
 (0)