{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ " # Machine Learning LAB 1 (course 2022/23, F. Chiariotti) \n", "\n", "The notebook contains some simple tasks to be performed about classification and regression. Complete all the required code sections and answer to all the questions." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 1) Classification of NBA players role\n", "\n", "## IMPORTANT: make sure to rerun all the code from the beginning to obtain the results for the final version of your notebook, since this is the way we will do it before evaluting your notebook!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Place your name and ID number. Also recall to save the file as Surname_Name_LAB1.ipynb\n", "\n", "Student name:
\n", "ID Number:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Dataset description\n", "\n", "We will be working with a dataset of NBA basketball players data (you can get from https://www.kaggle.com/jacobbaruch/nba-player-of-the-week the full dataset).\n", "\n", "The provided data is a subset of the Kaggle dataset containing the players that have the role of Center and of Point Guard. For each player the dataset contains 3 features, the height, the weight and the age.\n", "\n", "From Wikipedia (if you are not a basketball fan!!):\n", "\n", "The Center (C), also known as the five, or the big man, is one of the five positions in a regular basketball game. The center is normally the tallest player on the team, and often has a great deal of strength and body mass as well. In the NBA, the center is usually 6' 10\" (2.08 m) or taller and usually weighs 240 lbs (109 kg) or more. \n", "\n", "Point Guards (PG, a.k.a. as \"play maker\") are expected to run the team's offense by controlling the ball and making sure that it gets to the right players at the right time. In the NBA, point guards are usually about 6' 3\" (1.93 m) or shorter, and average about 6' 2\" (1.88 m). Having above-average size (height, muscle) is considered advantageous, although size is secondary to situational awareness, speed, quickness, and ball handling skills. Shorter players tend to be better dribblers since they are closer to the floor, and thus have better control of the ball while dribbling. \n", "\n", "\n", "As it is clear from the description, the height and weight of the player are good hints to predict their role and in this lab we will exploit this features to estimate the role.\n", "\n", "\n", "### Three features are considered for this dataset:\n", "\n", "\n", "1) Height in cm\n", "\n", "2) Weight in kg\n", "\n", "3) Age in years" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We first import all the packages that are needed." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "%matplotlib inline\n", "import matplotlib.pyplot as plt\n", "import csv\n", "\n", "import numpy as np\n", "import scipy as sp\n", "import sklearn as sl\n", "from scipy import stats\n", "from sklearn import datasets\n", "from sklearn import linear_model" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Perceptron\n", "Firstly we will implement the perceptron algorithm and use it to learn a halfspace." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**TO DO** Set the random seed (you can use your ID (matricola) or any other number!)." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "IDnumber = 235245 #replace with your ID or try some random values\n", "np.random.seed(IDnumber)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Load the dataset and then split in training set and test set (the training set is typically larger, you can use a 70% tranining 30% test split) after applying a random permutation to the datset." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A) Load dataset and perform permutation" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['Position', 'Height cm', 'kg', 'Age']\n", "260\n" ] } ], "source": [ "#load the dataset\n", "filename = 'data/NBA.csv'\n", "NBA = csv.reader(open(filename, newline=''), delimiter=',')\n", "\n", "header = next(NBA) #skip first line\n", "print(header)\n", "\n", "dataset = list(NBA)\n", "for i in range(len(dataset)):\n", " dataset[i] = [int(x) for x in dataset[i]]\n", " \n", "dataset = np.asarray(dataset)\n", "\n", "X = dataset[:,1:4] #columns 1,2,3 contain the features\n", "Y = dataset[:,0] # column 0: labels\n", "\n", "Y = Y*2-1 # set labels to -1, 1 as required by perceptron implementation\n", "\n", "m = dataset.shape[0]\n", "print(m)\n", "permutation = np.random.permutation(m) # random permurtation\n", "\n", "X = X[permutation]\n", "Y = Y[permutation]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We are going to classify class \"1\" (Center) vs class \"-1\" (Point Guard)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "B) **TO DO** Divide the data into training set and test set (70% of the data in the first set, 30% in the second one)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[ 1 1 -1 -1 -1 1 1 -1 -1 -1 1 -1 -1 -1 -1 -1 -1 -1 1 1 1 -1 1 -1\n", " 1 -1 1 1 1 1 -1 -1 1 1 1 -1 -1 1 1 -1 1 1 1 -1 1 -1 1 1\n", " 1 1 -1 -1 -1 1 1 1 1 1 -1 1 1 -1 1 1 1 1 -1 1 -1 -1 1 1\n", " 1 1 -1 -1 -1 1 -1 -1 -1 1 -1 -1 1 1 1 1 1 1 -1 -1 1 1 1 1\n", " -1 1 1 -1 -1 1 1 1 -1 1 -1 1 -1 1 1 1 -1 -1 1 -1 1 1 1 1\n", " -1 -1 -1 1 1 1 -1 1 -1 1 -1 1 1 1 -1 -1 1 1 -1 1 -1 -1 1 1\n", " -1 -1 1 -1 1 1 1 1 1 1 1 1 1 -1 1 -1 -1 1 1 1 1 -1 1 1\n", " -1 -1 -1 1 1 1 1 1 1 -1 -1 1 1 -1]\n", "78\n", "Shape of training set: (182, 3)\n", "Shape of test set: (78, 3)\n" ] } ], "source": [ "#Divide in training and test: make sure that your training set\n", "#contains at least 10 elements from class 1 and at least 10 elements\n", "#from class -1! If it does not, modify the code so to apply more random\n", "#permutations (or the same permutation multiple times) until this happens.\n", "#IMPORTANT: do not change the random seed.\n", "\n", "#m_training needs to be the number of samples in the training set\n", "m_training = int(X.shape[0]*0.7)\n", "\n", "#m_test needs to be the number of samples in the test set\n", "m_test = int(X.shape[0]-(X.shape[0]*0.7))\n", "\n", "#X_training = instances for training set\n", "X_training = X[:m_training,:]\n", "#Y_training = labels for the training set\n", "Y_training = Y[:m_training]\n", "\n", "#X_test = instances for test set\n", "X_test = X[m_training:,]\n", "#Y_test = labels for the test set\n", "Y_test = Y[m_training:]\n", "\n", "print(Y_training) #to make sure that Y_training contains both 1 and -1\n", "print(m_test)\n", "\n", "print(\"Shape of training set: \" + str(X_training.shape))\n", "print(\"Shape of test set: \" + str(X_test.shape))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**TO DO** Now add a 1 in front of each sample so that we can use a vector in homogeneous coordinates to describe all the coefficients of the model. You can use the function $hstack$ in $numpy$" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "#add a 1 to each sample (homogeneous coordinates)\n", "X_training = np.hstack((np.ones((m_training,1)),X_training))\n", "X_test = np.hstack((np.ones((m_test,1)),X_test))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**TO DO** Now complete the function *perceptron*. Since the perceptron does not terminate if the data is not linearly separable, your implementation should return the desired output (see below) if it reached the termination condition seen in class or if a maximum number of iterations have already been run, where one iteration corresponds to one update of the perceptron weights. In case the termination is reached because the maximum number of iterations have been completed, the implementation should return **the best model** seen up to now.\n", "\n", "The input parameters to pass are:\n", "- $X$: the matrix of input features, one row for each sample\n", "- $Y$: the vector of labels for the input features matrix X\n", "- $max\\_num\\_iterations$: the maximum number of iterations for running the perceptron\n", "\n", "The output values are:\n", "- $best\\_w$: the vector with the coefficients of the best model\n", "- $best\\_error$: the *fraction* of misclassified samples for the best model" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "def perceptron_update(current_w, x, y):\n", " # Place in this function the update rule of the perceptron algorithm\n", " new_w = current_w + y*x\n", " return new_w\n", "\n", "def perceptron(X, Y, max_num_iterations):\n", " \n", " #init the algorith with w=0, use a best_w variable to keep track of the best solution\n", " curr_w = np.zeros(X.shape[1])\n", " best_w = curr_w\n", " num_samples = X.shape[0]\n", " best_error = num_samples+1\n", " #now scan the entire dataset, and while we do it we compute the empirical\n", " #risk (0-1 loss) for the curr_w and also save 1 point that is misclassified\n", " #by curr_w\n", " #in output produce the best_w and the corresponding best_error\n", " index_misclassified = 1\n", " num_misclassified = 0\n", " \n", " \n", " \n", " num_iter = 0\n", " #main loop continue until all samples correctly classified or max # iterations reached\n", " while ((index_misclassified != -1) and (num_iter < max_num_iterations)):\n", " \n", " index_misclassified = -1\n", " num_misclassified = 0\n", " permutation = np.random.permutation(num_samples)\n", " for i in range(num_samples):\n", " #let's generate a random permutation so to check the elements in a random order\n", " \n", " x = X[permutation[i],:]\n", " y = Y[permutation[i]]\n", " prediction = np.sign(np.dot(curr_w,x))\n", " if (prediction != y):\n", " index_misclassified = permutation[i]\n", " num_misclassified += 1\n", " if num_misclassified < best_error:\n", " best_error = num_misclassified\n", " best_w = curr_w\n", " num_iter += 1\n", " #call update function using a misclassifed sample\n", " curr_w = perceptron_update(curr_w, X[index_misclassified,:],Y[index_misclassified])\n", " best_error = float(best_error)/float(num_samples)\n", " \n", " return best_w, best_error" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we use the implementation above of the perceptron to learn a model from the training data using 100 iterations and print the error of the best model we have found." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Training Error of perpceptron (100 iterations): 0.06593406593406594\n" ] } ], "source": [ "#now run the perceptron for 100 iterations\n", "w_found, error = perceptron(X_training,Y_training, 100)\n", "print(\"Training Error of perpceptron (100 iterations): \" + str(error))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**TO DO** use the best model $w\\_found$ to predict the labels for the test dataset and print the fraction of misclassified samples in the test set (the test error that is an estimate of the true loss)." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Test Error of perpceptron (100 iterations): 0.10256410256410256\n" ] } ], "source": [ "#now use the w_found to make predictions on test dataset\n", "\n", "num_errors = 0\n", "\n", "for i in range(m_test):\n", " x = X_test[i,:]\n", " y = Y_test[i]\n", " predicted = np.sign(np.dot(w_found,x))\n", " if (predicted != y):\n", " num_errors += 1\n", "\n", "true_loss_estimate = num_errors/m_test # error rate on the test set\n", "#NOTE: you can avoid using num_errors if you prefer, as long as true_loss_estimate is correct\n", "print(\"Test Error of perpceptron (100 iterations): \" + str(true_loss_estimate))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**TO DO** **[Answer the following]** What about the difference betweeen the training error and the test error in terms of fraction of misclassified samples)? Explain what you observe. [Write the answer in this cell]\n", "\n", "**ANSWER QUESTION 1**" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**TO DO** Copy the code from the last 2 cells above in the cell below and repeat the training with 3000 iterations. Then print the error in the training set and the estimate of the true loss obtained from the test set." ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.06593406593406594\n", "0.10256410256410256\n" ] } ], "source": [ "#now run the perceptron for 5000 iterations here!\n", "\n", "w_found, error = perceptron(X_training,Y_training, 3000)\n", "\n", "print(error)\n", "\n", "num_errors = 0.\n", "\n", "for i in range(m_test):\n", " x = X_test[i,:]\n", " y = Y_test[i]\n", " predicted = np.sign(np.dot(w_found,x))\n", " if (predicted != y):\n", " num_errors += 1\n", "\n", "true_loss_estimate = num_errors/m_test\n", "print(true_loss_estimate)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**TO DO** [Answer the following] What about the difference betweeen the training error and the test error in terms of fraction of misclassified samples) when running for a larger number of iterations ? Explain what you observe and compare with the previous case. [Write the answer in this cell]\n", "\n", "**ANSWER QUESTION 2**" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Logistic Regression\n", "Now we use logistic regression, exploiting the implementation in Scikit-learn, to predict labels. We will also plot the decision region of logistic regression.\n", "\n", "We first load the dataset again." ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['Position', 'Height cm', 'kg', 'Age']\n" ] } ], "source": [ "filename = 'data/NBA.csv'\n", "NBA = csv.reader(open(filename, newline=''), delimiter=',')\n", "\n", "header = next(NBA)\n", "print(header)\n", "\n", "dataset = list(NBA)\n", "for i in range(len(dataset)):\n", " dataset[i] = [int(x) for x in dataset[i]]\n", " \n", "dataset = np.asarray(dataset)\n", "\n", "X = dataset[:,1:]\n", "Y = dataset[:,0]\n", "\n", "Y = Y*2-1 # set labels to -1, 1 as required by perceptron implementation\n", "\n", "m = dataset.shape[0]\n", "permutation = np.random.permutation(m)\n", "\n", "X = X[permutation]\n", "Y = Y[permutation]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**TO DO** As for the previous part, divide the data into training and test (70%-30%) and add a 1 as first component to each sample." ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [], "source": [ "#Divide in training and test: make sure that your training set\n", "#contains at least 10 elements from class 1 and at least 10 elements\n", "#from class -1! If it does not, modify the code so to apply more random\n", "#permutations (or the same permutation multiple times) until this happens.\n", "#IMPORTANT: do not change the random seed.\n", "\n", "m_training = int(X.shape[0]*0.7)\n", "m_test = int(X.shape[0]-(X.shape[0]*0.7))\n", "\n", "X_training = X[:m_training,:]\n", "Y_training = Y[:m_training]\n", "\n", "X_test = X[m_training:,]\n", "Y_test = Y[m_training:]\n", "\n", "#add a 1 as first component to each sample\n", "#X_training = np.hstack((np.ones((m_training,1)),X_training))\n", "#X_test = np.hstack((np.ones((m_test,1)),X_test))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To define a logistic regression model in Scikit-learn use the instruction\n", "\n", "$linear\\_model.LogisticRegression(C=1e5)$\n", "\n", "($C$ is a parameter related to *regularization*, a technique that\n", "we will see later in the course. Setting it to a high value is almost\n", "as ignoring regularization, so the instruction above corresponds to the\n", "logistic regression you have seen in class.)\n", "\n", "To learn the model you need to use the $fit(...)$ instruction and to predict you need to use the $predict(...)$ function. See the Scikit-learn documentation for how to use it.\n", "\n", "**TO DO** Define the logistic regression model, then learn the model using the training set and predict on the test set. Then print the fraction of samples misclassified in the training set and in the test set." ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Intercept: [-19.41146172]\n", "Coefficients: [[-0.02864034 0.23066252 0.0599345 ]]\n", "Error rate on training set: 0.06593406593406594\n", "Error rate on test set: 0.0641025641025641\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "C:\\Users\\Anay Deshpande\\Anaconda3\\lib\\site-packages\\sklearn\\linear_model\\logistic.py:432: FutureWarning: Default solver will be changed to 'lbfgs' in 0.22. Specify a solver to silence this warning.\n", " FutureWarning)\n" ] } ], "source": [ "#part on logistic regression for 2 classes\n", "logreg = linear_model.LogisticRegression(C=1e5) #C very large to ignore regularization\n", "\n", "#learn from training set\n", "\n", "logreg.fit(X_training, Y_training)\n", "print(\"Intercept:\" , logreg.intercept_)\n", "print(\"Coefficients:\" , logreg.coef_)\n", "\n", "#predict on training set\n", "\n", "predicted_training = logreg.predict(X_training)\n", "\n", "#print the error rate = fraction of misclassified samples\n", "error_rate_training = 0\n", "for i in range(len(Y_training)):\n", " if predicted_training[i]!=Y_training[i]:\n", " error_rate_training += 1\n", "error_rate_training = error_rate_training / m_training\n", "print(\"Error rate on training set: \"+str(error_rate_training))\n", "\n", "#predict on test set\n", "\n", "predicted_test = logreg.predict(X_test)\n", "\n", "#print the error rate = fraction of misclassified samples\n", "error_rate_test = 0\n", "for i in range(len(Y_test)):\n", " if predicted_test[i]!=Y_test[i]:\n", " error_rate_test += 1\n", "error_rate_test = error_rate_test / m_test\n", "print(\"Error rate on test set: \" + str(error_rate_test))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**TO DO** Now pick two features and restrict the dataset to include only two features, whose indices are specified in the $feature$ vector below. Then split into training and test. Which features are you going to select ?" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [], "source": [ "#to make the plot we need to reduce the data to 2D, so we choose two features\n", "features_list = ['height', 'weight', 'age']\n", "labels_list = ['Center', 'Point guard']\n", "\n", "index_feature1 = 0 # we choose height\n", "index_feature2 = 1 # and weight (age of course is not very meaningful)\n", "features = [index_feature1, index_feature2]\n", "\n", "feature_name0 = features_list[features[0]]\n", "feature_name1 = features_list[features[1]]\n", "\n", "X_reduced = X[:,features]\n", "\n", "X_training = X_reduced[:m_training,]\n", "Y_training = Y[:m_training]\n", "\n", "X_test = X_reduced[m_training:,]\n", "Y_test = Y[m_training:]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now learn a model using the training data and measure the performances." ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Error rate on test set: 0.0641025641025641\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "C:\\Users\\Anay Deshpande\\Anaconda3\\lib\\site-packages\\sklearn\\linear_model\\logistic.py:432: FutureWarning: Default solver will be changed to 'lbfgs' in 0.22. Specify a solver to silence this warning.\n", " FutureWarning)\n" ] } ], "source": [ "# learning from training data\n", "logreg.fit(X_training, Y_training)\n", "\n", "#print the error rate = fraction of misclassified samples\n", "error_rate_test = 0\n", "for i in range(len(Y_test)):\n", " if predicted_test[i]!=Y_test[i]:\n", " error_rate_test += 1\n", "error_rate_test = error_rate_test / m_test\n", "print(\"Error rate on test set: \" + str(error_rate_test))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**TO DO** [Answer the following] Which features did you select and why ? Compare the perfromances with the ones of the case with all the 3 features and comment about the results. [Write the answer in this cell]\n", "\n", "**ANSWER QUESTION 3**" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If everything is ok, the code below uses the model in $logreg$ to plot the decision region for the two features chosen above, with colors denoting the predicted value. It also plots the points (with correct labels) in the training set. It makes a similar plot for the test set." ] }, { "cell_type": "code", "execution_count": 26, "metadata": { "scrolled": true }, "outputs": [ { "data": { "application/javascript": [ "/* Put everything inside the global mpl namespace */\n", "window.mpl = {};\n", "\n", "\n", "mpl.get_websocket_type = function() {\n", " if (typeof(WebSocket) !== 'undefined') {\n", " return WebSocket;\n", " } else if (typeof(MozWebSocket) !== 'undefined') {\n", " return MozWebSocket;\n", " } else {\n", " alert('Your browser does not have WebSocket support. ' +\n", " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", " 'Firefox 4 and 5 are also supported but you ' +\n", " 'have to enable WebSockets in about:config.');\n", " };\n", "}\n", "\n", "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", " this.id = figure_id;\n", "\n", " this.ws = websocket;\n", "\n", " this.supports_binary = (this.ws.binaryType != undefined);\n", "\n", " if (!this.supports_binary) {\n", " var warnings = document.getElementById(\"mpl-warnings\");\n", " if (warnings) {\n", " warnings.style.display = 'block';\n", " warnings.textContent = (\n", " \"This browser does not support binary websocket messages. \" +\n", " \"Performance may be slow.\");\n", " }\n", " }\n", "\n", " this.imageObj = new Image();\n", "\n", " this.context = undefined;\n", " this.message = undefined;\n", " this.canvas = undefined;\n", " this.rubberband_canvas = undefined;\n", " this.rubberband_context = undefined;\n", " this.format_dropdown = undefined;\n", "\n", " this.image_mode = 'full';\n", "\n", " this.root = $('
');\n", " this._root_extra_style(this.root)\n", " this.root.attr('style', 'display: inline-block');\n", "\n", " $(parent_element).append(this.root);\n", "\n", " this._init_header(this);\n", " this._init_canvas(this);\n", " this._init_toolbar(this);\n", "\n", " var fig = this;\n", "\n", " this.waiting = false;\n", "\n", " this.ws.onopen = function () {\n", " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", " fig.send_message(\"send_image_mode\", {});\n", " if (mpl.ratio != 1) {\n", " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n", " }\n", " fig.send_message(\"refresh\", {});\n", " }\n", "\n", " this.imageObj.onload = function() {\n", " if (fig.image_mode == 'full') {\n", " // Full images could contain transparency (where diff images\n", " // almost always do), so we need to clear the canvas so that\n", " // there is no ghosting.\n", " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", " }\n", " fig.context.drawImage(fig.imageObj, 0, 0);\n", " };\n", "\n", " this.imageObj.onunload = function() {\n", " fig.ws.close();\n", " }\n", "\n", " this.ws.onmessage = this._make_on_message_function(this);\n", "\n", " this.ondownload = ondownload;\n", "}\n", "\n", "mpl.figure.prototype._init_header = function() {\n", " var titlebar = $(\n", " '
');\n", " var titletext = $(\n", " '
');\n", " titlebar.append(titletext)\n", " this.root.append(titlebar);\n", " this.header = titletext[0];\n", "}\n", "\n", "\n", "\n", "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", "\n", "}\n", "\n", "\n", "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", "\n", "}\n", "\n", "mpl.figure.prototype._init_canvas = function() {\n", " var fig = this;\n", "\n", " var canvas_div = $('
');\n", "\n", " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", "\n", " function canvas_keyboard_event(event) {\n", " return fig.key_event(event, event['data']);\n", " }\n", "\n", " canvas_div.keydown('key_press', canvas_keyboard_event);\n", " canvas_div.keyup('key_release', canvas_keyboard_event);\n", " this.canvas_div = canvas_div\n", " this._canvas_extra_style(canvas_div)\n", " this.root.append(canvas_div);\n", "\n", " var canvas = $('');\n", " canvas.addClass('mpl-canvas');\n", " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", "\n", " this.canvas = canvas[0];\n", " this.context = canvas[0].getContext(\"2d\");\n", "\n", " var backingStore = this.context.backingStorePixelRatio ||\n", "\tthis.context.webkitBackingStorePixelRatio ||\n", "\tthis.context.mozBackingStorePixelRatio ||\n", "\tthis.context.msBackingStorePixelRatio ||\n", "\tthis.context.oBackingStorePixelRatio ||\n", "\tthis.context.backingStorePixelRatio || 1;\n", "\n", " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", "\n", " var rubberband = $('');\n", " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", "\n", " var pass_mouse_events = true;\n", "\n", " canvas_div.resizable({\n", " start: function(event, ui) {\n", " pass_mouse_events = false;\n", " },\n", " resize: function(event, ui) {\n", " fig.request_resize(ui.size.width, ui.size.height);\n", " },\n", " stop: function(event, ui) {\n", " pass_mouse_events = true;\n", " fig.request_resize(ui.size.width, ui.size.height);\n", " },\n", " });\n", "\n", " function mouse_event_fn(event) {\n", " if (pass_mouse_events)\n", " return fig.mouse_event(event, event['data']);\n", " }\n", "\n", " rubberband.mousedown('button_press', mouse_event_fn);\n", " rubberband.mouseup('button_release', mouse_event_fn);\n", " // Throttle sequential mouse events to 1 every 20ms.\n", " rubberband.mousemove('motion_notify', mouse_event_fn);\n", "\n", " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", "\n", " canvas_div.on(\"wheel\", function (event) {\n", " event = event.originalEvent;\n", " event['data'] = 'scroll'\n", " if (event.deltaY < 0) {\n", " event.step = 1;\n", " } else {\n", " event.step = -1;\n", " }\n", " mouse_event_fn(event);\n", " });\n", "\n", " canvas_div.append(canvas);\n", " canvas_div.append(rubberband);\n", "\n", " this.rubberband = rubberband;\n", " this.rubberband_canvas = rubberband[0];\n", " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", " this.rubberband_context.strokeStyle = \"#000000\";\n", "\n", " this._resize_canvas = function(width, height) {\n", " // Keep the size of the canvas, canvas container, and rubber band\n", " // canvas in synch.\n", " canvas_div.css('width', width)\n", " canvas_div.css('height', height)\n", "\n", " canvas.attr('width', width * mpl.ratio);\n", " canvas.attr('height', height * mpl.ratio);\n", " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", "\n", " rubberband.attr('width', width);\n", " rubberband.attr('height', height);\n", " }\n", "\n", " // Set the figure to an initial 600x600px, this will subsequently be updated\n", " // upon first draw.\n", " this._resize_canvas(600, 600);\n", "\n", " // Disable right mouse context menu.\n", " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", " return false;\n", " });\n", "\n", " function set_focus () {\n", " canvas.focus();\n", " canvas_div.focus();\n", " }\n", "\n", " window.setTimeout(set_focus, 100);\n", "}\n", "\n", "mpl.figure.prototype._init_toolbar = function() {\n", " var fig = this;\n", "\n", " var nav_element = $('
');\n", " nav_element.attr('style', 'width: 100%');\n", " this.root.append(nav_element);\n", "\n", " // Define a callback function for later on.\n", " function toolbar_event(event) {\n", " return fig.toolbar_button_onclick(event['data']);\n", " }\n", " function toolbar_mouse_event(event) {\n", " return fig.toolbar_button_onmouseover(event['data']);\n", " }\n", "\n", " for(var toolbar_ind in mpl.toolbar_items) {\n", " var name = mpl.toolbar_items[toolbar_ind][0];\n", " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", " var image = mpl.toolbar_items[toolbar_ind][2];\n", " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", "\n", " if (!name) {\n", " // put a spacer in here.\n", " continue;\n", " }\n", " var button = $('