Skip to content

Commit

Permalink
Backport PR bqplot#1397: feat: make a PNG export of the figure availa…
Browse files Browse the repository at this point in the history
…ble in the kernel
  • Loading branch information
mariobuikhuizen authored and meeseeksmachine committed Sep 30, 2021
1 parent baac16f commit 9e6ea3b
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 0 deletions.
30 changes: 30 additions & 0 deletions bqplot/figure.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,12 @@ class Figure(DOMWidget):
animation_duration = Int().tag(sync=True,
display_name='Animation duration')

def __init__(self, **kwargs):
super(Figure, self).__init__(**kwargs)

self._upload_png_callback = None
self.on_msg(self._handle_custom_msgs)

@default('scale_x')
def _default_scale_x(self):
return LinearScale(min=0, max=1, allow_padding=False)
Expand Down Expand Up @@ -185,6 +191,23 @@ def save_svg(self, filename='bqplot.svg'):
'''
self.send({"type": "save_svg", "filename": filename})

def get_png_data(self, callback, scale=None):
'''
Gets the Figure as a PNG memory view
Parameters
----------
callback: callable
Called with the PNG data as the only positional argument.
scale: float (default: None)
Scale up the png resolution when scale > 1, when not given base this on the screen pixel ratio.
'''
if self._upload_png_callback:
raise Exception('get_png_data already in progress')
self._upload_png_callback = callback
self.send({'type': 'upload_png', 'scale': scale})

@validate('min_aspect_ratio', 'max_aspect_ratio')
def _validate_aspect_ratio(self, proposal):
value = proposal['value']
Expand All @@ -196,6 +219,13 @@ def _validate_aspect_ratio(self, proposal):
raise TraitError('setting max_aspect_ratio < min_aspect_ratio')
return value

def _handle_custom_msgs(self, _, content, buffers=None):
if content.get('event') == 'upload_png':
try:
self._upload_png_callback(buffers[0])
finally:
self._upload_png_callback = None

_view_name = Unicode('Figure').tag(sync=True)
_model_name = Unicode('FigureModel').tag(sync=True)
_view_module = Unicode('bqplot').tag(sync=True)
Expand Down
15 changes: 15 additions & 0 deletions js/src/Figure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ export class Figure extends widgets.DOMWidgetView {
// TODO: remove the save png event mechanism.
this.model.on('save_png', this.save_png, this);
this.model.on('save_svg', this.save_svg, this);
this.model.on('upload_png', this.upload_png, this);

const figure_scale_promise = this.create_figure_scales();

Expand Down Expand Up @@ -1178,6 +1179,20 @@ export class Figure extends widgets.DOMWidgetView {
});
}

async upload_png(model, scale) {
const canvas = await this.get_rendered_canvas(scale);
canvas.toBlob(async (blob) => {
const buff = await blob.arrayBuffer();
model.send(
{
event: 'upload_png',
},
null,
[buff]
);
});
}

save_png(filename, scale) {
// Render a SVG data into a canvas and download as PNG.

Expand Down
2 changes: 2 additions & 0 deletions js/src/FigureModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ export class FigureModel extends widgets.DOMWidgetModel {
this.trigger('save_png', msg.filename, msg.scale);
} else if (msg.type === 'save_svg') {
this.trigger('save_svg', msg.filename);
} else if (msg.type === 'upload_png') {
this.trigger('upload_png', this, msg.scale);
}
}

Expand Down

0 comments on commit 9e6ea3b

Please # to comment.