如何在Palantir铸造车间创建分段累积和图?



我有一些代表维护任务的对象,它们看起来像这样:

<表类> 将在 状态 tbody><<tr>2021-12-01打开2022-06-17打开2022-07-05关闭2022-07-05关闭2022-08-01打开2023-09-02打开

您可以使用Foundry Function来实现这一点。创建一个TypeScript函数库,并使用以下代码(见内联注释以获得解释):

import { Function, Double, ThreeDimensionalAggregation, IRange, IRangeable, Timestamp, BucketKey, BucketValue } from "@foundry/functions-api";
// Replace MaintenanceJob with your object
// To make your object available, add it in the Settings > Ontology tab
import { ObjectSet, MaintenanceJob } from "@foundry/ontology-api";
export class MyFunctions {
// You will find this function in Workshop after it's published
// Replace MaintenanceJob with your object
@Function()
public async cumulativeJobsByMonthByStatus(jobs: ObjectSet<MaintenanceJob>): Promise<ThreeDimensionalAggregation<IRange<Timestamp>, string, Double>> {
const bucketedJobs = await jobs
.groupBy(j => j.dueOn.byMonth())
.segmentBy(j => j.status.topValues())
.count();
const sortedBucketedJobs = sortBuckets(bucketedJobs);
const cumulativeSortedBucketedJobs = cumulativeSum3D(sortedBucketedJobs);
return cumulativeSortedBucketedJobs
}
}
/**
* Sort buckets of a 2D or 3D aggregation by the first axis in ascending order
* 
* Example input 1:
* { buckets: [
*   { key: { min: "2022-01-01", max: "2022-12-31" }, value: 456 },
*   { key: { min: "2021-01-01", max: "2021-12-31" }, value: 123 },
*   { key: { min: "2023-01-01", max: "2023-12-31" }, value: 789 },
* ]}
* 
* Example output 1:
* { buckets: [
*   { key: { min: "2021-01-01", max: "2021-12-31" }, value: 123 },
*   { key: { min: "2022-01-01", max: "2022-12-31" }, value: 456 },
*   { key: { min: "2023-01-01", max: "2023-12-31" }, value: 789 },
* ]}
* 
* Example input 2:
* { buckets: [
*   { key: 22, value: 456 },
*   { key: 21, value: 123 },
*   { key: 23, value: 789 },
* ]}
* 
* Example output 2:
* { buckets: [
*   { key: 21, value: 123 },
*   { key: 22, value: 456 },
*   { key: 23, value: 789 },
* ]}
* 
* Example input 3:
* { buckets: [
*   { key: { min: "2022-01-01", max: "2022-12-31" }, value: [{ key: "open", value: 789 }, { key: "closed", value: 910 }] },
*   { key: { min: "2021-01-01", max: "2021-12-31" }, value: [{ key: "open", value: 123 }, { key: "closed", value: 456 }] },
*   { key: { min: "2023-01-01", max: "2023-12-31" }, value: [{ key: "open", value: 314 }, { key: "closed", value: 42 }] },
* ]}
* 
* Example output 3:
* { buckets: [
*   { key: { min: "2021-01-01", max: "2021-12-31" }, value: [{ key: "open", value: 123 }, { key: "closed", value: 456 }] },
*   { key: { min: "2022-01-01", max: "2022-12-31" }, value: [{ key: "open", value: 789 }, { key: "closed", value: 910 }] },
*   { key: { min: "2023-01-01", max: "2023-12-31" }, value: [{ key: "open", value: 314 }, { key: "closed", value: 42 }] },
* ]}
*/
function sortBuckets<K1 extends BucketKey, K2 extends BucketKey, V extends BucketValue>(buckets: ThreeDimensionalAggregation<K1, K2, V>): ThreeDimensionalAggregation<K1, K2, V>;
function sortBuckets<K extends BucketKey, V extends BucketValue>(buckets: TwoDimensionalAggregation<K, V>): TwoDimensionalAggregation<K, V>;
function sortBuckets<K extends BucketKey, V>(buckets: { buckets: { key: K, value: V}[] }): { buckets: { key: K, value: V}[] } {
return {
// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
buckets: buckets.buckets.sort(({ key: k1 }, { key: k2 }) => {
if (typeof k1 !== typeof k2) throw new Error("Inconsistent bucket key types")
// If not objects, these must be either numbers or booleans which can be compared like this
if (typeof k1 !== "object" || typeof k2 !== "object") return Number(k1) - Number(k2);
// If a bucket doesn't have a minimum, it suggests that it is the global unbounded minimum bucket, so must be lower
if (!(k1 as IRange<IRangeable>).min) return -1;
if (!(k2 as IRange<IRangeable>).min) return 1;
// Otherwise, compare both buckets' minimums
return (k1 as IRange<IRangeable>).min!.valueOf() - (k2 as IRange<IRangeable>).min!.valueOf();
}),
};
}
/**
* Calculates a cumulative sum for a ThreeDimensionalAggregation over numbers, along the first axis and segmented by the second axis
* The order of the buckets into the function matters for how the values are aggregated
* 
* Example input 1:
* { buckets: [
*   { key: { min: "2021-01-01", max: "2021-12-31" }, value: [{ key: "open", value: 123 }, { key: "closed", value: 456 }] },
*   { key: { min: "2022-01-01", max: "2022-12-31" }, value: [{ key: "open", value: 789 }, { key: "closed", value: 910 }] },
*   { key: { min: "2023-01-01", max: "2023-12-31" }, value: [{ key: "open", value: 314 }, { key: "closed", value: 42 }] },
* ]}
* 
* Example output 1:
* { buckets: [
*   { key: { min: "2021-01-01", max: "2021-12-31" }, value: [{ key: "open", value: 123 }, { key: "closed", value: 456 }] },
*   { key: { min: "2022-01-01", max: "2022-12-31" }, value: [{ key: "open", value: 912 }, { key: "closed", value: 1366 }] },
*   { key: { min: "2023-01-01", max: "2023-12-31" }, value: [{ key: "open", value: 1226 }, { key: "closed", value: 1408 }] },
* ]}
* 
* Example input 2:
* { buckets: [
*   { key: { min: "2023-01-01", max: "2023-12-31" }, value: [{ key: "open", value: 314 }, { key: "closed", value: 42 }] },
*   { key: { min: "2022-01-01", max: "2022-12-31" }, value: [{ key: "open", value: 789 }, { key: "closed", value: 910 }] },
*   { key: { min: "2021-01-01", max: "2021-12-31" }, value: [{ key: "open", value: 123 }, { key: "closed", value: 456 }] },
* ]}
* 
* Example output 2:
* { buckets: [
*   { key: { min: "2023-01-01", max: "2023-12-31" }, value: [{ key: "open", value: 314 }, { key: "closed", value: 42 }] },
*   { key: { min: "2022-01-01", max: "2022-12-31" }, value: [{ key: "open", value: 1103 }, { key: "closed", value: 952 }] },
*   { key: { min: "2021-01-01", max: "2021-12-31" }, value: [{ key: "open", value: 1226 }, { key: "closed", value: 1408 }] },
* ]}
*/
const cumulativeSum3D = <T extends BucketKey, U extends BucketKey>(buckets: ThreeDimensionalAggregation<T, U, number>): ThreeDimensionalAggregation<T, U, number> => {
// This holds the running total for each secondary axis value
// e.g. you `{ open: 123, closed: 456 }` at some point in the examples above
const cumulativeBuckets = new Map<U, number>();

return {
buckets: buckets.buckets.map(b => ({
key: b.key,
value: b.value.map(v => {
// Update the running total with the value we are seeing
cumulativeBuckets.set(v.key, (cumulativeBuckets.get(v.key) ?? 0) + v.value)
return {
key: v.key,
// Use the running total value
value: cumulativeBuckets.get(v.key)!,
}
})
}))
}
}

提交更改并发布函数版本。在Palantir Foundry文档中有一个关于如何创建存储库和发布函数的分步指南。

在你的Workshop中,你可以创建一个Chart: XY小部件。作为数据源,选择您创建的函数并传入相关对象集。在Workshop中也有关于使用派生聚合的Palantir Foundry文档。

你也可以通过在Quiver分析中创建图表,然后使用Quiver Dashboard来控制布局并将其嵌入到你的Workshop应用程序中来实现这一点。

最新更新