Public
Edited
Apr 9
3 forks
2 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
viewof selectedNodes = Inputs.table(filteredNodes, {required: false, value: filteredNodes})
Insert cell
Insert cell
Insert cell
namespaceTotal
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
nodeTotal
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
gpuTotal
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
allocatedGpus = PieChart(gpuTotal, {
name: d => d.name,
value: d => d.value,
width: 600,
height: 600
})
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
nodes = new Promise(async (resolve, reject) => {
const transport = new clientjs.HTTPTransport("https://portal.nrp-nautilus.io/rpc");
const client = new clientjs.Client(new clientjs.RequestManager([transport]));
const results = await client.request({method: 'guest.ListNodeInfo', params: []})
let nodes = {}
for (var rawDataRow of rawData) {
nodes[rawDataRow.node] = {
Name: rawDataRow.node || "Unknown",
Region: "Unknown",
Zone: "Unknown",
Taints: "Unknown",
GPUType: "Unknown",
FPGAType: "Unknown"
}
}
for (var node of results['Nodes']) {
nodes[node.Name] = {
Name: node.Name,
Region: node.Region,
Zone: node.Zone,
Taints: node.Taints?.map(t => t.key + '=' + t.value)?.join(','),
GPUType: node.GPUType || "Unknown",
FPGAType: node.FPGAType
}
}
resolve(nodes)
})
Insert cell
filteredNodes = Object.entries(nodes).map(([key, value]) => value).filter((row) =>
(new RegExp(nodeNameFilter)).test(row.Name) &&
(new RegExp(nodeRegionFilter)).test(row.Region) &&
(new RegExp(nodeZoneFilter)).test(row.Zone) &&
(new RegExp(nodeGPUFilter)).test(row.GPUType) &&
(new RegExp(nodeFPGAFilter)).test(row.FPGAType) &&
(new RegExp(nodeTaintsFilter)).test(row.Taints)
)
Insert cell
namespaceTotal = Object.entries(filteredData.reduce((acc, row) => {
let output = acc
output[row.namespace] = acc[row.namespace] || {}
output[row.namespace]['name'] = row.namespace
output[row.namespace][row.resource] = output[row.namespace][row.resource] ? output[row.namespace][row.resource] : 0
output[row.namespace][row.resource] += row.value
return output
}, {})).map(([key, namespace]) => ({
name: namespace.name,
pi: namespaces[namespace.name].PI,
institution: namespaces[namespace.name].Institution,
description: namespaces[namespace.name].Description,
cpu: namespace.cpu || 0,
gpu: namespace.gpu || 0,
fpga: namespace.fpga || 0,
memory: namespace.memory || 0,
storage: namespace.storage || 0
}))
Insert cell
nodeTotal = Object.entries(filteredData.reduce((acc, row) => {
let output = acc
output[row.node] = acc[row.node] || {}
output[row.node]['name'] = row.node
output[row.node][row.resource] = output[row.node][row.resource] ? output[row.node][row.resource] : 0
output[row.node][row.resource] += row.value
return output
}, {})).map(([key, node]) => ({
name: node.name,
cpu: node.cpu || 0,
gpu: node.gpu || 0,
fpga: node.fpga || 0,
memory: node.memory || 0,
storage: node.storage || 0,
gputype: nodes[node.name].GPUType,
fpgatype: nodes[node.name].FPGAType
}))
Insert cell
gpuTotal = Object.entries(nodeTotal.reduce((acc, row) => {
let output = acc
output[row.gputype] = acc[row.gputype] || 0
output[row.gputype] += row.gpu
return output
}, {})).map(([key, value]) => ({
name: key,
value: value
}))
Insert cell
filteredData = rawData.filter((data) => {
return selectedNamespaces.some((selectedNamespace) => selectedNamespace.Name === data.namespace)
}).filter((data) => {
return selectedNodes.some((selectedNode) => selectedNode.Name === data.node)
})
Insert cell
filteredNamespaces = Object.entries(namespaces).map(([key, value]) => value).filter((row) =>
(new RegExp(namespaceNameFilter)).test(row.Name) &&
(new RegExp(namespaceInstitutionFilter)).test(row.Institution) &&
(new RegExp(namespaceUserInstitutionFilter)).test(row.UserInstitutions)
)
Insert cell
// Copyright 2018-2023 Observable, Inc.
// Released under the ISC license.
// https://observablehq.com/@d3/pie-chart
function PieChart(data, {
name = ([x]) => x, // given d in data, returns the (ordinal) label
value = ([, y]) => y, // given d in data, returns the (quantitative) value
title, // given d in data, returns the title text
width = 600, // outer width, in pixels
height = 600, // outer height, in pixels
innerRadius = 0, // inner radius of pie, in pixels (non-zero for donut)
outerRadius = Math.min(width, height) / 2, // outer radius of pie, in pixels
labelRadius = (innerRadius * 0.2 + outerRadius * 0.8), // center radius of labels
format = ",", // a format specifier for values (in the label)
names, // array of names (the domain of the color scale)
colors, // array of colors for names
stroke = innerRadius > 0 ? "none" : "white", // stroke separating widths
strokeWidth = 1, // width of stroke separating wedges
strokeLinejoin = "round", // line join of stroke separating wedges
padAngle = stroke === "none" ? 1 / outerRadius : 0, // angular separation between wedges, in radians
} = {}) {

data.sort((a,b) => {
return parseInt(b.hours) - parseInt(a.hours);
});
// Compute values.
const N = d3.map(data, name);
const V = d3.map(data, value);
const I = d3.range(N.length).filter(i => !isNaN(V[i]));

// Unique the names.
if (names === undefined) names = N;
names = new d3.InternSet(names);

// Chose a default color scheme based on cardinality.
if (colors === undefined) colors = d3.schemeSpectral[names.size];
if (colors === undefined) colors = d3.quantize(t => d3.interpolateSpectral(t * 0.8 + 0.1), names.size);

// Construct scales.
const color = d3.scaleOrdinal(names, colors);

// Compute titles.
if (title === undefined) {
const formatValue = d3.format(format);
title = i => `${formatValue(V[i])}\n${N[i]}`;
} else {
const O = d3.map(data, d => d);
const T = title;
title = i => T(O[i], i, data);
}

// Construct arcs.
const arcs = d3.pie().padAngle(padAngle).sort(null).value(i => V[i])(I);
const arc = d3.arc().innerRadius(innerRadius).outerRadius(outerRadius);
const arcLabel = d3.arc().innerRadius(labelRadius).outerRadius(labelRadius);
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [-width / 2, -height / 2, width, height])
.attr("style", "max-width: 100%; height: auto; height: intrinsic;");

svg.append("g")
.attr("stroke", stroke)
.attr("stroke-width", strokeWidth)
.attr("stroke-linejoin", strokeLinejoin)
.selectAll("path")
.data(arcs)
.join("path")
.attr("fill", d => color(N[d.data]))
.attr("d", arc)
.append("title")
.text(d => title(d.data));

svg.append("g")
.attr("font-family", "sans-serif")
.attr("font-size", 12)
.attr("text-anchor", "middle")
.selectAll("text")
.data(arcs)
.join("text")
.attr("transform", d => `translate(${arcLabel.centroid(d)})`)
.selectAll("tspan")
.data((d, i) => {
const lines = `${title(d.data)}`.split(/\n/);
return (d.endAngle - d.startAngle) > 0.25 ? lines : lines.slice(0, 1);
})
.join("tspan")
.attr("x", 0)
.attr("y", (_, i) => `${i * 1.1}em`)
.attr("font-weight", (_, i) => i ? null : "bold")
.text(d => d);

return Object.assign(svg.node(), {scales: {color}});
}
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more