diff --git a/.gitignore b/.gitignore index 763513e..32b46f9 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ .ipynb_checkpoints +.idea + diff --git a/exercise.ipynb b/exercise/exercise.ipynb similarity index 79% rename from exercise.ipynb rename to exercise/exercise.ipynb index 8fa65e3..79151af 100644 --- a/exercise.ipynb +++ b/exercise/exercise.ipynb @@ -25,10 +25,17 @@ "\n", "\n", "### (3) 判断\n", - "企业发放的奖金根据利润提成。利润(I): 低于或等于 10 万元时,奖金可提 10%; 高于 10 万元,低于 20 万元时,低于 10 万元的部分按 10%提成,高于 10 万元的部分,可提成 7.5%; 20 万到 40 万之间时,高于 20 万元的部分,可提成 5%; 40 万到 60 万之间时,高于 40 万元的部分,可提成 3%; 60 万到 100 万之间时,高于 60 万元的部分,可提成 1.5%, 高于 100 万元时, 超过 100 万元的部分按 1%提成, 从键盘输入当月利润 I,求应发放奖金总数?\n", + "企业发放的奖金根据利润提成。利润(I): \n", + "* 低于或等于 10 万元时,奖金可提 10%; \n", + "* 高于 10 万元,低于 20 万元时,低于 10 万元的部分按 10%提成,高于 10 万元的部分,可提成 7.5%; \n", + "* 20 万到 40 万之间时,高于 20 万元的部分,可提成 5%; \n", + "* 40 万到 60 万之间时,高于 40 万元的部分,可提成 3%; \n", + "* 60 万到 100 万之间时,高于 60 万元的部分,可提成 1.5%, \n", + "* 高于 100 万元时, 超过 100 万元的部分按 1%提成, \n", + "从键盘输入当月利润 I,求应发放奖金总数?\n", "\n", "### (4)循环\n", - "输出9x9的口诀表\n", + "输出9x9的乘法口诀表\n", "\n", "### (5)算法\n", "给一个数字列表,将其按照由大到小的顺序排列\n", @@ -48,7 +55,7 @@ "例如把`c:`下面所有的`.dll`文件找到\n", "\n", "### (8)应用3\n", - "你还有个目录,里面是程序(假如是C或者是Python),统计一下你写过多少行代码。包括空行和注释,但是要分别列出来。\n", + "你有个目录,里面是程序(假如是C或者是Python),统计一下你写过多少行代码。包括空行和注释,但是要分别列出来。\n", "\n" ] }, diff --git a/kmeans/k-means.ipynb b/kmeans/k-means.ipynb index 4856a7a..18b0838 100644 --- a/kmeans/k-means.ipynb +++ b/kmeans/k-means.ipynb @@ -414,6 +414,7 @@ } ], "metadata": { + "jupytext_formats": "ipynb,py", "kernelspec": { "display_name": "Python 3", "language": "python", diff --git a/kmeans/k-means.py b/kmeans/k-means.py index 6a40b67..cd69f96 100755 --- a/kmeans/k-means.py +++ b/kmeans/k-means.py @@ -1,3 +1,33 @@ +# -*- coding: utf-8 -*- +# --- +# jupyter: +# jupytext_format_version: '1.2' +# jupytext_formats: ipynb,py +# kernelspec: +# display_name: Python 3 +# language: python +# name: python3 +# language_info: +# codemirror_mode: +# name: ipython +# version: 3 +# file_extension: .py +# mimetype: text/x-python +# name: python +# nbconvert_exporter: python +# pygments_lexer: ipython3 +# version: 3.5.2 +# --- + +# # k-means demo + +# + +# This line configures matplotlib to show figures embedded in the notebook, +# instead of opening a new window for each figure. More about that later. +# If you are using an old version of IPython, try using '%pylab inline' instead. +# %matplotlib inline + +# import librarys from numpy import * import matplotlib.pyplot as plt import pandas as pd @@ -7,12 +37,36 @@ names = ['sepal-length', 'sepal-width', 'petal-length', 'petal-width', 'class'] dataset = pd.read_csv("iris.csv", header=0, index_col=0) dataset.head() +# - + #对类别进行编码,3个类别分别赋值0,1,2 dataset['class'][dataset['class']=='Iris-setosa']=0 dataset['class'][dataset['class']=='Iris-versicolor']=1 dataset['class'][dataset['class']=='Iris-virginica']=2 +def originalDatashow(dataSet): + #绘制原始的样本点 + num,dim=shape(dataSet) + marksamples=['ob'] #样本图形标记 + for i in range(num): + plt.plot(datamat.iat[i,0],datamat.iat[i,1],marksamples[0],markersize=5) + plt.title('original dataset') + plt.xlabel('sepal length') + plt.ylabel('sepal width') + plt.show() + + +# + {"scrolled": true} +#获取样本数据 +datamat = dataset.loc[:, ['sepal-length', 'sepal-width']] +# 真实的标签 +labels = dataset.loc[:, ['class']] +#原始数据显示 +originalDatashow(datamat) + + +# - def randChosenCent(dataSet,k): """初始化聚类中心:通过在区间范围随机产生的值作为新的中心点""" @@ -34,6 +88,8 @@ def randChosenCent(dataSet,k): centroids = dataSet.iloc[centroidsIndex] return mat(centroids) +# + + def distEclud(vecA, vecB): """算距离, 两个向量间欧式距离""" return sqrt(sum(power(vecA - vecB, 2))) #la.norm(vecA-vecB) @@ -91,9 +147,13 @@ def kMeans(dataSet, k): centroids[cent, :] = mean(ptsInClust, axis=0) return centroids, clusterAssment +# - +# 进行k-means聚类 +k = 3 # 用户定义聚类数 +mycentroids, clusterAssment = kMeans(datamat, k) -# 2维数据聚类效果显示 +# + def datashow(dataSet, k, centroids, clusterAssment): # 二维空间显示聚类结果 from matplotlib import pyplot as plt num, dim = shape(dataSet) # 样本数num ,维数dim @@ -123,8 +183,8 @@ def datashow(dataSet, k, centroids, clusterAssment): # 二维空间显示聚类 plt.title('k-means cluster result') # 标题 plt.show() - - + + # 画出实际图像 def trgartshow(dataSet, k, labels): from matplotlib import pyplot as plt @@ -139,48 +199,17 @@ def trgartshow(dataSet, k, labels): plt.plot(datamat.iat[i, 0], datamat.iat[i, 1], marksamples[int(labels.iat[i, 0])], markersize=6, label=label[int(labels.iat[i, 0])]) plt.legend(loc='upper left') + # 添加轴标签和标题 - plt.xlabel('sepal length') plt.ylabel('sepal width') - plt.title('iris true result') # 标题 # 显示图形 plt.show() # label=labels.iat[i,0] +# - - -def originalDatashow(dataSet): - """聚类前,绘制原始的样本点""" - - #样本的个数和特征维数 - num,dim=shape(dataSet) - marksamples=['ob'] #样本图形标记 - for i in range(num): - plt.plot(datamat.iat[i,0],datamat.iat[i,1],marksamples[0],markersize=5) - plt.title('original dataset') - plt.xlabel('sepal length') - plt.ylabel('sepal width') #标题 - plt.show() - - -if __name__ == '__main__': - # 获取样本数据 - datamat = dataset.loc[:, ['sepal-length', 'sepal-width']] - # 真实的标签 - labels = dataset.loc[:, ['class']] - # 原始数据显示 - originalDatashow(datamat) - - # kmeans聚类 - k = 3 # 用户定义聚类数 - mycentroids, clusterAssment = kMeans(datamat, k) - - # 绘图显示 - datashow(datamat, k, mycentroids, clusterAssment) - trgartshow(datamat, 3, labels) - # plt.show() - - - +# 绘图显示 +datashow(datamat, k, mycentroids, clusterAssment) +trgartshow(datamat, 3, labels) diff --git a/logistic_regression/Least_squares.ipynb b/logistic_regression/Least_squares.ipynb new file mode 100644 index 0000000..7cba3ac --- /dev/null +++ b/logistic_regression/Least_squares.ipynb @@ -0,0 +1,186 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Linear regression\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Least squares\n", + "\n", + "A mathematical procedure for finding the best-fitting curve to a given set of points by minimizing the sum of the squares of the offsets (\"the residuals\") of the points from the curve. The sum of the squares of the offsets is used instead of the offset absolute values because this allows the residuals to be treated as a continuous differentiable quantity. However, because squares of the offsets are used, outlying points can have a disproportionate effect on the fit, a property which may or may not be desirable depending on the problem at hand. \n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Show the data\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "%matplotlib inline\n", + "\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "import sklearn\n", + "from sklearn import datasets\n", + "\n", + "# load data\n", + "d = datasets.load_diabetes()\n", + "\n", + "X = d.data[:, 2]\n", + "Y = d.target\n", + "\n", + "# draw original data\n", + "plt.scatter(X, Y)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Theory\n", + "For $N$ observation data:\n", + "$$\n", + "\\mathbf{X} = \\{x_1, x_2, ..., x_N \\} \\\\\n", + "\\mathbf{Y} = \\{y_1, y_2, ..., y_N \\}\n", + "$$\n", + "\n", + "We want to find the model which can predict the data. The simplest model is linear model, which has the form of \n", + "$$\n", + "y = ax + b\n", + "$$\n", + "\n", + "The purpose is to find parameters $a, b$ which best fit the model to the observation data. \n", + "\n", + "We use the sum of squares to measure the differences (loss function) between the model's prediction and observation data:\n", + "$$\n", + "L = \\sum_{i=1}^{N} (y_i - a x_i + b)^2\n", + "$$\n", + "\n", + "To make the loss function minimize, we can find the parameters:\n", + "$$\n", + "\\frac{\\partial L}{\\partial a} = -2 \\sum_{i=1}^{N} (y_i - a x_i - b) x_i \\\\\n", + "\\frac{\\partial L}{\\partial b} = -2 \\sum_{i=1}^{N} (y_i - a x_i - b)\n", + "$$\n", + "When the loss is minimized, therefore the partial difference is zero, then we can get:\n", + "$$\n", + "-2 \\sum_{i=1}^{N} (y_i - a x_i - b) x_i = 0 \\\\\n", + "-2 \\sum_{i=1}^{N} (y_i - a x_i - b) = 0 \\\\\n", + "$$\n", + "\n", + "We reoder the items as:\n", + "$$\n", + "a \\sum x_i^2 + b \\sum x_i = \\sum y_i x_i \\\\\n", + "a \\sum x_i + b N = \\sum y_i\n", + "$$\n", + "By solving the linear equation we can obtain the model parameters." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Program" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "a = 949.435260, b = 152.133484\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "N = X.shape[0]\n", + "\n", + "S_X2 = np.sum(X*X)\n", + "S_X = np.sum(X)\n", + "S_XY = np.sum(X*Y)\n", + "S_Y = np.sum(Y)\n", + "\n", + "A1 = np.array([[S_X2, S_X], \n", + " [S_X, N]])\n", + "B1 = np.array([S_XY, S_Y])\n", + "\n", + "coeff = np.linalg.inv(A1).dot(B1)\n", + "\n", + "print('a = %f, b = %f' % (coeff[0], coeff[1]))\n", + "\n", + "x_min = np.min(X)\n", + "x_max = np.max(X)\n", + "y_min = coeff[0] * x_min + coeff[1]\n", + "y_max = coeff[0] * x_max + coeff[1]\n", + "\n", + "plt.scatter(X, Y)\n", + "plt.plot([x_min, x_max], [y_min, y_max], 'r')\n", + "plt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.5.2" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/logistic_regression/Least_squares.py b/logistic_regression/Least_squares.py new file mode 100644 index 0000000..bb99f64 --- /dev/null +++ b/logistic_regression/Least_squares.py @@ -0,0 +1,113 @@ +# --- +# jupyter: +# jupytext_format_version: '1.2' +# kernelspec: +# display_name: Python 3 +# language: python +# name: python3 +# language_info: +# codemirror_mode: +# name: ipython +# version: 3 +# file_extension: .py +# mimetype: text/x-python +# name: python +# nbconvert_exporter: python +# pygments_lexer: ipython3 +# version: 3.5.2 +# --- + +# # Linear regression +# +# + +# ## Least squares +# +# A mathematical procedure for finding the best-fitting curve to a given set of points by minimizing the sum of the squares of the offsets ("the residuals") of the points from the curve. The sum of the squares of the offsets is used instead of the offset absolute values because this allows the residuals to be treated as a continuous differentiable quantity. However, because squares of the offsets are used, outlying points can have a disproportionate effect on the fit, a property which may or may not be desirable depending on the problem at hand. +# + +# ### Show the data +# + +# + +# %matplotlib inline + +import matplotlib.pyplot as plt +import numpy as np +import sklearn +from sklearn import datasets + +# load data +d = datasets.load_diabetes() + +X = d.data[:, 2] +Y = d.target + +# draw original data +plt.scatter(X, Y) +plt.show() +# - + +# ### Theory +# For $N$ observation data: +# $$ +# \mathbf{X} = \{x_1, x_2, ..., x_N \} \\ +# \mathbf{Y} = \{y_1, y_2, ..., y_N \} +# $$ +# +# We want to find the model which can predict the data. The simplest model is linear model, which has the form of +# $$ +# y = ax + b +# $$ +# +# The purpose is to find parameters $a, b$ which best fit the model to the observation data. +# +# We use the sum of squares to measure the differences (loss function) between the model's prediction and observation data: +# $$ +# L = \sum_{i=1}^{N} (y_i - a x_i + b)^2 +# $$ +# +# To make the loss function minimize, we can find the parameters: +# $$ +# \frac{\partial L}{\partial a} = -2 \sum_{i=1}^{N} (y_i - a x_i - b) x_i \\ +# \frac{\partial L}{\partial b} = -2 \sum_{i=1}^{N} (y_i - a x_i - b) +# $$ +# When the loss is minimized, therefore the partial difference is zero, then we can get: +# $$ +# -2 \sum_{i=1}^{N} (y_i - a x_i - b) x_i = 0 \\ +# -2 \sum_{i=1}^{N} (y_i - a x_i - b) = 0 \\ +# $$ +# +# We reoder the items as: +# $$ +# a \sum x_i^2 + b \sum x_i = \sum y_i x_i \\ +# a \sum x_i + b N = \sum y_i +# $$ +# By solving the linear equation we can obtain the model parameters. + +# ### Program + +# + +N = X.shape[0] + +S_X2 = np.sum(X*X) +S_X = np.sum(X) +S_XY = np.sum(X*Y) +S_Y = np.sum(Y) + +A1 = np.array([[S_X2, S_X], + [S_X, N]]) +B1 = np.array([S_XY, S_Y]) + +coeff = np.linalg.inv(A1).dot(B1) + +print('a = %f, b = %f' % (coeff[0], coeff[1])) + +x_min = np.min(X) +x_max = np.max(X) +y_min = coeff[0] * x_min + coeff[1] +y_max = coeff[0] * x_max + coeff[1] + +plt.scatter(X, Y) +plt.plot([x_min, x_max], [y_min, y_max], 'r') +plt.show() diff --git a/logistic_regression/linear_regression.py b/logistic_regression/linear_regression.py new file mode 100644 index 0000000..5fd5d7d --- /dev/null +++ b/logistic_regression/linear_regression.py @@ -0,0 +1,66 @@ + +import matplotlib.pyplot as plt +import numpy as np +import sklearn +from sklearn import datasets + +# load data +d = datasets.load_diabetes() + +X = d.data[:, 2] +Y = d.target + +# draw original data +plt.scatter(X, Y) +plt.show() + + +############################################################################### +# Least squares +############################################################################### + +# L = \sum_{i=1, N} (y_i - a*x_i - b)^2 +N = X.shape[0] + +S_X2 = np.sum(X*X) +S_X = np.sum(X) +S_XY = np.sum(X*Y) +S_Y = np.sum(Y) + +A1 = np.array([[S_X2, S_X], [S_X, N]]) +B1 = np.array([S_XY, S_Y]) + +coeff = np.linalg.inv(A1).dot(B1) + +x_min = np.min(X) +x_max = np.max(X) +y_min = coeff[0] * x_min + coeff[1] +y_max = coeff[0] * x_max + coeff[1] + +plt.scatter(X, Y) +plt.plot([x_min, x_max], [y_min, y_max], 'r') +plt.show() + + +############################################################################### +# Linear regression +############################################################################### +# the loss function +# L = \sum_{i=1, N} (y_i - a*x_i - b)^2 + +n_train = 1000 + + +a, b = 1, 1 +epsilon = 0.001 + +for i in range(n_train): + for j in range(N): + a = a + epsilon*2*(Y[j] - a*X[j] - b)*X[j] + b = b + epsilon*2*(Y[j] - a*X[j] - b) + + L = 0 + for j in range(N): + L = L + (Y[j]-a*X[j]-b)**2 + print("epoch %4d: loss = %f" % (i, L)) + diff --git a/matplotlib/matplotlib_ani1.ipynb b/matplotlib/matplotlib_ani1.ipynb new file mode 100644 index 0000000..836badb --- /dev/null +++ b/matplotlib/matplotlib_ani1.ipynb @@ -0,0 +1,575 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Animation\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "%matplotlib inline\n", + "\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "from matplotlib import animation, rc\n", + "from IPython.display import HTML\n", + "\n", + "\n", + "# First set up the figure, the axis, and the plot element we want to animate\n", + "fig, ax = plt.subplots()\n", + "\n", + "ax.set_xlim(( 0, 2))\n", + "ax.set_ylim((-2, 2))\n", + "\n", + "line, = ax.plot([], [], lw=2)\n", + "\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\n", + "# initialization function: plot the background of each frame\n", + "def init():\n", + " line.set_data([], [])\n", + " return (line,)\n", + "\n", + "# animation function. This is called sequentially\n", + "def animate(i):\n", + " x = np.linspace(0, 2, 1000)\n", + " y = np.sin(2 * np.pi * (x - 0.01 * i))\n", + " line.set_data(x, y)\n", + " return (line,)\n", + "\n", + "# call the animator. blit=True means only re-draw the parts that have changed.\n", + "anim = animation.FuncAnimation(fig, animate, init_func=init,\n", + " frames=100, interval=20, blit=True)\n", + "\n", + "HTML(anim.to_html5_video())" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.5.2" + }, + "main_language": "python" + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/matplotlib/matplotlib_ani1.py b/matplotlib/matplotlib_ani1.py new file mode 100644 index 0000000..08e484f --- /dev/null +++ b/matplotlib/matplotlib_ani1.py @@ -0,0 +1,63 @@ +# --- +# jupyter: +# jupytext_format_version: '1.2' +# kernelspec: +# display_name: Python 3 +# language: python +# name: python3 +# language_info: +# codemirror_mode: +# name: ipython +# version: 3 +# file_extension: .py +# mimetype: text/x-python +# name: python +# nbconvert_exporter: python +# pygments_lexer: ipython3 +# version: 3.5.2 +# --- + +# ## Animation +# + +# + +# %matplotlib inline + +import numpy as np +import matplotlib.pyplot as plt + +from matplotlib import animation, rc +from IPython.display import HTML + + +# First set up the figure, the axis, and the plot element we want to animate +fig, ax = plt.subplots() + +ax.set_xlim(( 0, 2)) +ax.set_ylim((-2, 2)) + +line, = ax.plot([], [], lw=2) + + + + + +# + + +# initialization function: plot the background of each frame +def init(): + line.set_data([], []) + return (line,) + +# animation function. This is called sequentially +def animate(i): + x = np.linspace(0, 2, 1000) + y = np.sin(2 * np.pi * (x - 0.01 * i)) + line.set_data(x, y) + return (line,) + +# call the animator. blit=True means only re-draw the parts that have changed. +anim = animation.FuncAnimation(fig, animate, init_func=init, + frames=100, interval=20, blit=True) + +HTML(anim.to_html5_video()) diff --git a/matplotlib/matplotlib_ani2.ipynb b/matplotlib/matplotlib_ani2.ipynb new file mode 100644 index 0000000..b394366 --- /dev/null +++ b/matplotlib/matplotlib_ani2.ipynb @@ -0,0 +1,844 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "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 = $('