Skip to content

Commit

Permalink
fix regression bug around log scale colors
Browse files Browse the repository at this point in the history
  • Loading branch information
bmschmidt committed Mar 7, 2023
1 parent 9c420c1 commit 9bbe14b
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 81 deletions.
97 changes: 61 additions & 36 deletions dist/deepscatter.js
Original file line number Diff line number Diff line change
Expand Up @@ -16693,6 +16693,7 @@ void run_color_fill(in float ease) {
} else {
float fractional_color = linstep(u_color_domain, a_color);
float color_pos = (u_color_map_position * -1. - 1.) / 32. + 0.5 / 32.;
fractional_color = domainify(u_color_domain, u_color_transform, a_color, true);
fill = texture2D(u_color_aesthetic_map , vec2(color_pos, fractional_color));
fill = vec4(fill.rgb, alpha);
}
Expand All @@ -16703,6 +16704,7 @@ void run_color_fill(in float ease) {
} else {
float last_fractional = linstep(u_last_color_domain, a_last_color);
float color_pos = (u_last_color_map_position * -1. - 1.) / 32. + 0.5 / 32.;
last_fractional = domainify(u_last_color_domain, u_last_color_transform, a_last_color, true);
last_fill = texture2D(u_color_aesthetic_map, vec2(color_pos, last_fractional));
// Alpha channel interpolation already happened.
last_fill = vec4(last_fill.rgb, alpha);
Expand Down Expand Up @@ -24881,7 +24883,7 @@ class TileBufferManager {
}
}
for (const key of ["ix", "ix_in_tile", ...needed_dimensions]) {
if (!this.ready_or_not_here_it_comes(key)) {
if (!this.ready_or_not_here_it_comes(key).ready) {
return false;
}
}
Expand All @@ -24891,17 +24893,22 @@ class TileBufferManager {
const { renderer, regl_elements } = this;
const current = this.regl_elements.get(key);
if (current === null) {
return false;
return { ready: false, promise: null };
}
if (current === void 0) {
if (!this.tile.ready) {
return false;
return { ready: false, promise: null };
}
regl_elements.set(key, null);
renderer.deferred_functions.push(() => this.create_regl_buffer(key));
return false;
const created = new Promise((resolve) => {
renderer.deferred_functions.push(async () => {
await this.create_regl_buffer(key);
resolve();
});
});
return { ready: false, promise: created };
}
return true;
return { ready: true, promise: Promise.resolve() };
}
release(colname) {
let current;
Expand Down Expand Up @@ -35712,6 +35719,7 @@ class Scatterplot {
}
add_identifier_column(name, codes, key_field) {
const true_codes = Array.isArray(codes) ? Object.fromEntries(codes.map((next) => [next, 1])) : codes;
console.log({ true_codes });
this._root.add_label_identifiers(true_codes, name, key_field);
}
async add_labels_from_url(url, name, label_key, size_key, options) {
Expand Down Expand Up @@ -35937,40 +35945,57 @@ class Scatterplot {
return;
}
async start_transformations(prefs, delay = 110) {
if (this.prefs.duration < delay) {
return Promise.resolve();
}
const needed_keys = /* @__PURE__ */ new Set();
if (!prefs.encoding) {
return Promise.resolve();
}
for (const [k, v] of Object.entries(prefs.encoding)) {
if (v && typeof v !== "string" && v["field"] !== void 0) {
needed_keys.add(v["field"]);
}
}
let num_unready_columns = 0;
if (this._renderer) {
for (const tile of this._renderer.visible_tiles()) {
const manager = tile._buffer_manager;
if (manager !== void 0 && manager.ready()) {
for (const key of needed_keys) {
if (manager.ready_or_not_here_it_comes(key)) {
num_unready_columns += 1;
return new Promise((resolve) => {
if (this.prefs.duration < delay) {
delay = this.prefs.duration;
}
const needed_keys = /* @__PURE__ */ new Set();
if (!prefs.encoding) {
resolve();
}
for (const [k, v] of Object.entries(prefs.encoding)) {
if (v && typeof v !== "string" && v["field"] !== void 0) {
needed_keys.add(v["field"]);
}
}
if (this._renderer) {
const promises = [];
const sine_qua_non = [];
for (const tile of this._renderer.visible_tiles()) {
const manager = tile._buffer_manager;
if (manager !== void 0 && manager.ready()) {
for (const key of needed_keys) {
const { ready, promise } = manager.ready_or_not_here_it_comes(key);
if (!ready) {
if (promise !== null) {
promises.push(promise);
if (tile.key === "0/0/0") {
sine_qua_non.push(promise);
}
}
}
}
}
}
}
} else {
return Promise.resolve();
}
if (num_unready_columns === this._renderer.visible_tiles().length) {
return Promise.resolve();
}
return new Promise((resolve) => {
setTimeout(() => {
if (promises.length === 0) {
resolve();
} else {
const starttime = Date.now();
void Promise.all(sine_qua_non).then(() => {
const endtime = Date.now();
const elapsed = endtime - starttime;
if (elapsed < delay) {
setTimeout(() => {
resolve();
}, delay - elapsed);
} else {
resolve();
}
});
}
} else {
resolve();
}, delay);
}
});
}
async unsafe_plotAPI(prefs) {
Expand Down
96 changes: 60 additions & 36 deletions src/deepscatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,15 +148,17 @@ export default class Scatterplot<T extends Tile> {
*/
add_identifier_column(
name: string,
codes: string[] | Record<string, number>,
codes: string[] | bigint[] | Record<string, number> | Record<bigint, number>,
key_field: string
) {
const true_codes: Record<string, number> = Array.isArray(codes)
? Object.fromEntries(codes.map((next) => [next, 1]))
: codes;


console.log({true_codes})
this._root.add_label_identifiers(true_codes, name, key_field);
}

async add_labels_from_url(
url: string,
name: string,
Expand Down Expand Up @@ -534,45 +536,67 @@ export default class Scatterplot<T extends Tile> {
// is probably OK. Using the *current* transition time means that the start
// of a set of duration-0 calls (like, e.g., dragging a time slider) will
// block but that
if (this.prefs.duration < delay) {
return Promise.resolve();
}
const needed_keys : Set<string> = new Set();
if (!prefs.encoding) {
return Promise.resolve();
}
for (const [k, v] of Object.entries(prefs.encoding)) {
if (v && typeof(v) !== 'string' && v['field'] !== undefined) {
needed_keys.add(v['field']);
return new Promise(((resolve) => {
if (this.prefs.duration < delay) {
delay = this.prefs.duration;
}
}
let num_unready_columns = 0;

if (this._renderer) {
for (const tile of this._renderer.visible_tiles()) {
// Allow unready tiles to stay unready; who know's what's going on there.
const manager = tile._buffer_manager
if (manager !== undefined && manager.ready()) {
for (const key of needed_keys) {
if (manager.ready_or_not_here_it_comes(key)) {
num_unready_columns += 1;
}
}
const needed_keys : Set<string> = new Set();
if (!prefs.encoding) {
resolve()
}
for (const [k, v] of Object.entries(prefs.encoding)) {
if (v && typeof(v) !== 'string' && v['field'] !== undefined) {
needed_keys.add(v['field']);
}
}
} else {
return Promise.resolve();
}
if (num_unready_columns === this._renderer.visible_tiles().length) {
return Promise.resolve();
}
return new Promise((resolve) => {
setTimeout(() => {
// I want to use this number to determine how much longer to wait.
let num_unready_columns = 0;

if (this._renderer) {
const promises : Promise<void>[] = [];
const sine_qua_non : Promise<void>[] = [];
for (const tile of this._renderer.visible_tiles()) {
// Allow unready tiles to stay unready; who know's what's going on there.
const manager = tile._buffer_manager
if (manager !== undefined && manager.ready()) {
for (const key of needed_keys) {
const { ready, promise } = manager.ready_or_not_here_it_comes(key)
if (!ready) {
num_unready_columns += 1;
if (promise !== null) {
promises.push(promise);
if (tile.key === '0/0/0') {
// we really need this one done.
sine_qua_non.push(promise);
}
}
}
}
}
}
if (promises.length === 0) {
resolve()
} else {
const starttime = Date.now();
// It's important to get at least the first promise done,
// because it's needed to determine some details about state.
void Promise.all(sine_qua_non).then(() => {
const endtime = Date.now();
const elapsed = endtime - starttime;
if (elapsed < delay) {
setTimeout(() => {
resolve()
}, delay - elapsed);
} else {
resolve()
}
})
}
} else {
resolve()
}, delay);
});
}
}));
}

/**
* This is the main plot entry point: it's unsafe to fire multiple
* times in parallel because the transition state can get all borked up.
Expand Down
1 change: 1 addition & 0 deletions src/glsl/general.vert
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,7 @@ void run_color_fill(in float ease) {
} else {
float last_fractional = linstep(u_last_color_domain, a_last_color);
float color_pos = (u_last_color_map_position * -1. - 1.) / 32. + 0.5 / 32.;
last_fractional = domainify(u_last_color_domain, u_last_color_transform, a_last_color, true);
last_fill = texture2D(u_color_aesthetic_map, vec2(color_pos, last_fractional));
// Alpha channel interpolation already happened.
last_fill = vec4(last_fill.rgb, alpha);
Expand Down
24 changes: 15 additions & 9 deletions src/regl_rendering.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1160,7 +1160,7 @@ export class TileBufferManager<T extends Tile> {
}

for (const key of ['ix', 'ix_in_tile', ...needed_dimensions]) {
if (!this.ready_or_not_here_it_comes(key)) {
if (!this.ready_or_not_here_it_comes(key).ready) {
return false;
}
}
Expand All @@ -1172,28 +1172,34 @@ export class TileBufferManager<T extends Tile> {
*
* @param key a string representing the requested column; must either exist in the
* record batch or have a means for creating it asynchronously in 'transformations.'
* @returns true if the column is ready, false if it's not ready and a deferred call
* was created.
* @returns both an instantly available object called 'ready' that says if we're ready
* to go: and, if the tile is ready, a promise that starts the update going and resolves
* once it's ready.
*/
ready_or_not_here_it_comes(key : string) {
ready_or_not_here_it_comes(key : string) : {ready : boolean, promise: null | Promise<void>} {
const { renderer, regl_elements } = this;

const current = this.regl_elements.get(key);
if (current === null) {
// It's in the process of being built.
return false;
return {ready: false, promise: null};
}
if (current === undefined) {
if (!this.tile.ready) {
// Can't build b/c no tile ready.
return false;
return {ready: false, promise: null};
}
// Request that the buffer be created before returning false.
regl_elements.set(key, null);
renderer.deferred_functions.push(() => this.create_regl_buffer(key));
return false;
const created = new Promise<void>((resolve) => {
renderer.deferred_functions.push(async () => {
await this.create_regl_buffer(key)
resolve();
})
})
return {ready: false, promise: created};
}
return true;
return {ready: true, promise: Promise.resolve()};
}
/**
*
Expand Down

0 comments on commit 9bbe14b

Please sign in to comment.