Heatmap improvements (#4897)
* allow option to normalize the color distribution * make bounds work client side (instantaneous) * make more controls instantaneous
This commit is contained in:
parent
709a71b89a
commit
3c7feb770a
|
|
@ -387,8 +387,10 @@ export const controls = {
|
|||
xscale_interval: {
|
||||
type: 'SelectControl',
|
||||
label: t('XScale Interval'),
|
||||
renderTrigger: true,
|
||||
choices: formatSelectOptionsForRange(1, 50),
|
||||
default: '1',
|
||||
clearable: false,
|
||||
description: t('Number of steps to take between ticks when ' +
|
||||
'displaying the X scale'),
|
||||
},
|
||||
|
|
@ -397,7 +399,9 @@ export const controls = {
|
|||
type: 'SelectControl',
|
||||
label: t('YScale Interval'),
|
||||
choices: formatSelectOptionsForRange(1, 50),
|
||||
default: null,
|
||||
default: '1',
|
||||
clearable: false,
|
||||
renderTrigger: true,
|
||||
description: t('Number of steps to take between ticks when ' +
|
||||
'displaying the Y scale'),
|
||||
},
|
||||
|
|
@ -726,6 +730,7 @@ export const controls = {
|
|||
|
||||
bottom_margin: {
|
||||
type: 'SelectControl',
|
||||
clearable: false,
|
||||
freeForm: true,
|
||||
label: t('Bottom Margin'),
|
||||
choices: formatSelectOptions(['auto', 50, 75, 100, 125, 150, 200]),
|
||||
|
|
@ -747,6 +752,7 @@ export const controls = {
|
|||
left_margin: {
|
||||
type: 'SelectControl',
|
||||
freeForm: true,
|
||||
clearable: false,
|
||||
label: t('Left Margin'),
|
||||
choices: formatSelectOptions(['auto', 50, 75, 100, 125, 150, 200]),
|
||||
default: 'auto',
|
||||
|
|
|
|||
|
|
@ -1488,6 +1488,7 @@ export const visTypes = {
|
|||
},
|
||||
{
|
||||
label: t('Heatmap Options'),
|
||||
expanded: true,
|
||||
controlSetRows: [
|
||||
['linear_color_scheme'],
|
||||
['xscale_interval', 'yscale_interval'],
|
||||
|
|
@ -1495,7 +1496,7 @@ export const visTypes = {
|
|||
['left_margin', 'bottom_margin'],
|
||||
['y_axis_bounds', 'y_axis_format'],
|
||||
['show_legend', 'show_perc'],
|
||||
['show_values'],
|
||||
['show_values', 'normalized'],
|
||||
['sort_x_axis', 'sort_y_axis'],
|
||||
],
|
||||
},
|
||||
|
|
@ -1507,14 +1508,13 @@ export const visTypes = {
|
|||
all_columns_y: {
|
||||
validators: [v.nonEmpty],
|
||||
},
|
||||
normalized: t('Whether to apply a normal distribution based on rank on the color scale'),
|
||||
y_axis_bounds: {
|
||||
label: t('Value bounds'),
|
||||
renderTrigger: false,
|
||||
description: (
|
||||
renderTrigger: true,
|
||||
description: t(
|
||||
'Hard value bounds applied for color coding. Is only relevant ' +
|
||||
'and applied when the normalization is applied against the whole ' +
|
||||
'heatmap.'
|
||||
),
|
||||
'and applied when the normalization is applied against the whole heatmap.'),
|
||||
},
|
||||
y_axis_format: {
|
||||
label: t('Value Format'),
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ function heatmapVis(slice, payload) {
|
|||
const height = slice.height();
|
||||
const hmWidth = width - (margin.left + margin.right);
|
||||
const hmHeight = height - (margin.bottom + margin.top);
|
||||
const fp = d3.format('.3p');
|
||||
const fp = d3.format('.2%');
|
||||
|
||||
const xScale = ordScale('x', null, fd.sort_x_axis);
|
||||
const yScale = ordScale('y', null, fd.sort_y_axis);
|
||||
|
|
@ -102,7 +102,9 @@ function heatmapVis(slice, payload) {
|
|||
const Y = 1;
|
||||
const heatmapDim = [xRbScale.domain().length, yRbScale.domain().length];
|
||||
|
||||
const color = colorScalerFactory(fd.linear_color_scheme);
|
||||
const minBound = fd.y_axis_bounds[0] || 0;
|
||||
const maxBound = fd.y_axis_bounds[1] || 1;
|
||||
const colorScaler = colorScalerFactory(fd.linear_color_scheme, null, null, [minBound, maxBound]);
|
||||
|
||||
const scale = [
|
||||
d3.scale.linear()
|
||||
|
|
@ -149,11 +151,9 @@ function heatmapVis(slice, payload) {
|
|||
}
|
||||
|
||||
if (fd.show_legend) {
|
||||
const legendScaler = colorScalerFactory(
|
||||
fd.linear_color_scheme, null, null, payload.data.extents);
|
||||
const colorLegend = d3.legend.color()
|
||||
.labelFormat(valueFormatter)
|
||||
.scale(legendScaler)
|
||||
.scale(colorScaler)
|
||||
.shapePadding(0)
|
||||
.cells(50)
|
||||
.shapeWidth(10)
|
||||
|
|
@ -183,7 +183,7 @@ function heatmapVis(slice, payload) {
|
|||
s += '<div><b>' + fd.all_columns_y + ': </b>' + obj.y + '<div>';
|
||||
s += '<div><b>' + fd.metric + ': </b>' + valueFormatter(obj.v) + '<div>';
|
||||
if (fd.show_perc) {
|
||||
s += '<div><b>%: </b>' + fp(obj.perc) + '<div>';
|
||||
s += '<div><b>%: </b>' + fp(fd.normalized ? obj.rank : obj.perc) + '<div>';
|
||||
}
|
||||
tip.style('display', null);
|
||||
} else {
|
||||
|
|
@ -246,7 +246,7 @@ function heatmapVis(slice, payload) {
|
|||
const image = context.createImageData(heatmapDim[0], heatmapDim[1]);
|
||||
const pixs = {};
|
||||
data.forEach((d) => {
|
||||
const c = d3.rgb(color(d.perc));
|
||||
const c = d3.rgb(colorScaler(fd.normalized ? d.rank : d.perc));
|
||||
const x = xScale(d.x);
|
||||
const y = yScale(d.y);
|
||||
pixs[x + (y * xScale.domain().length)] = c;
|
||||
|
|
|
|||
|
|
@ -1804,11 +1804,6 @@ class HeatmapViz(BaseViz):
|
|||
overall = False
|
||||
max_ = df.v.max()
|
||||
min_ = df.v.min()
|
||||
bounds = fd.get('y_axis_bounds')
|
||||
if bounds and bounds[0] is not None:
|
||||
min_ = bounds[0]
|
||||
if bounds and bounds[1] is not None:
|
||||
max_ = bounds[1]
|
||||
if norm == 'heatmap':
|
||||
overall = True
|
||||
else:
|
||||
|
|
@ -1820,8 +1815,10 @@ class HeatmapViz(BaseViz):
|
|||
gb.apply(
|
||||
lambda x: (x.v - x.v.min()) / (x.v.max() - x.v.min()))
|
||||
)
|
||||
df['rank'] = gb.apply(lambda x: x.v.rank(pct=True))
|
||||
if overall:
|
||||
df['perc'] = (df.v - min_) / (max_ - min_)
|
||||
df['rank'] = df.v.rank(pct=True)
|
||||
return {
|
||||
'records': df.to_dict(orient='records'),
|
||||
'extents': [min_, max_],
|
||||
|
|
|
|||
Loading…
Reference in New Issue