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

[WIP] Dataset listing #73

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,16 @@
},
"dependencies": {
"@data-exp-lab/yt-tools": "^0.3.0",
"@jupyter-widgets/base": "^1.1.10 || ^2 || ^3 || ^4",
"@jupyterlab/application": "^3.0.4",
"@jupyterlab/coreutils": "^5.0.2",
"@jupyterlab/mainmenu": "^3.0.3",
"@jupyterlab/services": "^6.0.3",
"@jupyter-widgets/base": "^1.1.10 || ^2 || ^3 || ^4",
"@lumino/coreutils": "^1.5.3",
"@types/node": "^10.11.6",
"ipycanvas": "^0.8.2"
"ipycanvas": "^0.8.2",
"raw-loader": "^4.0.2",
"react": "^17.0.1"
},
"devDependencies": {
"@jupyterlab/builder": "^3.0.0",
Expand Down
64 changes: 64 additions & 0 deletions src/colormap_container.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { WidgetModel } from '@jupyter-widgets/base';
import { ColormapCollection } from '@data-exp-lab/yt-tools';
import { MODULE_NAME, MODULE_VERSION } from './version';
const yt_tools = await import('@data-exp-lab/yt-tools');

export class ColormapContainerModel extends WidgetModel {
defaults(): any {
return {
...super.defaults(),
colormap_values: {},
_initialized: false,
_model_name: ColormapContainerModel.model_name,
_model_module: ColormapContainerModel.model_module,
_model_module_version: ColormapContainerModel.model_module_version
};
}

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
initialize(attributes: any, options: any): void {
super.initialize(attributes, options);
this.colormap_values = this.get('colormap_values');
}

async normalize(
colormap_name: string,
data_array: Float64Array,
output_array: Uint8ClampedArray,
min_val: number,
max_val: number,
take_log: boolean
): Promise<void> {
if (!this._initialized) {
await this.setupColormaps();
}
const unclamped: Uint8Array = new Uint8Array(output_array.buffer);
this.colormaps.normalize(
colormap_name,
data_array,
unclamped,
min_val,
max_val,
take_log
);
}

private async setupColormaps(): Promise<void> {
if (this._initialized) {
return;
}
this.colormaps = new yt_tools.ColormapCollection();
for (const [name, values] of Object.entries(this.colormap_values)) {
const arr_values: Uint8Array = Uint8Array.from(values);
this.colormaps.add_colormap(name, arr_values);
}
this._initialized = true;
}

colormap_values: unknown;
colormaps: ColormapCollection;
_initialized: boolean;
static model_name = 'ColormapContainerModel';
static model_module = MODULE_NAME;
static model_module_version = MODULE_VERSION;
}
156 changes: 156 additions & 0 deletions src/dataset_manager.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
// This is an attempt to implement a manager for datasets and variable meshes and the like.
// Much of it is based on what I was able to learn from @jupyterlab/running and
// @jupyterlab/running-extension.

import { Token } from '@lumino/coreutils';

import { IDisposable, DisposableDelegate } from '@lumino/disposable';

// Let's try doing this with React, shall we?
import * as React from 'react';

import { ReactWidget, ToolbarButtonComponent } from '@jupyterlab/apputils';

import { nullTranslator, ITranslator } from '@jupyterlab/translation';

import { refreshIcon } from '@jupyterlab/ui-components';

// We create a token for all the different types of datasets we want to make
// available, and then we allow each one to provide that token.

export const IYTDatasetsManager = new Token<IYTDatasetsManager>(
'@yt-project/yt-tools:YTDatasetsManager'
);

// This is the "manager" object. What it does is collect each individual
// "dataset" that is registered with widgyts. It's not obvious to me yet if this
// is too many levels of hierarchy, but it is entirely reasonable that we may
// eventually want each dataset to be an individual yt Dataset, and then have
// multiple objects living underneath it.
//
// It's worth noting that this will show up with one for each running kernel.
// That helps us get around the fact that we'll need to load them from there!
// We also probably want one for the pure Jupyterlab session, or maybe for the
// server instance itself.

export interface IYTDatasetsManager {
add(manager: IYTDatasetsManager.IManager): IDisposable;
items(): ReadonlyArray<IYTDatasetsManager.IManager>;
}

// This next part is code from @jupyterlab/extensions , and I think it does
// precisely what we need it to do.
export class YTDatasetsManager implements IYTDatasetsManager {
/**
* Add a running item manager.
*
* @param manager - The running item manager.
*
*/
add(manager: IYTDatasetsManager.IManager): IDisposable {
this._managers.push(manager);
return new DisposableDelegate(() => {
const i = this._managers.indexOf(manager);

if (i > -1) {
this._managers.splice(i, 1);
}
});
}

obtainNewManager(name: string): IYTDatasetsManager.IManager {
return {
name: name,
refreshAvailable: () => null,
available(): IYTDatasetsManager.IYTDataset[] {
return [
{
open: () => null,
close: () => null,
label: () => null
}
];
}
};
}

/**
* Return an iterator of launcher items.
*/
items(): ReadonlyArray<IYTDatasetsManager.IManager> {
return this._managers;
}

private _managers: IYTDatasetsManager.IManager[] = [];
}

export namespace IYTDatasetsManager {
export interface IManager {
name: string;
available(): IYTDataset[];
refreshAvailable(): void;
}

export interface IYTDataset {
// called when the item is clicked
open: () => void;
// when the dataset has been closed (no shutdown)
close: () => void;
// called to determine the label for each item
label: () => string;
// called to determine the `title` attribute for each item, which is revealed on hover
labelTitle?: () => string;
// called to determine the `detail` attribute which is shown optionally
// in a column after the label
detail?: () => string;
}
}

function YTDatasetComponent(props: {
managers: IYTDatasetsManager;
translator?: ITranslator;
}) {
const translator = props.translator || nullTranslator;
const trans = translator.load('jupyterlab');
return (
<>
<div className={'jp-RunningSessions-header'}>
<ToolbarButtonComponent
tooltip={trans.__('Refresh List')}
icon={refreshIcon}
onClick={() =>
props.managers
.items()
.forEach(manager => manager.refreshAvailable())
}
/>
</div>
{props.managers.items().map(manager => (
// this is where we'll have to do a bunch more...
<li>{manager.name}</li>
))}
</>
);
}

export class YTDatasets extends ReactWidget {
constructor(managers: IYTDatasetsManager, translator?: ITranslator) {
super();
this.managers = managers;
this.translator = translator || nullTranslator;

// we should add a class, probably?
this.addClass('jp-RunningSessions');
}
protected render() {
return (
<YTDatasetComponent
managers={this.managers}
translator={this.translator}
/>
);
}

private managers: IYTDatasetsManager;
protected translator: ITranslator;
}
96 changes: 96 additions & 0 deletions src/fixed_res_buffer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import {
DOMWidgetModel,
ISerializers,
unpack_models
} from '@jupyter-widgets/base';
import { FixedResolutionBuffer } from '@data-exp-lab/yt-tools';
import { MODULE_NAME, MODULE_VERSION } from './version';
import { VariableMeshModel } from './variable_mesh';
const yt_tools = await import('@data-exp-lab/yt-tools');

export interface IFRBViewBounds {
x_low: number;
x_high: number;
y_low: number;
y_high: number;
}

export class FRBModel extends DOMWidgetModel {
defaults(): any {
return {
...super.defaults(),
_model_name: FRBModel.model_name,
_model_module: FRBModel.model_module,
_model_module_version: FRBModel.model_module_version,
image_data: null,
width: 512,
height: 512,
view_center: [0.5, 0.5],
view_width: [1.0, 1.0],
frb: null,
variable_mesh_model: null
};
}

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
initialize(attributes: any, options: any): void {
super.initialize(attributes, options);
this.on_some_change(['width', 'height'], this.sizeChanged, this);
this.sizeChanged();
}

static serializers: ISerializers = {
...DOMWidgetModel.serializers,
variable_mesh_model: { deserialize: unpack_models }
};

sizeChanged(): void {
this.width = this.get('width');
this.height = this.get('height');
this.data_buffer = new Float64Array(this.width * this.height);
}

calculateViewBounds(): IFRBViewBounds {
this.view_width = this.get('view_width');
this.view_center = this.get('view_center');
const hwidths: [number, number] = [
this.view_width[0] / 2,
this.view_width[1] / 2
];
const bounds = <IFRBViewBounds>{
x_low: this.view_center[0] - hwidths[0],
x_high: this.view_center[0] + hwidths[0],
y_low: this.view_center[1] - hwidths[1],
y_high: this.view_center[1] + hwidths[1]
};
return bounds;
}

async depositDataBuffer(
variable_mesh_model: VariableMeshModel
): Promise<Float64Array> {
const bounds: IFRBViewBounds = this.calculateViewBounds();
this.frb = new yt_tools.FixedResolutionBuffer(
this.width,
this.height,
bounds.x_low,
bounds.x_high,
bounds.y_low,
bounds.y_high
);
this.frb.deposit(variable_mesh_model.variable_mesh, this.data_buffer);
return this.data_buffer;
}

frb: FixedResolutionBuffer;
variable_mesh_model: VariableMeshModel;
data_buffer: Float64Array;
width: number;
height: number;
view_center: [number, number];
view_width: [number, number];

static model_name = 'FRBModel';
static model_module = MODULE_NAME;
static model_module_version = MODULE_VERSION;
}
8 changes: 8 additions & 0 deletions src/icon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { LabIcon } from '@jupyterlab/ui-components';

import ytSvgStr from '../style/yt_logo.svg';

export const ytIcon = new LabIcon({
name: 'widgets:yticon',
svgstr: ytSvgStr
});
Loading