<script src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML"></script>
<!-- MathJax configuration -->
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
tex2jax: {
inlineMath: [ ['$','$'], ["\\(","\\)"] ],
displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
processEscapes: true,
processEnvironments: true
},
// Center justify equations in code and markdown cells. Elsewhere
// we use CSS to left justify single line equations in code cells.
displayAlign: 'center',
"HTML-CSS": {
styles: {'.MathJax_Display': {"margin": 0}},
linebreaks: { automatic: true }
}
});
</script>
<!-- End of mathjax configuration --></head>
MSCI 719 - Operations Analytics - Case Study 1¶
Prepared by:
- Arif Hikmet Onat Balta - 20743281
- Daniel Wei - 20498636
- Sulaiman Olabiyi - 20690635
A. Exploratory Data Analysis¶
First, we need to import some necessary python modules and then read the csv data file.
# Import necessary modules import scipy from ggplot import * import math import numpy as np import pandas as pd import seaborn as sns import matplotlib.pyplot as plt%matplotlib notebook
# Import csv data as a pandas data frame (df)df = pd.read_csv("Case1RocketFuel.csv", sep=';')
Second, we need to analyze each variable and check if there are any data set quirks.
# 1. List variable nameslist(df)
['user_id', 'test', 'converted', 'tot_impr', 'mode_impr_day', 'mode_impr_hour']
# 2. List first few rows of data to understand moredf.head(5)
user_id | test | converted | tot_impr | mode_impr_day | mode_impr_hour | |
---|---|---|---|---|---|---|
0 | 1069124 | 1 | 0 | 130 | 1 | 20 |
1 | 1119715 | 1 | 0 | 93 | 2 | 22 |
2 | 1144181 | 1 | 0 | 21 | 2 | 18 |
3 | 1435133 | 1 | 0 | 355 | 2 | 10 |
4 | 1015700 | 1 | 0 | 276 | 5 | 14 |
# 3. Check if each row has an unique user_idcondition = len(df.user_id.unique()) == df.user_id.count() print("Does each row has an unique user_id?: %s" %condition)
Does each row has an unique user_id?: True
# 4. Check unique values of variables 'test' and 'converted'print("'test' column consists of these values: %s" %df.test.unique()) print("'converted' column consists of these values: %s" %df.converted.unique())
'test' column consists of these values: [1 0] 'converted' column consists of these values: [0 1]
# 5. Summarize last three variablesprint "Summarize 'tot_impr', 'mode_impr_day' and 'mode_impr_hour' columns: " print df[["tot_impr", "mode_impr_day", "mode_impr_hour"]].describe()
Summarize 'tot_impr', 'mode_impr_day' and 'mode_impr_hour' columns: tot_impr mode_impr_day mode_impr_hour count 588101.000000 588101.000000 588101.000000 mean 24.820876 4.025533 14.469061 std 43.715181 2.004019 4.834634 min 1.000000 1.000000 0.000000 25% 4.000000 2.000000 11.000000 50% 13.000000 4.000000 14.000000 75% 27.000000 6.000000 18.000000 max 2065.000000 7.000000 23.000000
'tot_impr' column ranges from 1 to 2065. This means some users are shown the online ad more than 2000 times.
# 6. 99% percentile for 'tot_impr'print("99%% of impressions per user is between %d and %d" % (min(df.tot_impr), df.tot_impr.quantile(0.99)))
99% of impressions per user is between 1 and 202
# 7. PLot histogram of total impressionsplt.hist(df.tot_impr, bins="auto") plt.xlabel('Total Impressions') plt.ylabel('Frequency') plt.title('Histogram of Total Impressions') plt.axis([0, 202, 0, 60000]) plt.show()
mpl.get_websocket_type = function() { if (typeof(WebSocket) !== 'undefined') { return WebSocket; } else if (typeof(MozWebSocket) !== 'undefined') { return MozWebSocket; } else { alert('Your browser does not have WebSocket support.' + 'Please try Chrome, Safari or Firefox ≥ 6. ' + 'Firefox 4 and 5 are also supported but you ' + 'have to enable WebSockets in about:config.'); }; }
mpl.figure = function(figure_id, websocket, ondownload, parent_element) { this.id = figure_id;
this.ws = websocket;
this.supports_binary = (this.ws.binaryType != undefined);
if (!this.supports_binary) {
var warnings = document.getElementById("mpl-warnings");
if (warnings) {
warnings.style.display = 'block';
warnings.textContent = (
"This browser does not support binary websocket messages. " +
"Performance may be slow.");
}
}
this.imageObj = new Image();
this.context = undefined;
this.message = undefined;
this.canvas = undefined;
this.rubberband_canvas = undefined;
this.rubberband_context = undefined;
this.format_dropdown = undefined;
this.image_mode = 'full';
this.root = $('<div/>');
this._root_extra_style(this.root)
this.root.attr('style', 'display: inline-block');
$(parent_element).append(this.root);
this._init_header(this);
this._init_canvas(this);
this._init_toolbar(this);
var fig = this;
this.waiting = false;
this.ws.onopen = function () {
fig.send_message("supports_binary", {value: fig.supports_binary});
fig.send_message("send_image_mode", {});
fig.send_message("refresh", {});
}
this.imageObj.onload = function() {
if (fig.image_mode == 'full') {
// Full images could contain transparency (where diff images
// almost always do), so we need to clear the canvas so that
// there is no ghosting.
fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);
}
fig.context.drawImage(fig.imageObj, 0, 0);
};
this.imageObj.onunload = function() {
this.ws.close();
}
this.ws.onmessage = this._make_on_message_function(this);
this.ondownload = ondownload;
}
mpl.figure.prototype._init_header = function() { var titlebar = $( '
mpl.figure.prototype._canvas_extra_style = function(canvas_div) {
}
mpl.figure.prototype._root_extra_style = function(canvas_div) {
}
mpl.figure.prototype._init_canvas = function() { var fig = this;
var canvas_div = $('<div/>');
canvas_div.attr('style', 'position: relative; clear: both; outline: 0');
function canvas_keyboard_event(event) {
return fig.key_event(event, event['data']);
}
canvas_div.keydown('key_press', canvas_keyboard_event);
canvas_div.keyup('key_release', canvas_keyboard_event);
this.canvas_div = canvas_div
this._canvas_extra_style(canvas_div)
this.root.append(canvas_div);
var canvas = $('<canvas/>');
canvas.addClass('mpl-canvas');
canvas.attr('style', "left: 0; top: 0; z-index: 0; outline: 0")
this.canvas = canvas[0];
this.context = canvas[0].getContext("2d");
var rubberband = $('<canvas/>');
rubberband.attr('style', "position: absolute; left: 0; top: 0; z-index: 1;")
var pass_mouse_events = true;
canvas_div.resizable({
start: function(event, ui) {
pass_mouse_events = false;
},
resize: function(event, ui) {
fig.request_resize(ui.size.width, ui.size.height);
},
stop: function(event, ui) {
pass_mouse_events = true;
fig.request_resize(ui.size.width, ui.size.height);
},
});
function mouse_event_fn(event) {
if (pass_mouse_events)
return fig.mouse_event(event, event['data']);
}
rubberband.mousedown('button_press', mouse_event_fn);
rubberband.mouseup('button_release', mouse_event_fn);
// Throttle sequential mouse events to 1 every 20ms.
rubberband.mousemove('motion_notify', mouse_event_fn);
rubberband.mouseenter('figure_enter', mouse_event_fn);
rubberband.mouseleave('figure_leave', mouse_event_fn);
canvas_div.on("wheel", function (event) {
event = event.originalEvent;
event['data'] = 'scroll'
if (event.deltaY < 0) {
event.step = 1;
} else {
event.step = -1;
}
mouse_event_fn(event);
});
canvas_div.append(canvas);
canvas_div.append(rubberband);
this.rubberband = rubberband;
this.rubberband_canvas = rubberband[0];
this.rubberband_context = rubberband[0].getContext("2d");
this.rubberband_context.strokeStyle = "#000000";
this._resize_canvas = function(width, height) {
// Keep the size of the canvas, canvas container, and rubber band
// canvas in synch.
canvas_div.css('width', width)
canvas_div.css('height', height)
canvas.attr('width', width);
canvas.attr('height', height);
rubberband.attr('width', width);
rubberband.attr('height', height);
}
// Set the figure to an initial 600x600px, this will subsequently be updated
// upon first draw.
this._resize_canvas(600, 600);
// Disable right mouse context menu.
$(this.rubberband_canvas).bind("contextmenu",function(e){
return false;
});
function set_focus () {
canvas.focus();
canvas_div.focus();
}
window.setTimeout(set_focus, 100);
}
mpl.figure.prototype._init_toolbar = function() { var fig = this;
var nav_element = $('<div/>')
nav_element.attr('style', 'width: 100%');
this.root.append(nav_element);
// Define a callback function for later on.
function toolbar_event(event) {
return fig.toolbar_button_onclick(event['data']);
}
function toolbar_mouse_event(event) {
return fig.toolbar_button_onmouseover(event['data']);
}
for(var toolbar_ind in mpl.toolbar_items) {
var name = mpl.toolbar_items[toolbar_ind][0];
var tooltip = mpl.toolbar_items[toolbar_ind][1];
var image = mpl.toolbar_items[toolbar_ind][2];
var method_name = mpl.toolbar_items[toolbar_ind][3];
if (!name) {
// put a spacer in here.
continue;
}
var button = $('<button/>');
button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +
'ui-button-icon-only');
button.attr('role', 'button');
button.attr('aria-disabled', 'false');
button.click(method_name, toolbar_event);
button.mouseover(tooltip, toolbar_mouse_event);
var icon_img = $('<span/>');
icon_img.addClass('ui-button-icon-primary ui-icon');
icon_img.addClass(image);
icon_img.addClass('ui-corner-all');
var tooltip_span = $('<span/>');
tooltip_span.addClass('ui-button-text');
tooltip_span.html(tooltip);
button.append(icon_img);
button.append(tooltip_span);
nav_element.append(button);
}
var fmt_picker_span = $('<span/>');
var fmt_picker = $('<select/>');
fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');
fmt_picker_span.append(fmt_picker);
nav_element.append(fmt_picker_span);
this.format_dropdown = fmt_picker[0];
for (var ind in mpl.extensions) {
var fmt = mpl.extensions[ind];
var option = $(
'<option/>', {selected: fmt === mpl.default_extension}).html(fmt);
fmt_picker.append(option)
}
// Add hover states to the ui-buttons
$( ".ui-button" ).hover(
function() { $(this).addClass("ui-state-hover");},
function() { $(this).removeClass("ui-state-hover");}
);
var status_bar = $('<span class="mpl-message"/>');
nav_element.append(status_bar);
this.message = status_bar[0];
}
mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) { // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client, // which will in turn request a refresh of the image. this.send_message('resize', {'width': x_pixels, 'height': y_pixels}); }
mpl.figure.prototype.send_message = function(type, properties) { properties['type'] = type; properties['figure_id'] = this.id; this.ws.send(JSON.stringify(properties)); }
mpl.figure.prototype.send_draw_message = function() { if (!this.waiting) { this.waiting = true; this.ws.send(JSON.stringify({type: "draw", figure_id: this.id})); } }
mpl.figure.prototype.handle_save = function(fig, msg) { var format_dropdown = fig.format_dropdown; var format = format_dropdown.options[format_dropdown.selectedIndex].value; fig.ondownload(fig, format); }
mpl.figure.prototype.handle_resize = function(fig, msg) { var size = msg['size']; if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) { fig._resize_canvas(size[0], size[1]); fig.send_message("refresh", {}); }; }
mpl.figure.prototype.handle_rubberband = function(fig, msg) { var x0 = msg['x0']; var y0 = fig.canvas.height - msg['y0']; var x1 = msg['x1']; var y1 = fig.canvas.height - msg['y1']; x0 = Math.floor(x0) + 0.5; y0 = Math.floor(y0) + 0.5; x1 = Math.floor(x1) + 0.5; y1 = Math.floor(y1) + 0.5; var min_x = Math.min(x0, x1); var min_y = Math.min(y0, y1); var width = Math.abs(x1 - x0); var height = Math.abs(y1 - y0);
fig.rubberband_context.clearRect(
0, 0, fig.canvas.width, fig.canvas.height);
fig.rubberband_context.strokeRect(min_x, min_y, width, height);
}
mpl.figure.prototype.handle_figure_label = function(fig, msg) { // Updates the figure title. fig.header.textContent = msg['label']; }
mpl.figure.prototype.handle_cursor = function(fig, msg) { var cursor = msg['cursor']; switch(cursor) { case 0: cursor = 'pointer'; break; case 1: cursor = 'default'; break; case 2: cursor = 'crosshair'; break; case 3: cursor = 'move'; break; } fig.rubberband_canvas.style.cursor = cursor; }
mpl.figure.prototype.handle_message = function(fig, msg) { fig.message.textContent = msg['message']; }
mpl.figure.prototype.handle_draw = function(fig, msg) { // Request the server to send over a new figure. fig.send_draw_message(); }
mpl.figure.prototype.handle_image_mode = function(fig, msg) { fig.image_mode = msg['mode']; }
mpl.figure.prototype.updated_canvas_event = function() { // Called whenever the canvas gets updated. this.send_message("ack", {}); }
// A function to construct a web socket function for onmessage handling. // Called in the figure constructor. mpl.figure.prototype._make_on_message_function = function(fig) { return function socket_on_message(evt) { if (evt.data instanceof Blob) { /* FIXME: We get "Resource interpreted as Image but * transferred with MIME type text/plain:" errors on * Chrome. But how to set the MIME type? It doesn't seem * to be part of the websocket stream */ evt.data.type = "image/png";
/* Free the memory for the previous frames */
if (fig.imageObj.src) {
(window.URL || window.webkitURL).revokeObjectURL(
fig.imageObj.src);
}
fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(
evt.data);
fig.updated_canvas_event();
fig.waiting = false;
return;
}
else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == "data:image/png;base64") {
fig.imageObj.src = evt.data;
fig.updated_canvas_event();
fig.waiting = false;
return;
}
var msg = JSON.parse(evt.data);
var msg_type = msg['type'];
// Call the "handle_{type}" callback, which takes
// the figure and JSON message as its only arguments.
try {
var callback = fig["handle_" + msg_type];
} catch (e) {
console.log("No handler for the '" + msg_type + "' message type: ", msg);
return;
}
if (callback) {
try {
// console.log("Handling '" + msg_type + "' message: ", msg);
callback(fig, msg);
} catch (e) {
console.log("Exception inside the 'handler_" + msg_type + "' callback:", e, e.stack, msg);
}
}
};
}
// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas mpl.findpos = function(e) { //this section is from http://www.quirksmode.org/js/events_properties.html var targ; if (!e) e = window.event; if (e.target) targ = e.target; else if (e.srcElement) targ = e.srcElement; if (targ.nodeType == 3) // defeat Safari bug targ = targ.parentNode;
// jQuery normalizes the pageX and pageY
// pageX,Y are the mouse positions relative to the document
// offset() returns the position of the element relative to the document
var x = e.pageX - $(targ).offset().left;
var y = e.pageY - $(targ).offset().top;
return {"x": x, "y": y};
};
/*
- return a copy of an object with only non-object keys
- we need this to avoid circular references
- http://stackoverflow.com/a/24161582/3208463 */ function simpleKeys (original) { return Object.keys(original).reduce(function (obj, key) { if (typeof original[key] !== 'object') obj[key] = original[key] return obj; }, {}); }
mpl.figure.prototype.mouse_event = function(event, name) { var canvas_pos = mpl.findpos(event)
if (name === 'button_press')
{
this.canvas.focus();
this.canvas_div.focus();
}
var x = canvas_pos.x;
var y = canvas_pos.y;
this.send_message(name, {x: x, y: y, button: event.button,
step: event.step,
guiEvent: simpleKeys(event)});
/* This prevents the web browser from automatically changing to
* the text insertion cursor when the button is pressed. We want
* to control all of the cursor setting manually through the
* 'cursor' event from matplotlib */
event.preventDefault();
return false;
}
mpl.figure.prototype._key_event_extra = function(event, name) { // Handle any extra behaviour associated with a key event }
mpl.figure.prototype.key_event = function(event, name) {
// Prevent repeat events
if (name == 'key_press')
{
if (event.which === this._key)
return;
else
this._key = event.which;
}
if (name == 'key_release')
this._key = null;
var value = '';
if (event.ctrlKey && event.which != 17)
value += "ctrl+";
if (event.altKey && event.which != 18)
value += "alt+";
if (event.shiftKey && event.which != 16)
value += "shift+";
value += 'k';
value += event.which.toString();
this._key_event_extra(event, name);
this.send_message(name, {key: value,
guiEvent: simpleKeys(event)});
return false;
}
mpl.figure.prototype.toolbar_button_onclick = function(name) { if (name == 'download') { this.handle_save(this, null); } else { this.send_message("toolbar_button", {name: name}); } };
mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) { this.message.textContent = tooltip; }; mpl.toolbar_items = [["Home", "Reset original view", "fa fa-home icon-home", "home"], ["Back", "Back to previous view", "fa fa-arrow-left icon-arrow-left", "back"], ["Forward", "Forward to next view", "fa fa-arrow-right icon-arrow-right", "forward"], ["", "", "", ""], ["Pan", "Pan axes with left mouse, zoom with right", "fa fa-arrows icon-move", "pan"], ["Zoom", "Zoom to rectangle", "fa fa-square-o icon-check-empty", "zoom"], ["", "", "", ""], ["Download", "Download plot", "fa fa-floppy-o icon-save", "download"]];
mpl.extensions = ["eps", "jpeg", "pdf", "png", "ps", "raw", "svg", "tif"];
mpl.default_extension = "png";var comm_websocket_adapter = function(comm) { // Create a "websocket"-like object which calls the given IPython comm // object with the appropriate methods. Currently this is a non binary // socket, so there is still some room for performance tuning. var ws = {};
ws.close = function() {
comm.close()
};
ws.send = function(m) {
//console.log('sending', m);
comm.send(m);
};
// Register the callback with on_msg.
comm.on_msg(function(msg) {
//console.log('receiving', msg['content']['data'], msg);
// Pass the mpl event to the overriden (by mpl) onmessage function.
ws.onmessage(msg['content']['data'])
});
return ws;
}
mpl.mpl_figure_comm = function(comm, msg) { // This is the function which gets called when the mpl process // starts-up an IPython Comm through the "matplotlib" channel.
var id = msg.content.data.id;
// Get hold of the div created by the display call when the Comm
// socket was opened in Python.
var element = $("#" + id);
var ws_proxy = comm_websocket_adapter(comm)
function ondownload(figure, format) {
window.open(figure.imageObj.src);
}
var fig = new mpl.figure(id, ws_proxy,
ondownload,
element.get(0));
// Call onopen now - mpl needs it, as it is assuming we've passed it a real
// web socket which is closed, not our websocket->open comm proxy.
ws_proxy.onopen();
fig.parent_element = element.get(0);
fig.cell_info = mpl.find_output_cell("<div id='" + id + "'></div>");
if (!fig.cell_info) {
console.error("Failed to find cell for figure", id, fig);
return;
}
var output_index = fig.cell_info[2]
var cell = fig.cell_info[0];
};
mpl.figure.prototype.handle_close = function(fig, msg) { fig.root.unbind('remove')
// Update the output cell to use the data from the current canvas.
fig.push_to_output();
var dataURL = fig.canvas.toDataURL();
// Re-enable the keyboard manager in IPython - without this line, in FF,
// the notebook keyboard shortcuts fail.
IPython.keyboard_manager.enable()
$(fig.parent_element).html('<img src="' + dataURL + '">');
fig.close_ws(fig, msg);
}
mpl.figure.prototype.close_ws = function(fig, msg){ fig.send_message('closing', msg); // fig.ws.close() }
mpl.figure.prototype.push_to_output = function(remove_interactive) { // Turn the data on the canvas into data in the output cell. var dataURL = this.canvas.toDataURL(); this.cell_info[1]['text/html'] = ''; }
mpl.figure.prototype.updated_canvas_event = function() { // Tell IPython that the notebook contents must change. IPython.notebook.set_dirty(true); this.send_message("ack", {}); var fig = this; // Wait a second, then push the new image to the DOM so // that it is saved nicely (might be nice to debounce this). setTimeout(function () { fig.push_to_output() }, 1000); }
mpl.figure.prototype._init_toolbar = function() { var fig = this;
var nav_element = $('<div/>')
nav_element.attr('style', 'width: 100%');
this.root.append(nav_element);
// Define a callback function for later on.
function toolbar_event(event) {
return fig.toolbar_button_onclick(event['data']);
}
function toolbar_mouse_event(event) {
return fig.toolbar_button_onmouseover(event['data']);
}
for(var toolbar_ind in mpl.toolbar_items){
var name = mpl.toolbar_items[toolbar_ind][0];
var tooltip = mpl.toolbar_items[toolbar_ind][1];
var image = mpl.toolbar_items[toolbar_ind][2];
var method_name = mpl.toolbar_items[toolbar_ind][3];
if (!name) { continue; };
var button = $('<button class="btn btn-default" href="#" title="' + name + '"><i class="fa ' + image + ' fa-lg"></i></button>');
button.click(method_name, toolbar_event);
button.mouseover(tooltip, toolbar_mouse_event);
nav_element.append(button);
}
// Add the status bar.
var status_bar = $('<span class="mpl-message" style="text-align:right; float: right;"/>');
nav_element.append(status_bar);
this.message = status_bar[0];
// Add the close button to the window.
var buttongrp = $('<div class="btn-group inline pull-right"></div>');
var button = $('<button class="btn btn-mini btn-primary" href="#" title="Stop Interaction"><i class="fa fa-power-off icon-remove icon-large"></i></button>');
button.click(function (evt) { fig.handle_close(fig, {}); } );
button.mouseover('Stop Interaction', toolbar_mouse_event);
buttongrp.append(button);
var titlebar = this.root.find($('.ui-dialog-titlebar'));
titlebar.prepend(buttongrp);
}
mpl.figure.prototype._root_extra_style = function(el){ var fig = this el.on("remove", function(){ fig.close_ws(fig, {}); }); }
mpl.figure.prototype._canvas_extra_style = function(el){ // this is important to make the div 'focusable el.attr('tabindex', 0) // reach out to IPython and tell the keyboard manager to turn it's self // off when our div gets focus
// location in version 3
if (IPython.notebook.keyboard_manager) {
IPython.notebook.keyboard_manager.register_events(el);
}
else {
// location in version 2
IPython.keyboard_manager.register_events(el);
}
}
mpl.figure.prototype._key_event_extra = function(event, name) { var manager = IPython.notebook.keyboard_manager; if (!manager) manager = IPython.keyboard_manager;
// Check for shift+enter
if (event.shiftKey && event.which == 13) {
this.canvas_div.blur();
event.shiftKey = false;
// Send a "J" for go to next cell
event.which = 74;
event.keyCode = 74;
manager.command_mode();
manager.handle_keydown(event);
}
}
mpl.figure.prototype.handle_save = function(fig, msg) { fig.ondownload(fig, null); }
mpl.find_output_cell = function(html_output) { // Return the cell and output element which can be found uniquely in the notebook. // Note - this is a bit hacky, but it is done because the "notebook_saving.Notebook" // IPython event is triggered only after the cells have been serialised, which for // our purposes (turning an active figure into a static one), is too late. var cells = IPython.notebook.get_cells(); var ncells = cells.length; for (var i=0; i<ncells; i++) { var cell = cells[i]; if (cell.cell_type === 'code'){ for (var j=0; j<cell.output_area.outputs.length; j++) { var data = cell.output_area.outputs[j]; if (data.data) { // IPython >= 3 moved mimebundle to data attribute of output data = data.data; } if (data['text/html'] == html_output) { return [cell, data, j]; } } } } }
// Register the function which deals with the matplotlib target/channel. // The kernel may be null if the page has been refreshed. if (IPython.notebook.kernel != null) { IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm); }
</script>It looks like 'tot_impr' column has a poisson distribution with a very long tail on the right.
# 8. Who saw the advertisement more? Converted or non-converted users?print("Average impression of converted users: %d" %df["tot_impr"][df["converted"]==1].mean()) print("Average impression of non-converted users: %d" %df["tot_impr"][df["converted"]==0].mean())
print("Median impression of converted users: %d" %df["tot_impr"][df["converted"]==1].median()) print("Median impression of non-converted users: %d" %df["tot_impr"][df["converted"]==0].median())
Average impression of converted users: 83 Average impression of non-converted users: 23 Median impression of converted users: 64 Median impression of non-converted users: 13
# 9. Plot histogram of impressions for converted test-group usersplt.hist(df[(df["converted"]==1) & (df["test"]==1)]["tot_impr"].values, bins=300) plt.xlabel('Total Impressions') plt.ylabel('Frequency') plt.title('Histogram of Total Impressions For Converted Test Group') plt.axis([0, 600, 0, 900]) plt.show()
mpl.get_websocket_type = function() { if (typeof(WebSocket) !== 'undefined') { return WebSocket; } else if (typeof(MozWebSocket) !== 'undefined') { return MozWebSocket; } else { alert('Your browser does not have WebSocket support.' + 'Please try Chrome, Safari or Firefox ≥ 6. ' + 'Firefox 4 and 5 are also supported but you ' + 'have to enable WebSockets in about:config.'); }; }
mpl.figure = function(figure_id, websocket, ondownload, parent_element) { this.id = figure_id;
this.ws = websocket;
this.supports_binary = (this.ws.binaryType != undefined);
if (!this.supports_binary) {
var warnings = document.getElementById("mpl-warnings");
if (warnings) {
warnings.style.display = 'block';
warnings.textContent = (
"This browser does not support binary websocket messages. " +
"Performance may be slow.");
}
}
this.imageObj = new Image();
this.context = undefined;
this.message = undefined;
this.canvas = undefined;
this.rubberband_canvas = undefined;
this.rubberband_context = undefined;
this.format_dropdown = undefined;
this.image_mode = 'full';
this.root = $('<div/>');
this._root_extra_style(this.root)
this.root.attr('style', 'display: inline-block');
$(parent_element).append(this.root);
this._init_header(this);
this._init_canvas(this);
this._init_toolbar(this);
var fig = this;
this.waiting = false;
this.ws.onopen = function () {
fig.send_message("supports_binary", {value: fig.supports_binary});
fig.send_message("send_image_mode", {});
fig.send_message("refresh", {});
}
this.imageObj.onload = function() {
if (fig.image_mode == 'full') {
// Full images could contain transparency (where diff images
// almost always do), so we need to clear the canvas so that
// there is no ghosting.
fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);
}
fig.context.drawImage(fig.imageObj, 0, 0);
};
this.imageObj.onunload = function() {
this.ws.close();
}
this.ws.onmessage = this._make_on_message_function(this);
this.ondownload = ondownload;
}
mpl.figure.prototype._init_header = function() { var titlebar = $( '
mpl.figure.prototype._canvas_extra_style = function(canvas_div) {
}
mpl.figure.prototype._root_extra_style = function(canvas_div) {
}
mpl.figure.prototype._init_canvas = function() { var fig = this;
var canvas_div = $('<div/>');
canvas_div.attr('style', 'position: relative; clear: both; outline: 0');
function canvas_keyboard_event(event) {
return fig.key_event(event, event['data']);
}
canvas_div.keydown('key_press', canvas_keyboard_event);
canvas_div.keyup('key_release', canvas_keyboard_event);
this.canvas_div = canvas_div
this._canvas_extra_style(canvas_div)
this.root.append(canvas_div);
var canvas = $('<canvas/>');
canvas.addClass('mpl-canvas');
canvas.attr('style', "left: 0; top: 0; z-index: 0; outline: 0")
this.canvas = canvas[0];
this.context = canvas[0].getContext("2d");
var rubberband = $('<canvas/>');
rubberband.attr('style', "position: absolute; left: 0; top: 0; z-index: 1;")
var pass_mouse_events = true;
canvas_div.resizable({
start: function(event, ui) {
pass_mouse_events = false;
},
resize: function(event, ui) {
fig.request_resize(ui.size.width, ui.size.height);
},
stop: function(event, ui) {
pass_mouse_events = true;
fig.request_resize(ui.size.width, ui.size.height);
},
});
function mouse_event_fn(event) {
if (pass_mouse_events)
return fig.mouse_event(event, event['data']);
}
rubberband.mousedown('button_press', mouse_event_fn);
rubberband.mouseup('button_release', mouse_event_fn);
// Throttle sequential mouse events to 1 every 20ms.
rubberband.mousemove('motion_notify', mouse_event_fn);
rubberband.mouseenter('figure_enter', mouse_event_fn);
rubberband.mouseleave('figure_leave', mouse_event_fn);
canvas_div.on("wheel", function (event) {
event = event.originalEvent;
event['data'] = 'scroll'
if (event.deltaY < 0) {
event.step = 1;
} else {
event.step = -1;
}
mouse_event_fn(event);
});
canvas_div.append(canvas);
canvas_div.append(rubberband);
this.rubberband = rubberband;
this.rubberband_canvas = rubberband[0];
this.rubberband_context = rubberband[0].getContext("2d");
this.rubberband_context.strokeStyle = "#000000";
this._resize_canvas = function(width, height) {
// Keep the size of the canvas, canvas container, and rubber band
// canvas in synch.
canvas_div.css('width', width)
canvas_div.css('height', height)
canvas.attr('width', width);
canvas.attr('height', height);
rubberband.attr('width', width);
rubberband.attr('height', height);
}
// Set the figure to an initial 600x600px, this will subsequently be updated
// upon first draw.
this._resize_canvas(600, 600);
// Disable right mouse context menu.
$(this.rubberband_canvas).bind("contextmenu",function(e){
return false;
});
function set_focus () {
canvas.focus();
canvas_div.focus();
}
window.setTimeout(set_focus, 100);
}
mpl.figure.prototype._init_toolbar = function() { var fig = this;
var nav_element = $('<div/>')
nav_element.attr('style', 'width: 100%');
this.root.append(nav_element);
// Define a callback function for later on.
function toolbar_event(event) {
return fig.toolbar_button_onclick(event['data']);
}
function toolbar_mouse_event(event) {
return fig.toolbar_button_onmouseover(event['data']);
}
for(var toolbar_ind in mpl.toolbar_items) {
var name = mpl.toolbar_items[toolbar_ind][0];
var tooltip = mpl.toolbar_items[toolbar_ind][1];
var image = mpl.toolbar_items[toolbar_ind][2];
var method_name = mpl.toolbar_items[toolbar_ind][3];
if (!name) {
// put a spacer in here.
continue;
}
var button = $('<button/>');
button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +
'ui-button-icon-only');
button.attr('role', 'button');
button.attr('aria-disabled', 'false');
button.click(method_name, toolbar_event);
button.mouseover(tooltip, toolbar_mouse_event);
var icon_img = $('<span/>');
icon_img.addClass('ui-button-icon-primary ui-icon');
icon_img.addClass(image);
icon_img.addClass('ui-corner-all');
var tooltip_span = $('<span/>');
tooltip_span.addClass('ui-button-text');
tooltip_span.html(tooltip);
button.append(icon_img);
button.append(tooltip_span);
nav_element.append(button);
}
var fmt_picker_span = $('<span/>');
var fmt_picker = $('<select/>');
fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');
fmt_picker_span.append(fmt_picker);
nav_element.append(fmt_picker_span);
this.format_dropdown = fmt_picker[0];
for (var ind in mpl.extensions) {
var fmt = mpl.extensions[ind];
var option = $(
'<option/>', {selected: fmt === mpl.default_extension}).html(fmt);
fmt_picker.append(option)
}
// Add hover states to the ui-buttons
$( ".ui-button" ).hover(
function() { $(this).addClass("ui-state-hover");},
function() { $(this).removeClass("ui-state-hover");}
);
var status_bar = $('<span class="mpl-message"/>');
nav_element.append(status_bar);
this.message = status_bar[0];
}
mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) { // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client, // which will in turn request a refresh of the image. this.send_message('resize', {'width': x_pixels, 'height': y_pixels}); }
mpl.figure.prototype.send_message = function(type, properties) { properties['type'] = type; properties['figure_id'] = this.id; this.ws.send(JSON.stringify(properties)); }
mpl.figure.prototype.send_draw_message = function() { if (!this.waiting) { this.waiting = true; this.ws.send(JSON.stringify({type: "draw", figure_id: this.id})); } }
mpl.figure.prototype.handle_save = function(fig, msg) { var format_dropdown = fig.format_dropdown; var format = format_dropdown.options[format_dropdown.selectedIndex].value; fig.ondownload(fig, format); }
mpl.figure.prototype.handle_resize = function(fig, msg) { var size = msg['size']; if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) { fig._resize_canvas(size[0], size[1]); fig.send_message("refresh", {}); }; }
mpl.figure.prototype.handle_rubberband = function(fig, msg) { var x0 = msg['x0']; var y0 = fig.canvas.height - msg['y0']; var x1 = msg['x1']; var y1 = fig.canvas.height - msg['y1']; x0 = Math.floor(x0) + 0.5; y0 = Math.floor(y0) + 0.5; x1 = Math.floor(x1) + 0.5; y1 = Math.floor(y1) + 0.5; var min_x = Math.min(x0, x1); var min_y = Math.min(y0, y1); var width = Math.abs(x1 - x0); var height = Math.abs(y1 - y0);
fig.rubberband_context.clearRect(
0, 0, fig.canvas.width, fig.canvas.height);
fig.rubberband_context.strokeRect(min_x, min_y, width, height);
}
mpl.figure.prototype.handle_figure_label = function(fig, msg) { // Updates the figure title. fig.header.textContent = msg['label']; }
mpl.figure.prototype.handle_cursor = function(fig, msg) { var cursor = msg['cursor']; switch(cursor) { case 0: cursor = 'pointer'; break; case 1: cursor = 'default'; break; case 2: cursor = 'crosshair'; break; case 3: cursor = 'move'; break; } fig.rubberband_canvas.style.cursor = cursor; }
mpl.figure.prototype.handle_message = function(fig, msg) { fig.message.textContent = msg['message']; }
mpl.figure.prototype.handle_draw = function(fig, msg) { // Request the server to send over a new figure. fig.send_draw_message(); }
mpl.figure.prototype.handle_image_mode = function(fig, msg) { fig.image_mode = msg['mode']; }
mpl.figure.prototype.updated_canvas_event = function() { // Called whenever the canvas gets updated. this.send_message("ack", {}); }
// A function to construct a web socket function for onmessage handling. // Called in the figure constructor. mpl.figure.prototype._make_on_message_function = function(fig) { return function socket_on_message(evt) { if (evt.data instanceof Blob) { /* FIXME: We get "Resource interpreted as Image but * transferred with MIME type text/plain:" errors on * Chrome. But how to set the MIME type? It doesn't seem * to be part of the websocket stream */ evt.data.type = "image/png";
/* Free the memory for the previous frames */
if (fig.imageObj.src) {
(window.URL || window.webkitURL).revokeObjectURL(
fig.imageObj.src);
}
fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(
evt.data);
fig.updated_canvas_event();
fig.waiting = false;
return;
}
else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == "data:image/png;base64") {
fig.imageObj.src = evt.data;
fig.updated_canvas_event();
fig.waiting = false;
return;
}
var msg = JSON.parse(evt.data);
var msg_type = msg['type'];
// Call the "handle_{type}" callback, which takes
// the figure and JSON message as its only arguments.
try {
var callback = fig["handle_" + msg_type];
} catch (e) {
console.log("No handler for the '" + msg_type + "' message type: ", msg);
return;
}
if (callback) {
try {
// console.log("Handling '" + msg_type + "' message: ", msg);
callback(fig, msg);
} catch (e) {
console.log("Exception inside the 'handler_" + msg_type + "' callback:", e, e.stack, msg);
}
}
};
}
// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas mpl.findpos = function(e) { //this section is from http://www.quirksmode.org/js/events_properties.html var targ; if (!e) e = window.event; if (e.target) targ = e.target; else if (e.srcElement) targ = e.srcElement; if (targ.nodeType == 3) // defeat Safari bug targ = targ.parentNode;
// jQuery normalizes the pageX and pageY
// pageX,Y are the mouse positions relative to the document
// offset() returns the position of the element relative to the document
var x = e.pageX - $(targ).offset().left;
var y = e.pageY - $(targ).offset().top;
return {"x": x, "y": y};
};
/*
- return a copy of an object with only non-object keys
- we need this to avoid circular references
- http://stackoverflow.com/a/24161582/3208463 */ function simpleKeys (original) { return Object.keys(original).reduce(function (obj, key) { if (typeof original[key] !== 'object') obj[key] = original[key] return obj; }, {}); }
mpl.figure.prototype.mouse_event = function(event, name) { var canvas_pos = mpl.findpos(event)
if (name === 'button_press')
{
this.canvas.focus();
this.canvas_div.focus();
}
var x = canvas_pos.x;
var y = canvas_pos.y;
this.send_message(name, {x: x, y: y, button: event.button,
step: event.step,
guiEvent: simpleKeys(event)});
/* This prevents the web browser from automatically changing to
* the text insertion cursor when the button is pressed. We want
* to control all of the cursor setting manually through the
* 'cursor' event from matplotlib */
event.preventDefault();
return false;
}
mpl.figure.prototype._key_event_extra = function(event, name) { // Handle any extra behaviour associated with a key event }
mpl.figure.prototype.key_event = function(event, name) {
// Prevent repeat events
if (name == 'key_press')
{
if (event.which === this._key)
return;
else
this._key = event.which;
}
if (name == 'key_release')
this._key = null;
var value = '';
if (event.ctrlKey && event.which != 17)
value += "ctrl+";
if (event.altKey && event.which != 18)
value += "alt+";
if (event.shiftKey && event.which != 16)
value += "shift+";
value += 'k';
value += event.which.toString();
this._key_event_extra(event, name);
this.send_message(name, {key: value,
guiEvent: simpleKeys(event)});
return false;
}
mpl.figure.prototype.toolbar_button_onclick = function(name) { if (name == 'download') { this.handle_save(this, null); } else { this.send_message("toolbar_button", {name: name}); } };
mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) { this.message.textContent = tooltip; }; mpl.toolbar_items = [["Home", "Reset original view", "fa fa-home icon-home", "home"], ["Back", "Back to previous view", "fa fa-arrow-left icon-arrow-left", "back"], ["Forward", "Forward to next view", "fa fa-arrow-right icon-arrow-right", "forward"], ["", "", "", ""], ["Pan", "Pan axes with left mouse, zoom with right", "fa fa-arrows icon-move", "pan"], ["Zoom", "Zoom to rectangle", "fa fa-square-o icon-check-empty", "zoom"], ["", "", "", ""], ["Download", "Download plot", "fa fa-floppy-o icon-save", "download"]];
mpl.extensions = ["eps", "jpeg", "pdf", "png", "ps", "raw", "svg", "tif"];
mpl.default_extension = "png";var comm_websocket_adapter = function(comm) { // Create a "websocket"-like object which calls the given IPython comm // object with the appropriate methods. Currently this is a non binary // socket, so there is still some room for performance tuning. var ws = {};
ws.close = function() {
comm.close()
};
ws.send = function(m) {
//console.log('sending', m);
comm.send(m);
};
// Register the callback with on_msg.
comm.on_msg(function(msg) {
//console.log('receiving', msg['content']['data'], msg);
// Pass the mpl event to the overriden (by mpl) onmessage function.
ws.onmessage(msg['content']['data'])
});
return ws;
}
mpl.mpl_figure_comm = function(comm, msg) { // This is the function which gets called when the mpl process // starts-up an IPython Comm through the "matplotlib" channel.
var id = msg.content.data.id;
// Get hold of the div created by the display call when the Comm
// socket was opened in Python.
var element = $("#" + id);
var ws_proxy = comm_websocket_adapter(comm)
function ondownload(figure, format) {
window.open(figure.imageObj.src);
}
var fig = new mpl.figure(id, ws_proxy,
ondownload,
element.get(0));
// Call onopen now - mpl needs it, as it is assuming we've passed it a real
// web socket which is closed, not our websocket->open comm proxy.
ws_proxy.onopen();
fig.parent_element = element.get(0);
fig.cell_info = mpl.find_output_cell("<div id='" + id + "'></div>");
if (!fig.cell_info) {
console.error("Failed to find cell for figure", id, fig);
return;
}
var output_index = fig.cell_info[2]
var cell = fig.cell_info[0];
};
mpl.figure.prototype.handle_close = function(fig, msg) { fig.root.unbind('remove')
// Update the output cell to use the data from the current canvas.
fig.push_to_output();
var dataURL = fig.canvas.toDataURL();
// Re-enable the keyboard manager in IPython - without this line, in FF,
// the notebook keyboard shortcuts fail.
IPython.keyboard_manager.enable()
$(fig.parent_element).html('<img src="' + dataURL + '">');
fig.close_ws(fig, msg);
}
mpl.figure.prototype.close_ws = function(fig, msg){ fig.send_message('closing', msg); // fig.ws.close() }
mpl.figure.prototype.push_to_output = function(remove_interactive) { // Turn the data on the canvas into data in the output cell. var dataURL = this.canvas.toDataURL(); this.cell_info[1]['text/html'] = ''; }
mpl.figure.prototype.updated_canvas_event = function() { // Tell IPython that the notebook contents must change. IPython.notebook.set_dirty(true); this.send_message("ack", {}); var fig = this; // Wait a second, then push the new image to the DOM so // that it is saved nicely (might be nice to debounce this). setTimeout(function () { fig.push_to_output() }, 1000); }
mpl.figure.prototype._init_toolbar = function() { var fig = this;
var nav_element = $('<div/>')
nav_element.attr('style', 'width: 100%');
this.root.append(nav_element);
// Define a callback function for later on.
function toolbar_event(event) {
return fig.toolbar_button_onclick(event['data']);
}
function toolbar_mouse_event(event) {
return fig.toolbar_button_onmouseover(event['data']);
}
for(var toolbar_ind in mpl.toolbar_items){
var name = mpl.toolbar_items[toolbar_ind][0];
var tooltip = mpl.toolbar_items[toolbar_ind][1];
var image = mpl.toolbar_items[toolbar_ind][2];
var method_name = mpl.toolbar_items[toolbar_ind][3];
if (!name) { continue; };
var button = $('<button class="btn btn-default" href="#" title="' + name + '"><i class="fa ' + image + ' fa-lg"></i></button>');
button.click(method_name, toolbar_event);
button.mouseover(tooltip, toolbar_mouse_event);
nav_element.append(button);
}
// Add the status bar.
var status_bar = $('<span class="mpl-message" style="text-align:right; float: right;"/>');
nav_element.append(status_bar);
this.message = status_bar[0];
// Add the close button to the window.
var buttongrp = $('<div class="btn-group inline pull-right"></div>');
var button = $('<button class="btn btn-mini btn-primary" href="#" title="Stop Interaction"><i class="fa fa-power-off icon-remove icon-large"></i></button>');
button.click(function (evt) { fig.handle_close(fig, {}); } );
button.mouseover('Stop Interaction', toolbar_mouse_event);
buttongrp.append(button);
var titlebar = this.root.find($('.ui-dialog-titlebar'));
titlebar.prepend(buttongrp);
}
mpl.figure.prototype._root_extra_style = function(el){ var fig = this el.on("remove", function(){ fig.close_ws(fig, {}); }); }
mpl.figure.prototype._canvas_extra_style = function(el){ // this is important to make the div 'focusable el.attr('tabindex', 0) // reach out to IPython and tell the keyboard manager to turn it's self // off when our div gets focus
// location in version 3
if (IPython.notebook.keyboard_manager) {
IPython.notebook.keyboard_manager.register_events(el);
}
else {
// location in version 2
IPython.keyboard_manager.register_events(el);
}
}
mpl.figure.prototype._key_event_extra = function(event, name) { var manager = IPython.notebook.keyboard_manager; if (!manager) manager = IPython.keyboard_manager;
// Check for shift+enter
if (event.shiftKey && event.which == 13) {
this.canvas_div.blur();
event.shiftKey = false;
// Send a "J" for go to next cell
event.which = 74;
event.keyCode = 74;
manager.command_mode();
manager.handle_keydown(event);
}
}
mpl.figure.prototype.handle_save = function(fig, msg) { fig.ondownload(fig, null); }
mpl.find_output_cell = function(html_output) { // Return the cell and output element which can be found uniquely in the notebook. // Note - this is a bit hacky, but it is done because the "notebook_saving.Notebook" // IPython event is triggered only after the cells have been serialised, which for // our purposes (turning an active figure into a static one), is too late. var cells = IPython.notebook.get_cells(); var ncells = cells.length; for (var i=0; i<ncells; i++) { var cell = cells[i]; if (cell.cell_type === 'code'){ for (var j=0; j<cell.output_area.outputs.length; j++) { var data = cell.output_area.outputs[j]; if (data.data) { // IPython >= 3 moved mimebundle to data attribute of output data = data.data; } if (data['text/html'] == html_output) { return [cell, data, j]; } } } } }
// Register the function which deals with the matplotlib target/channel. // The kernel may be null if the page has been refreshed. if (IPython.notebook.kernel != null) { IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm); }
</script>print "% 90 of converted test group users have encountered an impression less than ", \ df["tot_impr"][(df["test"]==1) & (df["converted"]==1)].quantile(0.90)print "% 80 of converted test group users have encountered an impression less than ",
df["tot_impr"][(df["test"]==1) & (df["converted"]==1)].quantile(0.80)
% 90 of converted test group users have encountered an impression less than 160.0 % 80 of converted test group users have encountered an impression less than 116.0
# 10. Plot histogram of impressions for converted control-group usersplt.hist(df[(df["converted"]==1) & (df["test"]==0)]["tot_impr"].values, bins="auto") plt.xlabel('Total Impressions') plt.ylabel('Frequency') plt.title('Histogram of Total Impressions For Converted Control Group') plt.axis([0, 600, 0, 100]) plt.show()
mpl.get_websocket_type = function() { if (typeof(WebSocket) !== 'undefined') { return WebSocket; } else if (typeof(MozWebSocket) !== 'undefined') { return MozWebSocket; } else { alert('Your browser does not have WebSocket support.' + 'Please try Chrome, Safari or Firefox ≥ 6. ' + 'Firefox 4 and 5 are also supported but you ' + 'have to enable WebSockets in about:config.'); }; }
mpl.figure = function(figure_id, websocket, ondownload, parent_element) { this.id = figure_id;
this.ws = websocket;
this.supports_binary = (this.ws.binaryType != undefined);
if (!this.supports_binary) {
var warnings = document.getElementById("mpl-warnings");
if (warnings) {
warnings.style.display = 'block';
warnings.textContent = (
"This browser does not support binary websocket messages. " +
"Performance may be slow.");
}
}
this.imageObj = new Image();
this.context = undefined;
this.message = undefined;
this.canvas = undefined;
this.rubberband_canvas = undefined;
this.rubberband_context = undefined;
this.format_dropdown = undefined;
this.image_mode = 'full';
this.root = $('<div/>');
this._root_extra_style(this.root)
this.root.attr('style', 'display: inline-block');
$(parent_element).append(this.root);
this._init_header(this);
this._init_canvas(this);
this._init_toolbar(this);
var fig = this;
this.waiting = false;
this.ws.onopen = function () {
fig.send_message("supports_binary", {value: fig.supports_binary});
fig.send_message("send_image_mode", {});
fig.send_message("refresh", {});
}
this.imageObj.onload = function() {
if (fig.image_mode == 'full') {
// Full images could contain transparency (where diff images
// almost always do), so we need to clear the canvas so that
// there is no ghosting.
fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);
}
fig.context.drawImage(fig.imageObj, 0, 0);
};
this.imageObj.onunload = function() {
this.ws.close();
}
this.ws.onmessage = this._make_on_message_function(this);
this.ondownload = ondownload;
}
mpl.figure.prototype._init_header = function() { var titlebar = $( '
mpl.figure.prototype._canvas_extra_style = function(canvas_div) {
}
mpl.figure.prototype._root_extra_style = function(canvas_div) {
}
mpl.figure.prototype._init_canvas = function() { var fig = this;
var canvas_div = $('<div/>');
canvas_div.attr('style', 'position: relative; clear: both; outline: 0');
function canvas_keyboard_event(event) {
return fig.key_event(event, event['data']);
}
canvas_div.keydown('key_press', canvas_keyboard_event);
canvas_div.keyup('key_release', canvas_keyboard_event);
this.canvas_div = canvas_div
this._canvas_extra_style(canvas_div)
this.root.append(canvas_div);
var canvas = $('<canvas/>');
canvas.addClass('mpl-canvas');
canvas.attr('style', "left: 0; top: 0; z-index: 0; outline: 0")
this.canvas = canvas[0];
this.context = canvas[0].getContext("2d");
var rubberband = $('<canvas/>');
rubberband.attr('style', "position: absolute; left: 0; top: 0; z-index: 1;")
var pass_mouse_events = true;
canvas_div.resizable({
start: function(event, ui) {
pass_mouse_events = false;
},
resize: function(event, ui) {
fig.request_resize(ui.size.width, ui.size.height);
},
stop: function(event, ui) {
pass_mouse_events = true;
fig.request_resize(ui.size.width, ui.size.height);
},
});
function mouse_event_fn(event) {
if (pass_mouse_events)
return fig.mouse_event(event, event['data']);
}
rubberband.mousedown('button_press', mouse_event_fn);
rubberband.mouseup('button_release', mouse_event_fn);
// Throttle sequential mouse events to 1 every 20ms.
rubberband.mousemove('motion_notify', mouse_event_fn);
rubberband.mouseenter('figure_enter', mouse_event_fn);
rubberband.mouseleave('figure_leave', mouse_event_fn);
canvas_div.on("wheel", function (event) {
event = event.originalEvent;
event['data'] = 'scroll'
if (event.deltaY < 0) {
event.step = 1;
} else {
event.step = -1;
}
mouse_event_fn(event);
});
canvas_div.append(canvas);
canvas_div.append(rubberband);
this.rubberband = rubberband;
this.rubberband_canvas = rubberband[0];
this.rubberband_context = rubberband[0].getContext("2d");
this.rubberband_context.strokeStyle = "#000000";
this._resize_canvas = function(width, height) {
// Keep the size of the canvas, canvas container, and rubber band
// canvas in synch.
canvas_div.css('width', width)
canvas_div.css('height', height)
canvas.attr('width', width);
canvas.attr('height', height);
rubberband.attr('width', width);
rubberband.attr('height', height);
}
// Set the figure to an initial 600x600px, this will subsequently be updated
// upon first draw.
this._resize_canvas(600, 600);
// Disable right mouse context menu.
$(this.rubberband_canvas).bind("contextmenu",function(e){
return false;
});
function set_focus () {
canvas.focus();
canvas_div.focus();
}
window.setTimeout(set_focus, 100);
}
mpl.figure.prototype._init_toolbar = function() { var fig = this;
var nav_element = $('<div/>')
nav_element.attr('style', 'width: 100%');
this.root.append(nav_element);
// Define a callback function for later on.
function toolbar_event(event) {
return fig.toolbar_button_onclick(event['data']);
}
function toolbar_mouse_event(event) {
return fig.toolbar_button_onmouseover(event['data']);
}
for(var toolbar_ind in mpl.toolbar_items) {
var name = mpl.toolbar_items[toolbar_ind][0];
var tooltip = mpl.toolbar_items[toolbar_ind][1];
var image = mpl.toolbar_items[toolbar_ind][2];
var method_name = mpl.toolbar_items[toolbar_ind][3];
if (!name) {
// put a spacer in here.
continue;
}
var button = $('<button/>');
button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +
'ui-button-icon-only');
button.attr('role', 'button');
button.attr('aria-disabled', 'false');
button.click(method_name, toolbar_event);
button.mouseover(tooltip, toolbar_mouse_event);
var icon_img = $('<span/>');
icon_img.addClass('ui-button-icon-primary ui-icon');
icon_img.addClass(image);
icon_img.addClass('ui-corner-all');
var tooltip_span = $('<span/>');
tooltip_span.addClass('ui-button-text');
tooltip_span.html(tooltip);
button.append(icon_img);
button.append(tooltip_span);
nav_element.append(button);
}
var fmt_picker_span = $('<span/>');
var fmt_picker = $('<select/>');
fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');
fmt_picker_span.append(fmt_picker);
nav_element.append(fmt_picker_span);
this.format_dropdown = fmt_picker[0];
for (var ind in mpl.extensions) {
var fmt = mpl.extensions[ind];
var option = $(
'<option/>', {selected: fmt === mpl.default_extension}).html(fmt);
fmt_picker.append(option)
}
// Add hover states to the ui-buttons
$( ".ui-button" ).hover(
function() { $(this).addClass("ui-state-hover");},
function() { $(this).removeClass("ui-state-hover");}
);
var status_bar = $('<span class="mpl-message"/>');
nav_element.append(status_bar);
this.message = status_bar[0];
}
mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) { // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client, // which will in turn request a refresh of the image. this.send_message('resize', {'width': x_pixels, 'height': y_pixels}); }
mpl.figure.prototype.send_message = function(type, properties) { properties['type'] = type; properties['figure_id'] = this.id; this.ws.send(JSON.stringify(properties)); }
mpl.figure.prototype.send_draw_message = function() { if (!this.waiting) { this.waiting = true; this.ws.send(JSON.stringify({type: "draw", figure_id: this.id})); } }
mpl.figure.prototype.handle_save = function(fig, msg) { var format_dropdown = fig.format_dropdown; var format = format_dropdown.options[format_dropdown.selectedIndex].value; fig.ondownload(fig, format); }
mpl.figure.prototype.handle_resize = function(fig, msg) { var size = msg['size']; if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) { fig._resize_canvas(size[0], size[1]); fig.send_message("refresh", {}); }; }
mpl.figure.prototype.handle_rubberband = function(fig, msg) { var x0 = msg['x0']; var y0 = fig.canvas.height - msg['y0']; var x1 = msg['x1']; var y1 = fig.canvas.height - msg['y1']; x0 = Math.floor(x0) + 0.5; y0 = Math.floor(y0) + 0.5; x1 = Math.floor(x1) + 0.5; y1 = Math.floor(y1) + 0.5; var min_x = Math.min(x0, x1); var min_y = Math.min(y0, y1); var width = Math.abs(x1 - x0); var height = Math.abs(y1 - y0);
fig.rubberband_context.clearRect(
0, 0, fig.canvas.width, fig.canvas.height);
fig.rubberband_context.strokeRect(min_x, min_y, width, height);
}
mpl.figure.prototype.handle_figure_label = function(fig, msg) { // Updates the figure title. fig.header.textContent = msg['label']; }
mpl.figure.prototype.handle_cursor = function(fig, msg) { var cursor = msg['cursor']; switch(cursor) { case 0: cursor = 'pointer'; break; case 1: cursor = 'default'; break; case 2: cursor = 'crosshair'; break; case 3: cursor = 'move'; break; } fig.rubberband_canvas.style.cursor = cursor; }
mpl.figure.prototype.handle_message = function(fig, msg) { fig.message.textContent = msg['message']; }
mpl.figure.prototype.handle_draw = function(fig, msg) { // Request the server to send over a new figure. fig.send_draw_message(); }
mpl.figure.prototype.handle_image_mode = function(fig, msg) { fig.image_mode = msg['mode']; }
mpl.figure.prototype.updated_canvas_event = function() { // Called whenever the canvas gets updated. this.send_message("ack", {}); }
// A function to construct a web socket function for onmessage handling. // Called in the figure constructor. mpl.figure.prototype._make_on_message_function = function(fig) { return function socket_on_message(evt) { if (evt.data instanceof Blob) { /* FIXME: We get "Resource interpreted as Image but * transferred with MIME type text/plain:" errors on * Chrome. But how to set the MIME type? It doesn't seem * to be part of the websocket stream */ evt.data.type = "image/png";
/* Free the memory for the previous frames */
if (fig.imageObj.src) {
(window.URL || window.webkitURL).revokeObjectURL(
fig.imageObj.src);
}
fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(
evt.data);
fig.updated_canvas_event();
fig.waiting = false;
return;
}
else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == "data:image/png;base64") {
fig.imageObj.src = evt.data;
fig.updated_canvas_event();
fig.waiting = false;
return;
}
var msg = JSON.parse(evt.data);
var msg_type = msg['type'];
// Call the "handle_{type}" callback, which takes
// the figure and JSON message as its only arguments.
try {
var callback = fig["handle_" + msg_type];
} catch (e) {
console.log("No handler for the '" + msg_type + "' message type: ", msg);
return;
}
if (callback) {
try {
// console.log("Handling '" + msg_type + "' message: ", msg);
callback(fig, msg);
} catch (e) {
console.log("Exception inside the 'handler_" + msg_type + "' callback:", e, e.stack, msg);
}
}
};
}
// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas mpl.findpos = function(e) { //this section is from http://www.quirksmode.org/js/events_properties.html var targ; if (!e) e = window.event; if (e.target) targ = e.target; else if (e.srcElement) targ = e.srcElement; if (targ.nodeType == 3) // defeat Safari bug targ = targ.parentNode;
// jQuery normalizes the pageX and pageY
// pageX,Y are the mouse positions relative to the document
// offset() returns the position of the element relative to the document
var x = e.pageX - $(targ).offset().left;
var y = e.pageY - $(targ).offset().top;
return {"x": x, "y": y};
};
/*
- return a copy of an object with only non-object keys
- we need this to avoid circular references
- http://stackoverflow.com/a/24161582/3208463 */ function simpleKeys (original) { return Object.keys(original).reduce(function (obj, key) { if (typeof original[key] !== 'object') obj[key] = original[key] return obj; }, {}); }
mpl.figure.prototype.mouse_event = function(event, name) { var canvas_pos = mpl.findpos(event)
if (name === 'button_press')
{
this.canvas.focus();
this.canvas_div.focus();
}
var x = canvas_pos.x;
var y = canvas_pos.y;
this.send_message(name, {x: x, y: y, button: event.button,
step: event.step,
guiEvent: simpleKeys(event)});
/* This prevents the web browser from automatically changing to
* the text insertion cursor when the button is pressed. We want
* to control all of the cursor setting manually through the
* 'cursor' event from matplotlib */
event.preventDefault();
return false;
}
mpl.figure.prototype._key_event_extra = function(event, name) { // Handle any extra behaviour associated with a key event }
mpl.figure.prototype.key_event = function(event, name) {
// Prevent repeat events
if (name == 'key_press')
{
if (event.which === this._key)
return;
else
this._key = event.which;
}
if (name == 'key_release')
this._key = null;
var value = '';
if (event.ctrlKey && event.which != 17)
value += "ctrl+";
if (event.altKey && event.which != 18)
value += "alt+";
if (event.shiftKey && event.which != 16)
value += "shift+";
value += 'k';
value += event.which.toString();
this._key_event_extra(event, name);
this.send_message(name, {key: value,
guiEvent: simpleKeys(event)});
return false;
}
mpl.figure.prototype.toolbar_button_onclick = function(name) { if (name == 'download') { this.handle_save(this, null); } else { this.send_message("toolbar_button", {name: name}); } };
mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) { this.message.textContent = tooltip; }; mpl.toolbar_items = [["Home", "Reset original view", "fa fa-home icon-home", "home"], ["Back", "Back to previous view", "fa fa-arrow-left icon-arrow-left", "back"], ["Forward", "Forward to next view", "fa fa-arrow-right icon-arrow-right", "forward"], ["", "", "", ""], ["Pan", "Pan axes with left mouse, zoom with right", "fa fa-arrows icon-move", "pan"], ["Zoom", "Zoom to rectangle", "fa fa-square-o icon-check-empty", "zoom"], ["", "", "", ""], ["Download", "Download plot", "fa fa-floppy-o icon-save", "download"]];
mpl.extensions = ["eps", "jpeg", "pdf", "png", "ps", "raw", "svg", "tif"];
mpl.default_extension = "png";var comm_websocket_adapter = function(comm) { // Create a "websocket"-like object which calls the given IPython comm // object with the appropriate methods. Currently this is a non binary // socket, so there is still some room for performance tuning. var ws = {};
ws.close = function() {
comm.close()
};
ws.send = function(m) {
//console.log('sending', m);
comm.send(m);
};
// Register the callback with on_msg.
comm.on_msg(function(msg) {
//console.log('receiving', msg['content']['data'], msg);
// Pass the mpl event to the overriden (by mpl) onmessage function.
ws.onmessage(msg['content']['data'])
});
return ws;
}
mpl.mpl_figure_comm = function(comm, msg) { // This is the function which gets called when the mpl process // starts-up an IPython Comm through the "matplotlib" channel.
var id = msg.content.data.id;
// Get hold of the div created by the display call when the Comm
// socket was opened in Python.
var element = $("#" + id);
var ws_proxy = comm_websocket_adapter(comm)
function ondownload(figure, format) {
window.open(figure.imageObj.src);
}
var fig = new mpl.figure(id, ws_proxy,
ondownload,
element.get(0));
// Call onopen now - mpl needs it, as it is assuming we've passed it a real
// web socket which is closed, not our websocket->open comm proxy.
ws_proxy.onopen();
fig.parent_element = element.get(0);
fig.cell_info = mpl.find_output_cell("<div id='" + id + "'></div>");
if (!fig.cell_info) {
console.error("Failed to find cell for figure", id, fig);
return;
}
var output_index = fig.cell_info[2]
var cell = fig.cell_info[0];
};
mpl.figure.prototype.handle_close = function(fig, msg) { fig.root.unbind('remove')
// Update the output cell to use the data from the current canvas.
fig.push_to_output();
var dataURL = fig.canvas.toDataURL();
// Re-enable the keyboard manager in IPython - without this line, in FF,
// the notebook keyboard shortcuts fail.
IPython.keyboard_manager.enable()
$(fig.parent_element).html('<img src="' + dataURL + '">');
fig.close_ws(fig, msg);
}
mpl.figure.prototype.close_ws = function(fig, msg){ fig.send_message('closing', msg); // fig.ws.close() }
mpl.figure.prototype.push_to_output = function(remove_interactive) { // Turn the data on the canvas into data in the output cell. var dataURL = this.canvas.toDataURL(); this.cell_info[1]['text/html'] = ''; }
mpl.figure.prototype.updated_canvas_event = function() { // Tell IPython that the notebook contents must change. IPython.notebook.set_dirty(true); this.send_message("ack", {}); var fig = this; // Wait a second, then push the new image to the DOM so // that it is saved nicely (might be nice to debounce this). setTimeout(function () { fig.push_to_output() }, 1000); }
mpl.figure.prototype._init_toolbar = function() { var fig = this;
var nav_element = $('<div/>')
nav_element.attr('style', 'width: 100%');
this.root.append(nav_element);
// Define a callback function for later on.
function toolbar_event(event) {
return fig.toolbar_button_onclick(event['data']);
}
function toolbar_mouse_event(event) {
return fig.toolbar_button_onmouseover(event['data']);
}
for(var toolbar_ind in mpl.toolbar_items){
var name = mpl.toolbar_items[toolbar_ind][0];
var tooltip = mpl.toolbar_items[toolbar_ind][1];
var image = mpl.toolbar_items[toolbar_ind][2];
var method_name = mpl.toolbar_items[toolbar_ind][3];
if (!name) { continue; };
var button = $('<button class="btn btn-default" href="#" title="' + name + '"><i class="fa ' + image + ' fa-lg"></i></button>');
button.click(method_name, toolbar_event);
button.mouseover(tooltip, toolbar_mouse_event);
nav_element.append(button);
}
// Add the status bar.
var status_bar = $('<span class="mpl-message" style="text-align:right; float: right;"/>');
nav_element.append(status_bar);
this.message = status_bar[0];
// Add the close button to the window.
var buttongrp = $('<div class="btn-group inline pull-right"></div>');
var button = $('<button class="btn btn-mini btn-primary" href="#" title="Stop Interaction"><i class="fa fa-power-off icon-remove icon-large"></i></button>');
button.click(function (evt) { fig.handle_close(fig, {}); } );
button.mouseover('Stop Interaction', toolbar_mouse_event);
buttongrp.append(button);
var titlebar = this.root.find($('.ui-dialog-titlebar'));
titlebar.prepend(buttongrp);
}
mpl.figure.prototype._root_extra_style = function(el){ var fig = this el.on("remove", function(){ fig.close_ws(fig, {}); }); }
mpl.figure.prototype._canvas_extra_style = function(el){ // this is important to make the div 'focusable el.attr('tabindex', 0) // reach out to IPython and tell the keyboard manager to turn it's self // off when our div gets focus
// location in version 3
if (IPython.notebook.keyboard_manager) {
IPython.notebook.keyboard_manager.register_events(el);
}
else {
// location in version 2
IPython.keyboard_manager.register_events(el);
}
}
mpl.figure.prototype._key_event_extra = function(event, name) { var manager = IPython.notebook.keyboard_manager; if (!manager) manager = IPython.keyboard_manager;
// Check for shift+enter
if (event.shiftKey && event.which == 13) {
this.canvas_div.blur();
event.shiftKey = false;
// Send a "J" for go to next cell
event.which = 74;
event.keyCode = 74;
manager.command_mode();
manager.handle_keydown(event);
}
}
mpl.figure.prototype.handle_save = function(fig, msg) { fig.ondownload(fig, null); }
mpl.find_output_cell = function(html_output) { // Return the cell and output element which can be found uniquely in the notebook. // Note - this is a bit hacky, but it is done because the "notebook_saving.Notebook" // IPython event is triggered only after the cells have been serialised, which for // our purposes (turning an active figure into a static one), is too late. var cells = IPython.notebook.get_cells(); var ncells = cells.length; for (var i=0; i<ncells; i++) { var cell = cells[i]; if (cell.cell_type === 'code'){ for (var j=0; j<cell.output_area.outputs.length; j++) { var data = cell.output_area.outputs[j]; if (data.data) { // IPython >= 3 moved mimebundle to data attribute of output data = data.data; } if (data['text/html'] == html_output) { return [cell, data, j]; } } } } }
// Register the function which deals with the matplotlib target/channel. // The kernel may be null if the page has been refreshed. if (IPython.notebook.kernel != null) { IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm); }
</script>print "% 90 of converted control group users have encountered an impression less than ", \ df["tot_impr"][(df["test"]==1) & (df["converted"]==0)].quantile(0.90)print "% 80 of converted control group users have encountered an impression less than ",
df["tot_impr"][(df["test"]==1) & (df["converted"]==0)].quantile(0.80)
% 90 of converted control group users have encountered an impression less than 52.0 % 80 of converted control group users have encountered an impression less than 31.0
# 11. Bar plot of impressions vs. day of weekggplot(aes(x='mode_impr_day'), data=df) +
xlab("Days") + ylab("Impressions") + ggtitle("Impressions Vs. Day of Week") + geom_bar()
mpl.get_websocket_type = function() { if (typeof(WebSocket) !== 'undefined') { return WebSocket; } else if (typeof(MozWebSocket) !== 'undefined') { return MozWebSocket; } else { alert('Your browser does not have WebSocket support.' + 'Please try Chrome, Safari or Firefox ≥ 6. ' + 'Firefox 4 and 5 are also supported but you ' + 'have to enable WebSockets in about:config.'); }; }
mpl.figure = function(figure_id, websocket, ondownload, parent_element) { this.id = figure_id;
this.ws = websocket;
this.supports_binary = (this.ws.binaryType != undefined);
if (!this.supports_binary) {
var warnings = document.getElementById("mpl-warnings");
if (warnings) {
warnings.style.display = 'block';
warnings.textContent = (
"This browser does not support binary websocket messages. " +
"Performance may be slow.");
}
}
this.imageObj = new Image();
this.context = undefined;
this.message = undefined;
this.canvas = undefined;
this.rubberband_canvas = undefined;
this.rubberband_context = undefined;
this.format_dropdown = undefined;
this.image_mode = 'full';
this.root = $('<div/>');
this._root_extra_style(this.root)
this.root.attr('style', 'display: inline-block');
$(parent_element).append(this.root);
this._init_header(this);
this._init_canvas(this);
this._init_toolbar(this);
var fig = this;
this.waiting = false;
this.ws.onopen = function () {
fig.send_message("supports_binary", {value: fig.supports_binary});
fig.send_message("send_image_mode", {});
fig.send_message("refresh", {});
}
this.imageObj.onload = function() {
if (fig.image_mode == 'full') {
// Full images could contain transparency (where diff images
// almost always do), so we need to clear the canvas so that
// there is no ghosting.
fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);
}
fig.context.drawImage(fig.imageObj, 0, 0);
};
this.imageObj.onunload = function() {
this.ws.close();
}
this.ws.onmessage = this._make_on_message_function(this);
this.ondownload = ondownload;
}
mpl.figure.prototype._init_header = function() { var titlebar = $( '
mpl.figure.prototype._canvas_extra_style = function(canvas_div) {
}
mpl.figure.prototype._root_extra_style = function(canvas_div) {
}
mpl.figure.prototype._init_canvas = function() { var fig = this;
var canvas_div = $('<div/>');
canvas_div.attr('style', 'position: relative; clear: both; outline: 0');
function canvas_keyboard_event(event) {
return fig.key_event(event, event['data']);
}
canvas_div.keydown('key_press', canvas_keyboard_event);
canvas_div.keyup('key_release', canvas_keyboard_event);
this.canvas_div = canvas_div
this._canvas_extra_style(canvas_div)
this.root.append(canvas_div);
var canvas = $('<canvas/>');
canvas.addClass('mpl-canvas');
canvas.attr('style', "left: 0; top: 0; z-index: 0; outline: 0")
this.canvas = canvas[0];
this.context = canvas[0].getContext("2d");
var rubberband = $('<canvas/>');
rubberband.attr('style', "position: absolute; left: 0; top: 0; z-index: 1;")
var pass_mouse_events = true;
canvas_div.resizable({
start: function(event, ui) {
pass_mouse_events = false;
},
resize: function(event, ui) {
fig.request_resize(ui.size.width, ui.size.height);
},
stop: function(event, ui) {
pass_mouse_events = true;
fig.request_resize(ui.size.width, ui.size.height);
},
});
function mouse_event_fn(event) {
if (pass_mouse_events)
return fig.mouse_event(event, event['data']);
}
rubberband.mousedown('button_press', mouse_event_fn);
rubberband.mouseup('button_release', mouse_event_fn);
// Throttle sequential mouse events to 1 every 20ms.
rubberband.mousemove('motion_notify', mouse_event_fn);
rubberband.mouseenter('figure_enter', mouse_event_fn);
rubberband.mouseleave('figure_leave', mouse_event_fn);
canvas_div.on("wheel", function (event) {
event = event.originalEvent;
event['data'] = 'scroll'
if (event.deltaY < 0) {
event.step = 1;
} else {
event.step = -1;
}
mouse_event_fn(event);
});
canvas_div.append(canvas);
canvas_div.append(rubberband);
this.rubberband = rubberband;
this.rubberband_canvas = rubberband[0];
this.rubberband_context = rubberband[0].getContext("2d");
this.rubberband_context.strokeStyle = "#000000";
this._resize_canvas = function(width, height) {
// Keep the size of the canvas, canvas container, and rubber band
// canvas in synch.
canvas_div.css('width', width)
canvas_div.css('height', height)
canvas.attr('width', width);
canvas.attr('height', height);
rubberband.attr('width', width);
rubberband.attr('height', height);
}
// Set the figure to an initial 600x600px, this will subsequently be updated
// upon first draw.
this._resize_canvas(600, 600);
// Disable right mouse context menu.
$(this.rubberband_canvas).bind("contextmenu",function(e){
return false;
});
function set_focus () {
canvas.focus();
canvas_div.focus();
}
window.setTimeout(set_focus, 100);
}
mpl.figure.prototype._init_toolbar = function() { var fig = this;
var nav_element = $('<div/>')
nav_element.attr('style', 'width: 100%');
this.root.append(nav_element);
// Define a callback function for later on.
function toolbar_event(event) {
return fig.toolbar_button_onclick(event['data']);
}
function toolbar_mouse_event(event) {
return fig.toolbar_button_onmouseover(event['data']);
}
for(var toolbar_ind in mpl.toolbar_items) {
var name = mpl.toolbar_items[toolbar_ind][0];
var tooltip = mpl.toolbar_items[toolbar_ind][1];
var image = mpl.toolbar_items[toolbar_ind][2];
var method_name = mpl.toolbar_items[toolbar_ind][3];
if (!name) {
// put a spacer in here.
continue;
}
var button = $('<button/>');
button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +
'ui-button-icon-only');
button.attr('role', 'button');
button.attr('aria-disabled', 'false');
button.click(method_name, toolbar_event);
button.mouseover(tooltip, toolbar_mouse_event);
var icon_img = $('<span/>');
icon_img.addClass('ui-button-icon-primary ui-icon');
icon_img.addClass(image);
icon_img.addClass('ui-corner-all');
var tooltip_span = $('<span/>');
tooltip_span.addClass('ui-button-text');
tooltip_span.html(tooltip);
button.append(icon_img);
button.append(tooltip_span);
nav_element.append(button);
}
var fmt_picker_span = $('<span/>');
var fmt_picker = $('<select/>');
fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');
fmt_picker_span.append(fmt_picker);
nav_element.append(fmt_picker_span);
this.format_dropdown = fmt_picker[0];
for (var ind in mpl.extensions) {
var fmt = mpl.extensions[ind];
var option = $(
'<option/>', {selected: fmt === mpl.default_extension}).html(fmt);
fmt_picker.append(option)
}
// Add hover states to the ui-buttons
$( ".ui-button" ).hover(
function() { $(this).addClass("ui-state-hover");},
function() { $(this).removeClass("ui-state-hover");}
);
var status_bar = $('<span class="mpl-message"/>');
nav_element.append(status_bar);
this.message = status_bar[0];
}
mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) { // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client, // which will in turn request a refresh of the image. this.send_message('resize', {'width': x_pixels, 'height': y_pixels}); }
mpl.figure.prototype.send_message = function(type, properties) { properties['type'] = type; properties['figure_id'] = this.id; this.ws.send(JSON.stringify(properties)); }
mpl.figure.prototype.send_draw_message = function() { if (!this.waiting) { this.waiting = true; this.ws.send(JSON.stringify({type: "draw", figure_id: this.id})); } }
mpl.figure.prototype.handle_save = function(fig, msg) { var format_dropdown = fig.format_dropdown; var format = format_dropdown.options[format_dropdown.selectedIndex].value; fig.ondownload(fig, format); }
mpl.figure.prototype.handle_resize = function(fig, msg) { var size = msg['size']; if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) { fig._resize_canvas(size[0], size[1]); fig.send_message("refresh", {}); }; }
mpl.figure.prototype.handle_rubberband = function(fig, msg) { var x0 = msg['x0']; var y0 = fig.canvas.height - msg['y0']; var x1 = msg['x1']; var y1 = fig.canvas.height - msg['y1']; x0 = Math.floor(x0) + 0.5; y0 = Math.floor(y0) + 0.5; x1 = Math.floor(x1) + 0.5; y1 = Math.floor(y1) + 0.5; var min_x = Math.min(x0, x1); var min_y = Math.min(y0, y1); var width = Math.abs(x1 - x0); var height = Math.abs(y1 - y0);
fig.rubberband_context.clearRect(
0, 0, fig.canvas.width, fig.canvas.height);
fig.rubberband_context.strokeRect(min_x, min_y, width, height);
}
mpl.figure.prototype.handle_figure_label = function(fig, msg) { // Updates the figure title. fig.header.textContent = msg['label']; }
mpl.figure.prototype.handle_cursor = function(fig, msg) { var cursor = msg['cursor']; switch(cursor) { case 0: cursor = 'pointer'; break; case 1: cursor = 'default'; break; case 2: cursor = 'crosshair'; break; case 3: cursor = 'move'; break; } fig.rubberband_canvas.style.cursor = cursor; }
mpl.figure.prototype.handle_message = function(fig, msg) { fig.message.textContent = msg['message']; }
mpl.figure.prototype.handle_draw = function(fig, msg) { // Request the server to send over a new figure. fig.send_draw_message(); }
mpl.figure.prototype.handle_image_mode = function(fig, msg) { fig.image_mode = msg['mode']; }
mpl.figure.prototype.updated_canvas_event = function() { // Called whenever the canvas gets updated. this.send_message("ack", {}); }
// A function to construct a web socket function for onmessage handling. // Called in the figure constructor. mpl.figure.prototype._make_on_message_function = function(fig) { return function socket_on_message(evt) { if (evt.data instanceof Blob) { /* FIXME: We get "Resource interpreted as Image but * transferred with MIME type text/plain:" errors on * Chrome. But how to set the MIME type? It doesn't seem * to be part of the websocket stream */ evt.data.type = "image/png";
/* Free the memory for the previous frames */
if (fig.imageObj.src) {
(window.URL || window.webkitURL).revokeObjectURL(
fig.imageObj.src);
}
fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(
evt.data);
fig.updated_canvas_event();
fig.waiting = false;
return;
}
else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == "data:image/png;base64") {
fig.imageObj.src = evt.data;
fig.updated_canvas_event();
fig.waiting = false;
return;
}
var msg = JSON.parse(evt.data);
var msg_type = msg['type'];
// Call the "handle_{type}" callback, which takes
// the figure and JSON message as its only arguments.
try {
var callback = fig["handle_" + msg_type];
} catch (e) {
console.log("No handler for the '" + msg_type + "' message type: ", msg);
return;
}
if (callback) {
try {
// console.log("Handling '" + msg_type + "' message: ", msg);
callback(fig, msg);
} catch (e) {
console.log("Exception inside the 'handler_" + msg_type + "' callback:", e, e.stack, msg);
}
}
};
}
// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas mpl.findpos = function(e) { //this section is from http://www.quirksmode.org/js/events_properties.html var targ; if (!e) e = window.event; if (e.target) targ = e.target; else if (e.srcElement) targ = e.srcElement; if (targ.nodeType == 3) // defeat Safari bug targ = targ.parentNode;
// jQuery normalizes the pageX and pageY
// pageX,Y are the mouse positions relative to the document
// offset() returns the position of the element relative to the document
var x = e.pageX - $(targ).offset().left;
var y = e.pageY - $(targ).offset().top;
return {"x": x, "y": y};
};
/*
- return a copy of an object with only non-object keys
- we need this to avoid circular references
- http://stackoverflow.com/a/24161582/3208463 */ function simpleKeys (original) { return Object.keys(original).reduce(function (obj, key) { if (typeof original[key] !== 'object') obj[key] = original[key] return obj; }, {}); }
mpl.figure.prototype.mouse_event = function(event, name) { var canvas_pos = mpl.findpos(event)
if (name === 'button_press')
{
this.canvas.focus();
this.canvas_div.focus();
}
var x = canvas_pos.x;
var y = canvas_pos.y;
this.send_message(name, {x: x, y: y, button: event.button,
step: event.step,
guiEvent: simpleKeys(event)});
/* This prevents the web browser from automatically changing to
* the text insertion cursor when the button is pressed. We want
* to control all of the cursor setting manually through the
* 'cursor' event from matplotlib */
event.preventDefault();
return false;
}
mpl.figure.prototype._key_event_extra = function(event, name) { // Handle any extra behaviour associated with a key event }
mpl.figure.prototype.key_event = function(event, name) {
// Prevent repeat events
if (name == 'key_press')
{
if (event.which === this._key)
return;
else
this._key = event.which;
}
if (name == 'key_release')
this._key = null;
var value = '';
if (event.ctrlKey && event.which != 17)
value += "ctrl+";
if (event.altKey && event.which != 18)
value += "alt+";
if (event.shiftKey && event.which != 16)
value += "shift+";
value += 'k';
value += event.which.toString();
this._key_event_extra(event, name);
this.send_message(name, {key: value,
guiEvent: simpleKeys(event)});
return false;
}
mpl.figure.prototype.toolbar_button_onclick = function(name) { if (name == 'download') { this.handle_save(this, null); } else { this.send_message("toolbar_button", {name: name}); } };
mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) { this.message.textContent = tooltip; }; mpl.toolbar_items = [["Home", "Reset original view", "fa fa-home icon-home", "home"], ["Back", "Back to previous view", "fa fa-arrow-left icon-arrow-left", "back"], ["Forward", "Forward to next view", "fa fa-arrow-right icon-arrow-right", "forward"], ["", "", "", ""], ["Pan", "Pan axes with left mouse, zoom with right", "fa fa-arrows icon-move", "pan"], ["Zoom", "Zoom to rectangle", "fa fa-square-o icon-check-empty", "zoom"], ["", "", "", ""], ["Download", "Download plot", "fa fa-floppy-o icon-save", "download"]];
mpl.extensions = ["eps", "jpeg", "pdf", "png", "ps", "raw", "svg", "tif"];
mpl.default_extension = "png";var comm_websocket_adapter = function(comm) { // Create a "websocket"-like object which calls the given IPython comm // object with the appropriate methods. Currently this is a non binary // socket, so there is still some room for performance tuning. var ws = {};
ws.close = function() {
comm.close()
};
ws.send = function(m) {
//console.log('sending', m);
comm.send(m);
};
// Register the callback with on_msg.
comm.on_msg(function(msg) {
//console.log('receiving', msg['content']['data'], msg);
// Pass the mpl event to the overriden (by mpl) onmessage function.
ws.onmessage(msg['content']['data'])
});
return ws;
}
mpl.mpl_figure_comm = function(comm, msg) { // This is the function which gets called when the mpl process // starts-up an IPython Comm through the "matplotlib" channel.
var id = msg.content.data.id;
// Get hold of the div created by the display call when the Comm
// socket was opened in Python.
var element = $("#" + id);
var ws_proxy = comm_websocket_adapter(comm)
function ondownload(figure, format) {
window.open(figure.imageObj.src);
}
var fig = new mpl.figure(id, ws_proxy,
ondownload,
element.get(0));
// Call onopen now - mpl needs it, as it is assuming we've passed it a real
// web socket which is closed, not our websocket->open comm proxy.
ws_proxy.onopen();
fig.parent_element = element.get(0);
fig.cell_info = mpl.find_output_cell("<div id='" + id + "'></div>");
if (!fig.cell_info) {
console.error("Failed to find cell for figure", id, fig);
return;
}
var output_index = fig.cell_info[2]
var cell = fig.cell_info[0];
};
mpl.figure.prototype.handle_close = function(fig, msg) { fig.root.unbind('remove')
// Update the output cell to use the data from the current canvas.
fig.push_to_output();
var dataURL = fig.canvas.toDataURL();
// Re-enable the keyboard manager in IPython - without this line, in FF,
// the notebook keyboard shortcuts fail.
IPython.keyboard_manager.enable()
$(fig.parent_element).html('<img src="' + dataURL + '">');
fig.close_ws(fig, msg);
}
mpl.figure.prototype.close_ws = function(fig, msg){ fig.send_message('closing', msg); // fig.ws.close() }
mpl.figure.prototype.push_to_output = function(remove_interactive) { // Turn the data on the canvas into data in the output cell. var dataURL = this.canvas.toDataURL(); this.cell_info[1]['text/html'] = ''; }
mpl.figure.prototype.updated_canvas_event = function() { // Tell IPython that the notebook contents must change. IPython.notebook.set_dirty(true); this.send_message("ack", {}); var fig = this; // Wait a second, then push the new image to the DOM so // that it is saved nicely (might be nice to debounce this). setTimeout(function () { fig.push_to_output() }, 1000); }
mpl.figure.prototype._init_toolbar = function() { var fig = this;
var nav_element = $('<div/>')
nav_element.attr('style', 'width: 100%');
this.root.append(nav_element);
// Define a callback function for later on.
function toolbar_event(event) {
return fig.toolbar_button_onclick(event['data']);
}
function toolbar_mouse_event(event) {
return fig.toolbar_button_onmouseover(event['data']);
}
for(var toolbar_ind in mpl.toolbar_items){
var name = mpl.toolbar_items[toolbar_ind][0];
var tooltip = mpl.toolbar_items[toolbar_ind][1];
var image = mpl.toolbar_items[toolbar_ind][2];
var method_name = mpl.toolbar_items[toolbar_ind][3];
if (!name) { continue; };
var button = $('<button class="btn btn-default" href="#" title="' + name + '"><i class="fa ' + image + ' fa-lg"></i></button>');
button.click(method_name, toolbar_event);
button.mouseover(tooltip, toolbar_mouse_event);
nav_element.append(button);
}
// Add the status bar.
var status_bar = $('<span class="mpl-message" style="text-align:right; float: right;"/>');
nav_element.append(status_bar);
this.message = status_bar[0];
// Add the close button to the window.
var buttongrp = $('<div class="btn-group inline pull-right"></div>');
var button = $('<button class="btn btn-mini btn-primary" href="#" title="Stop Interaction"><i class="fa fa-power-off icon-remove icon-large"></i></button>');
button.click(function (evt) { fig.handle_close(fig, {}); } );
button.mouseover('Stop Interaction', toolbar_mouse_event);
buttongrp.append(button);
var titlebar = this.root.find($('.ui-dialog-titlebar'));
titlebar.prepend(buttongrp);
}
mpl.figure.prototype._root_extra_style = function(el){ var fig = this el.on("remove", function(){ fig.close_ws(fig, {}); }); }
mpl.figure.prototype._canvas_extra_style = function(el){ // this is important to make the div 'focusable el.attr('tabindex', 0) // reach out to IPython and tell the keyboard manager to turn it's self // off when our div gets focus
// location in version 3
if (IPython.notebook.keyboard_manager) {
IPython.notebook.keyboard_manager.register_events(el);
}
else {
// location in version 2
IPython.keyboard_manager.register_events(el);
}
}
mpl.figure.prototype._key_event_extra = function(event, name) { var manager = IPython.notebook.keyboard_manager; if (!manager) manager = IPython.keyboard_manager;
// Check for shift+enter
if (event.shiftKey && event.which == 13) {
this.canvas_div.blur();
event.shiftKey = false;
// Send a "J" for go to next cell
event.which = 74;
event.keyCode = 74;
manager.command_mode();
manager.handle_keydown(event);
}
}
mpl.figure.prototype.handle_save = function(fig, msg) { fig.ondownload(fig, null); }
mpl.find_output_cell = function(html_output) { // Return the cell and output element which can be found uniquely in the notebook. // Note - this is a bit hacky, but it is done because the "notebook_saving.Notebook" // IPython event is triggered only after the cells have been serialised, which for // our purposes (turning an active figure into a static one), is too late. var cells = IPython.notebook.get_cells(); var ncells = cells.length; for (var i=0; i<ncells; i++) { var cell = cells[i]; if (cell.cell_type === 'code'){ for (var j=0; j<cell.output_area.outputs.length; j++) { var data = cell.output_area.outputs[j]; if (data.data) { // IPython >= 3 moved mimebundle to data attribute of output data = data.data; } if (data['text/html'] == html_output) { return [cell, data, j]; } } } } }
// Register the function which deals with the matplotlib target/channel. // The kernel may be null if the page has been refreshed. if (IPython.notebook.kernel != null) { IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm); }
</script><ggplot: (29800996)>
By looking at this plot we can say that total number of impressions is almost consistent over day. Each day almost same amount of ad (around 8000) were shown to people.
# 12. Bar plot of impressions vs. hour of dayggplot(aes(x='mode_impr_hour'), data=df[(df["converted"]==1) & (df["mode_impr_hour"]>=8) & (df["mode_impr_hour"]<=23)]) +
xlab("Hours") + ylab("Impressions") + ggtitle("Impressions Vs. Hour") + geom_bar()
mpl.get_websocket_type = function() { if (typeof(WebSocket) !== 'undefined') { return WebSocket; } else if (typeof(MozWebSocket) !== 'undefined') { return MozWebSocket; } else { alert('Your browser does not have WebSocket support.' + 'Please try Chrome, Safari or Firefox ≥ 6. ' + 'Firefox 4 and 5 are also supported but you ' + 'have to enable WebSockets in about:config.'); }; }
mpl.figure = function(figure_id, websocket, ondownload, parent_element) { this.id = figure_id;
this.ws = websocket;
this.supports_binary = (this.ws.binaryType != undefined);
if (!this.supports_binary) {
var warnings = document.getElementById("mpl-warnings");
if (warnings) {
warnings.style.display = 'block';
warnings.textContent = (
"This browser does not support binary websocket messages. " +
"Performance may be slow.");
}
}
this.imageObj = new Image();
this.context = undefined;
this.message = undefined;
this.canvas = undefined;
this.rubberband_canvas = undefined;
this.rubberband_context = undefined;
this.format_dropdown = undefined;
this.image_mode = 'full';
this.root = $('<div/>');
this._root_extra_style(this.root)
this.root.attr('style', 'display: inline-block');
$(parent_element).append(this.root);
this._init_header(this);
this._init_canvas(this);
this._init_toolbar(this);
var fig = this;
this.waiting = false;
this.ws.onopen = function () {
fig.send_message("supports_binary", {value: fig.supports_binary});
fig.send_message("send_image_mode", {});
fig.send_message("refresh", {});
}
this.imageObj.onload = function() {
if (fig.image_mode == 'full') {
// Full images could contain transparency (where diff images
// almost always do), so we need to clear the canvas so that
// there is no ghosting.
fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);
}
fig.context.drawImage(fig.imageObj, 0, 0);
};
this.imageObj.onunload = function() {
this.ws.close();
}
this.ws.onmessage = this._make_on_message_function(this);
this.ondownload = ondownload;
}
mpl.figure.prototype._init_header = function() { var titlebar = $( '
mpl.figure.prototype._canvas_extra_style = function(canvas_div) {
}
mpl.figure.prototype._root_extra_style = function(canvas_div) {
}
mpl.figure.prototype._init_canvas = function() { var fig = this;
var canvas_div = $('<div/>');
canvas_div.attr('style', 'position: relative; clear: both; outline: 0');
function canvas_keyboard_event(event) {
return fig.key_event(event, event['data']);
}
canvas_div.keydown('key_press', canvas_keyboard_event);
canvas_div.keyup('key_release', canvas_keyboard_event);
this.canvas_div = canvas_div
this._canvas_extra_style(canvas_div)
this.root.append(canvas_div);
var canvas = $('<canvas/>');
canvas.addClass('mpl-canvas');
canvas.attr('style', "left: 0; top: 0; z-index: 0; outline: 0")
this.canvas = canvas[0];
this.context = canvas[0].getContext("2d");
var rubberband = $('<canvas/>');
rubberband.attr('style', "position: absolute; left: 0; top: 0; z-index: 1;")
var pass_mouse_events = true;
canvas_div.resizable({
start: function(event, ui) {
pass_mouse_events = false;
},
resize: function(event, ui) {
fig.request_resize(ui.size.width, ui.size.height);
},
stop: function(event, ui) {
pass_mouse_events = true;
fig.request_resize(ui.size.width, ui.size.height);
},
});
function mouse_event_fn(event) {
if (pass_mouse_events)
return fig.mouse_event(event, event['data']);
}
rubberband.mousedown('button_press', mouse_event_fn);
rubberband.mouseup('button_release', mouse_event_fn);
// Throttle sequential mouse events to 1 every 20ms.
rubberband.mousemove('motion_notify', mouse_event_fn);
rubberband.mouseenter('figure_enter', mouse_event_fn);
rubberband.mouseleave('figure_leave', mouse_event_fn);
canvas_div.on("wheel", function (event) {
event = event.originalEvent;
event['data'] = 'scroll'
if (event.deltaY < 0) {
event.step = 1;
} else {
event.step = -1;
}
mouse_event_fn(event);
});
canvas_div.append(canvas);
canvas_div.append(rubberband);
this.rubberband = rubberband;
this.rubberband_canvas = rubberband[0];
this.rubberband_context = rubberband[0].getContext("2d");
this.rubberband_context.strokeStyle = "#000000";
this._resize_canvas = function(width, height) {
// Keep the size of the canvas, canvas container, and rubber band
// canvas in synch.
canvas_div.css('width', width)
canvas_div.css('height', height)
canvas.attr('width', width);
canvas.attr('height', height);
rubberband.attr('width', width);
rubberband.attr('height', height);
}
// Set the figure to an initial 600x600px, this will subsequently be updated
// upon first draw.
this._resize_canvas(600, 600);
// Disable right mouse context menu.
$(this.rubberband_canvas).bind("contextmenu",function(e){
return false;
});
function set_focus () {
canvas.focus();
canvas_div.focus();
}
window.setTimeout(set_focus, 100);
}
mpl.figure.prototype._init_toolbar = function() { var fig = this;
var nav_element = $('<div/>')
nav_element.attr('style', 'width: 100%');
this.root.append(nav_element);
// Define a callback function for later on.
function toolbar_event(event) {
return fig.toolbar_button_onclick(event['data']);
}
function toolbar_mouse_event(event) {
return fig.toolbar_button_onmouseover(event['data']);
}
for(var toolbar_ind in mpl.toolbar_items) {
var name = mpl.toolbar_items[toolbar_ind][0];
var tooltip = mpl.toolbar_items[toolbar_ind][1];
var image = mpl.toolbar_items[toolbar_ind][2];
var method_name = mpl.toolbar_items[toolbar_ind][3];
if (!name) {
// put a spacer in here.
continue;
}
var button = $('<button/>');
button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +
'ui-button-icon-only');
button.attr('role', 'button');
button.attr('aria-disabled', 'false');
button.click(method_name, toolbar_event);
button.mouseover(tooltip, toolbar_mouse_event);
var icon_img = $('<span/>');
icon_img.addClass('ui-button-icon-primary ui-icon');
icon_img.addClass(image);
icon_img.addClass('ui-corner-all');
var tooltip_span = $('<span/>');
tooltip_span.addClass('ui-button-text');
tooltip_span.html(tooltip);
button.append(icon_img);
button.append(tooltip_span);
nav_element.append(button);
}
var fmt_picker_span = $('<span/>');
var fmt_picker = $('<select/>');
fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');
fmt_picker_span.append(fmt_picker);
nav_element.append(fmt_picker_span);
this.format_dropdown = fmt_picker[0];
for (var ind in mpl.extensions) {
var fmt = mpl.extensions[ind];
var option = $(
'<option/>', {selected: fmt === mpl.default_extension}).html(fmt);
fmt_picker.append(option)
}
// Add hover states to the ui-buttons
$( ".ui-button" ).hover(
function() { $(this).addClass("ui-state-hover");},
function() { $(this).removeClass("ui-state-hover");}
);
var status_bar = $('<span class="mpl-message"/>');
nav_element.append(status_bar);
this.message = status_bar[0];
}
mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) { // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client, // which will in turn request a refresh of the image. this.send_message('resize', {'width': x_pixels, 'height': y_pixels}); }
mpl.figure.prototype.send_message = function(type, properties) { properties['type'] = type; properties['figure_id'] = this.id; this.ws.send(JSON.stringify(properties)); }
mpl.figure.prototype.send_draw_message = function() { if (!this.waiting) { this.waiting = true; this.ws.send(JSON.stringify({type: "draw", figure_id: this.id})); } }
mpl.figure.prototype.handle_save = function(fig, msg) { var format_dropdown = fig.format_dropdown; var format = format_dropdown.options[format_dropdown.selectedIndex].value; fig.ondownload(fig, format); }
mpl.figure.prototype.handle_resize = function(fig, msg) { var size = msg['size']; if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) { fig._resize_canvas(size[0], size[1]); fig.send_message("refresh", {}); }; }
mpl.figure.prototype.handle_rubberband = function(fig, msg) { var x0 = msg['x0']; var y0 = fig.canvas.height - msg['y0']; var x1 = msg['x1']; var y1 = fig.canvas.height - msg['y1']; x0 = Math.floor(x0) + 0.5; y0 = Math.floor(y0) + 0.5; x1 = Math.floor(x1) + 0.5; y1 = Math.floor(y1) + 0.5; var min_x = Math.min(x0, x1); var min_y = Math.min(y0, y1); var width = Math.abs(x1 - x0); var height = Math.abs(y1 - y0);
fig.rubberband_context.clearRect(
0, 0, fig.canvas.width, fig.canvas.height);
fig.rubberband_context.strokeRect(min_x, min_y, width, height);
}
mpl.figure.prototype.handle_figure_label = function(fig, msg) { // Updates the figure title. fig.header.textContent = msg['label']; }
mpl.figure.prototype.handle_cursor = function(fig, msg) { var cursor = msg['cursor']; switch(cursor) { case 0: cursor = 'pointer'; break; case 1: cursor = 'default'; break; case 2: cursor = 'crosshair'; break; case 3: cursor = 'move'; break; } fig.rubberband_canvas.style.cursor = cursor; }
mpl.figure.prototype.handle_message = function(fig, msg) { fig.message.textContent = msg['message']; }
mpl.figure.prototype.handle_draw = function(fig, msg) { // Request the server to send over a new figure. fig.send_draw_message(); }
mpl.figure.prototype.handle_image_mode = function(fig, msg) { fig.image_mode = msg['mode']; }
mpl.figure.prototype.updated_canvas_event = function() { // Called whenever the canvas gets updated. this.send_message("ack", {}); }
// A function to construct a web socket function for onmessage handling. // Called in the figure constructor. mpl.figure.prototype._make_on_message_function = function(fig) { return function socket_on_message(evt) { if (evt.data instanceof Blob) { /* FIXME: We get "Resource interpreted as Image but * transferred with MIME type text/plain:" errors on * Chrome. But how to set the MIME type? It doesn't seem * to be part of the websocket stream */ evt.data.type = "image/png";
/* Free the memory for the previous frames */
if (fig.imageObj.src) {
(window.URL || window.webkitURL).revokeObjectURL(
fig.imageObj.src);
}
fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(
evt.data);
fig.updated_canvas_event();
fig.waiting = false;
return;
}
else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == "data:image/png;base64") {
fig.imageObj.src = evt.data;
fig.updated_canvas_event();
fig.waiting = false;
return;
}
var msg = JSON.parse(evt.data);
var msg_type = msg['type'];
// Call the "handle_{type}" callback, which takes
// the figure and JSON message as its only arguments.
try {
var callback = fig["handle_" + msg_type];
} catch (e) {
console.log("No handler for the '" + msg_type + "' message type: ", msg);
return;
}
if (callback) {
try {
// console.log("Handling '" + msg_type + "' message: ", msg);
callback(fig, msg);
} catch (e) {
console.log("Exception inside the 'handler_" + msg_type + "' callback:", e, e.stack, msg);
}
}
};
}
// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas mpl.findpos = function(e) { //this section is from http://www.quirksmode.org/js/events_properties.html var targ; if (!e) e = window.event; if (e.target) targ = e.target; else if (e.srcElement) targ = e.srcElement; if (targ.nodeType == 3) // defeat Safari bug targ = targ.parentNode;
// jQuery normalizes the pageX and pageY
// pageX,Y are the mouse positions relative to the document
// offset() returns the position of the element relative to the document
var x = e.pageX - $(targ).offset().left;
var y = e.pageY - $(targ).offset().top;
return {"x": x, "y": y};
};
/*
- return a copy of an object with only non-object keys
- we need this to avoid circular references
- http://stackoverflow.com/a/24161582/3208463 */ function simpleKeys (original) { return Object.keys(original).reduce(function (obj, key) { if (typeof original[key] !== 'object') obj[key] = original[key] return obj; }, {}); }
mpl.figure.prototype.mouse_event = function(event, name) { var canvas_pos = mpl.findpos(event)
if (name === 'button_press')
{
this.canvas.focus();
this.canvas_div.focus();
}
var x = canvas_pos.x;
var y = canvas_pos.y;
this.send_message(name, {x: x, y: y, button: event.button,
step: event.step,
guiEvent: simpleKeys(event)});
/* This prevents the web browser from automatically changing to
* the text insertion cursor when the button is pressed. We want
* to control all of the cursor setting manually through the
* 'cursor' event from matplotlib */
event.preventDefault();
return false;
}
mpl.figure.prototype._key_event_extra = function(event, name) { // Handle any extra behaviour associated with a key event }
mpl.figure.prototype.key_event = function(event, name) {
// Prevent repeat events
if (name == 'key_press')
{
if (event.which === this._key)
return;
else
this._key = event.which;
}
if (name == 'key_release')
this._key = null;
var value = '';
if (event.ctrlKey && event.which != 17)
value += "ctrl+";
if (event.altKey && event.which != 18)
value += "alt+";
if (event.shiftKey && event.which != 16)
value += "shift+";
value += 'k';
value += event.which.toString();
this._key_event_extra(event, name);
this.send_message(name, {key: value,
guiEvent: simpleKeys(event)});
return false;
}
mpl.figure.prototype.toolbar_button_onclick = function(name) { if (name == 'download') { this.handle_save(this, null); } else { this.send_message("toolbar_button", {name: name}); } };
mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) { this.message.textContent = tooltip; }; mpl.toolbar_items = [["Home", "Reset original view", "fa fa-home icon-home", "home"], ["Back", "Back to previous view", "fa fa-arrow-left icon-arrow-left", "back"], ["Forward", "Forward to next view", "fa fa-arrow-right icon-arrow-right", "forward"], ["", "", "", ""], ["Pan", "Pan axes with left mouse, zoom with right", "fa fa-arrows icon-move", "pan"], ["Zoom", "Zoom to rectangle", "fa fa-square-o icon-check-empty", "zoom"], ["", "", "", ""], ["Download", "Download plot", "fa fa-floppy-o icon-save", "download"]];
mpl.extensions = ["eps", "jpeg", "pdf", "png", "ps", "raw", "svg", "tif"];
mpl.default_extension = "png";var comm_websocket_adapter = function(comm) { // Create a "websocket"-like object which calls the given IPython comm // object with the appropriate methods. Currently this is a non binary // socket, so there is still some room for performance tuning. var ws = {};
ws.close = function() {
comm.close()
};
ws.send = function(m) {
//console.log('sending', m);
comm.send(m);
};
// Register the callback with on_msg.
comm.on_msg(function(msg) {
//console.log('receiving', msg['content']['data'], msg);
// Pass the mpl event to the overriden (by mpl) onmessage function.
ws.onmessage(msg['content']['data'])
});
return ws;
}
mpl.mpl_figure_comm = function(comm, msg) { // This is the function which gets called when the mpl process // starts-up an IPython Comm through the "matplotlib" channel.
var id = msg.content.data.id;
// Get hold of the div created by the display call when the Comm
// socket was opened in Python.
var element = $("#" + id);
var ws_proxy = comm_websocket_adapter(comm)
function ondownload(figure, format) {
window.open(figure.imageObj.src);
}
var fig = new mpl.figure(id, ws_proxy,
ondownload,
element.get(0));
// Call onopen now - mpl needs it, as it is assuming we've passed it a real
// web socket which is closed, not our websocket->open comm proxy.
ws_proxy.onopen();
fig.parent_element = element.get(0);
fig.cell_info = mpl.find_output_cell("<div id='" + id + "'></div>");
if (!fig.cell_info) {
console.error("Failed to find cell for figure", id, fig);
return;
}
var output_index = fig.cell_info[2]
var cell = fig.cell_info[0];
};
mpl.figure.prototype.handle_close = function(fig, msg) { fig.root.unbind('remove')
// Update the output cell to use the data from the current canvas.
fig.push_to_output();
var dataURL = fig.canvas.toDataURL();
// Re-enable the keyboard manager in IPython - without this line, in FF,
// the notebook keyboard shortcuts fail.
IPython.keyboard_manager.enable()
$(fig.parent_element).html('<img src="' + dataURL + '">');
fig.close_ws(fig, msg);
}
mpl.figure.prototype.close_ws = function(fig, msg){ fig.send_message('closing', msg); // fig.ws.close() }
mpl.figure.prototype.push_to_output = function(remove_interactive) { // Turn the data on the canvas into data in the output cell. var dataURL = this.canvas.toDataURL(); this.cell_info[1]['text/html'] = ''; }
mpl.figure.prototype.updated_canvas_event = function() { // Tell IPython that the notebook contents must change. IPython.notebook.set_dirty(true); this.send_message("ack", {}); var fig = this; // Wait a second, then push the new image to the DOM so // that it is saved nicely (might be nice to debounce this). setTimeout(function () { fig.push_to_output() }, 1000); }
mpl.figure.prototype._init_toolbar = function() { var fig = this;
var nav_element = $('<div/>')
nav_element.attr('style', 'width: 100%');
this.root.append(nav_element);
// Define a callback function for later on.
function toolbar_event(event) {
return fig.toolbar_button_onclick(event['data']);
}
function toolbar_mouse_event(event) {
return fig.toolbar_button_onmouseover(event['data']);
}
for(var toolbar_ind in mpl.toolbar_items){
var name = mpl.toolbar_items[toolbar_ind][0];
var tooltip = mpl.toolbar_items[toolbar_ind][1];
var image = mpl.toolbar_items[toolbar_ind][2];
var method_name = mpl.toolbar_items[toolbar_ind][3];
if (!name) { continue; };
var button = $('<button class="btn btn-default" href="#" title="' + name + '"><i class="fa ' + image + ' fa-lg"></i></button>');
button.click(method_name, toolbar_event);
button.mouseover(tooltip, toolbar_mouse_event);
nav_element.append(button);
}
// Add the status bar.
var status_bar = $('<span class="mpl-message" style="text-align:right; float: right;"/>');
nav_element.append(status_bar);
this.message = status_bar[0];
// Add the close button to the window.
var buttongrp = $('<div class="btn-group inline pull-right"></div>');
var button = $('<button class="btn btn-mini btn-primary" href="#" title="Stop Interaction"><i class="fa fa-power-off icon-remove icon-large"></i></button>');
button.click(function (evt) { fig.handle_close(fig, {}); } );
button.mouseover('Stop Interaction', toolbar_mouse_event);
buttongrp.append(button);
var titlebar = this.root.find($('.ui-dialog-titlebar'));
titlebar.prepend(buttongrp);
}
mpl.figure.prototype._root_extra_style = function(el){ var fig = this el.on("remove", function(){ fig.close_ws(fig, {}); }); }
mpl.figure.prototype._canvas_extra_style = function(el){ // this is important to make the div 'focusable el.attr('tabindex', 0) // reach out to IPython and tell the keyboard manager to turn it's self // off when our div gets focus
// location in version 3
if (IPython.notebook.keyboard_manager) {
IPython.notebook.keyboard_manager.register_events(el);
}
else {
// location in version 2
IPython.keyboard_manager.register_events(el);
}
}
mpl.figure.prototype._key_event_extra = function(event, name) { var manager = IPython.notebook.keyboard_manager; if (!manager) manager = IPython.keyboard_manager;
// Check for shift+enter
if (event.shiftKey && event.which == 13) {
this.canvas_div.blur();
event.shiftKey = false;
// Send a "J" for go to next cell
event.which = 74;
event.keyCode = 74;
manager.command_mode();
manager.handle_keydown(event);
}
}
mpl.figure.prototype.handle_save = function(fig, msg) { fig.ondownload(fig, null); }
mpl.find_output_cell = function(html_output) { // Return the cell and output element which can be found uniquely in the notebook. // Note - this is a bit hacky, but it is done because the "notebook_saving.Notebook" // IPython event is triggered only after the cells have been serialised, which for // our purposes (turning an active figure into a static one), is too late. var cells = IPython.notebook.get_cells(); var ncells = cells.length; for (var i=0; i<ncells; i++) { var cell = cells[i]; if (cell.cell_type === 'code'){ for (var j=0; j<cell.output_area.outputs.length; j++) { var data = cell.output_area.outputs[j]; if (data.data) { // IPython >= 3 moved mimebundle to data attribute of output data = data.data; } if (data['text/html'] == html_output) { return [cell, data, j]; } } } } }
// Register the function which deals with the matplotlib target/channel. // The kernel may be null if the page has been refreshed. if (IPython.notebook.kernel != null) { IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm); }
</script>