mirror of
https://github.com/LCTT/TranslateProject.git
synced 2024-12-26 21:30:55 +08:00
Merge remote-tracking branch 'LCTT/master'
This commit is contained in:
commit
a7ef13d90a
@ -1,40 +1,39 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12346-1.html)
|
||||
[#]: subject: (Import functions and variables into Bash with the source command)
|
||||
[#]: via: (https://opensource.com/article/20/6/bash-source-command)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
使用 source 命令将函数和变量导入 Bash
|
||||
======
|
||||
source 就像 Python 的 import 或者 Java 的 include。学习它扩展你的 Bash 能力。
|
||||
![bash logo on green background][1]
|
||||
|
||||
登录 Linux shell 时,你将继承特定的工作环境。对于 shell 而言,_环境_ (environment) 已经为你设置了某些变量,以确保你的命令按预期工作。例如,[PATH][2] 环境变量定义 shell 从哪里查找命令。没有它,几乎所有尝试在 Bash 中执行的所有操作都会因 **command not found** 错误而失败。在执行日常任务时,环境对你几乎是不可见的,但它很重要。
|
||||
> source 就像 Python 的 import 或者 Java 的 include。学习它来扩展你的 Bash 能力。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202006/24/235417tbzjpdbpbzkbjeul.jpg)
|
||||
|
||||
登录 Linux shell 时,你将继承特定的工作环境。对于 shell 而言,“<ruby>环境<rt>environment</rt></ruby>”意味着已经为你设置了某些变量,以确保你的命令可以按预期工作。例如,[PATH][2] 环境变量定义 shell 从哪里查找命令。没有它,几乎在 Bash 中尝试执行的所有操作都会因“命令未发现” 错误而失败。在执行日常任务时,环境对你几乎是不可见的,但它很重要。
|
||||
|
||||
有多种方法可以影响你的 shell 环境。你可以在配置文件中进行修改,例如 `~/.bashrc` 和 `~/.profile`,你可以在启动时运行服务,还可以创建自己的自定义命令或编写自己的 [Bash 函数][3] 。
|
||||
|
||||
### 通过 source 添加到你的环境
|
||||
|
||||
Bash(以及其他一些 shell)有一个称为 `source` 的内置命令。这就是令人困惑的地方:`source` 执行与命令 `.` 相同的功能(是的,那只是一个点),而与 `Tcl` 命令的 `source` 不是同一个(如果你输入 `man source`,也许在屏幕上显示的是它)。实际上,内置的 `source` 命令根本不在你的 `PATH` 中。这是 Bash 附带的命令,要获取有关它的更多信息,可以输入 `help source`。
|
||||
|
||||
Bash(以及其他一些 shell)有一个称为 `source` 的内置命令。这就是令人困惑的地方:`source` 执行与命令 `.` 相同的功能(是的,那只是一个点),而__不是_与 `Tcl` 命令相同的 `source`(如果你输入 `man source`,可能会在屏幕上显示)。实际上,内置的 `source` 命令根本不在你的 `PATH` 中。这是 Bash 附带的命令,要获取有关它的更多信息,可以输入 `help source`。
|
||||
`.` 命令兼容 [POSIX][4]。 但 `source` 命令不是 POSIX 定义的,但可以与 `.` 命令互换使用。
|
||||
|
||||
`.` 命令兼容 [POSIX][4]。 但 `source` 命令不是 POSIX 定义的,但可以与 `.` 命令互换。
|
||||
|
||||
根据 Bash `help`,`source` 命令在你当前的 shell 中执行一个文件。 “在你当前的 shell 中”这句很重要,因为它表示它不会启动子 shell。因此,用 `source` 执行的任何操作都发生在内部并影响_当前_环境。
|
||||
|
||||
在探讨 `source` 对环境的影响之前,请在测试文件上尝试 `source` 以确保其按预期执行代码。首先,创建一个简单的 Bash 脚本并将其保存为 `hello.sh`:
|
||||
根据 Bash `help`,`source` 命令在你当前的 shell 中执行一个文件。 “在你当前的 shell 中” 这句很重要,因为它表示它不会启动子 shell。因此,用 `source` 执行的任何操作都发生在内部并影响*当前*环境。
|
||||
|
||||
在探讨 `source` 对环境的影响之前,请用 `source` 命令导入一个测试文件,以确保其按预期执行代码。首先,创建一个简单的 Bash 脚本并将其保存为 `hello.sh`:
|
||||
|
||||
```
|
||||
#!/usr/bin/env bash
|
||||
echo "hello world"
|
||||
```
|
||||
|
||||
使用 `source`,即使不设置可执行也可以运行此脚本:
|
||||
|
||||
使用 `source`,即使该脚本不设置可执行也可以运行:
|
||||
|
||||
```
|
||||
$ source hello.sh
|
||||
@ -43,21 +42,19 @@ hello world
|
||||
|
||||
你也可以使用内置的 `.` 命令获得相同的结果:
|
||||
|
||||
|
||||
```
|
||||
$ . hello.sh
|
||||
hello world
|
||||
```
|
||||
|
||||
`source` 和 `.` 命令成功执行测试文件的内容。
|
||||
`source` 和 `.` 命令成功地执行了测试文件的内容。
|
||||
|
||||
### 设置变量和导入函数
|
||||
|
||||
你可以使用 `source` 将文件“导入”到 shell 环境中,就像你可以在 C 或 C++ 中使用 `include` 关键字引用一个库,或者在 Python 中使用 `import` 关键字引入一个模块一样。这是 `source` 的最常见用法之一,它也是 `.bashrc` 中的一个默认包含项,通过 `source` 导入 `.bash_aliases` 来将任何你自定义的别名在登录时导入。
|
||||
你可以使用 `source` 将文件 “导入” 到 shell 环境中,就像你可以在 C 或 C++ 中使用 `include` 关键字引用一个库,或者在 Python 中使用 `import` 关键字引入一个模块一样。这是 `source` 的最常见用法之一,它也是 `.bashrc` 中的一个默认包含方式,通过 `source` 导入 `.bash_aliases`,以便将任何你自定义的别名在登录时导入到你的环境。
|
||||
|
||||
这是导入 Bash 函数的示例。首先,在名为 `myfunctions` 的文件中创建一个函数。它将打印你的公共 IP 地址和本地 IP 地址:
|
||||
|
||||
|
||||
```
|
||||
function myip() {
|
||||
curl <http://icanhazip.com>
|
||||
@ -70,16 +67,14 @@ function myip() {
|
||||
}
|
||||
```
|
||||
|
||||
将函数导入你的 shell:
|
||||
|
||||
将该函数导入你的 shell:
|
||||
|
||||
```
|
||||
`$ source myfunctions`
|
||||
$ source myfunctions
|
||||
```
|
||||
|
||||
测试新函数:
|
||||
|
||||
|
||||
```
|
||||
$ myip
|
||||
93.184.216.34
|
||||
@ -88,16 +83,15 @@ inet6 fbd4:e85f:49c:2121:ce12:ef79:0e77:59d1
|
||||
inet 10.8.42.38
|
||||
```
|
||||
|
||||
### source 搜索
|
||||
### source 的搜索
|
||||
|
||||
当你在Bash中使用 `source` 时,它将在当前目录中搜索你引用的文件。但并非所有 shell 都这样,因此,如果你不使用 Bash,请查看文档。
|
||||
当你在 Bash 中使用 `source` 时,它将在当前目录中搜索你引用的文件。但并非所有 shell 都这样,因此,如果你不使用 Bash,请查看文档。
|
||||
|
||||
如果 Bash 找不到要执行的文件,它将搜索你的 `PATH`。同样,这并不是所有 shell 的默认设置,因此,如果你不使用 Bash,请查看文档。
|
||||
|
||||
这些都是 Bash 中不错的便利功能。这种出奇地强大,因为它允许你将常用函数保存在磁盘上的一个集中位置,然后将你的环境视为集成开发环境 (IDE)。你不必担心函数的存储位置,因为你知道它们在本地等同于在 `/usr/include` 下,因此无论你在哪,当你 source 过它们,Bash 都可以找到它们。
|
||||
|
||||
例如,你可以创建一个名为 `~/.local/include` 的目录作为常见函数存储区,然后将此代码块放入 .bashrc 文件中:
|
||||
这些都是 Bash 中不错的便利功能。这种出奇地强大,因为它允许你将常用函数保存在磁盘上的一个集中的位置,然后将你的环境视为集成开发环境 (IDE)。你不必担心函数的存储位置,因为你知道它们在你的本地位置等同于在 `/usr/include` 下,因此无论你在哪,当你导入它们时,Bash 都可以找到它们。
|
||||
|
||||
例如,你可以创建一个名为 `~/.local/include` 的目录作为常见函数存储区,然后将此代码块放入 `.bashrc` 文件中:
|
||||
|
||||
```
|
||||
for i in $HOME/.local/include/*;
|
||||
@ -111,7 +105,7 @@ done
|
||||
|
||||
### 将 source 用于开源
|
||||
|
||||
使用 `source` 或 `.` 执行文件是影响环境同时保持变更模块化的一种便捷方法。在下次考虑将大量代码复制并粘贴到 .bashrc 文件中时,请考虑将相关函数或别名组放入专用文件中,然后使用 source 获取它们。
|
||||
使用 `source` 或 `.` 来执行文件是影响环境同时保持变更模块化的一种便捷方法。在下次考虑将大量代码复制并粘贴到 `.bashrc` 文件中时,请考虑将相关函数或别名组放入专用文件中,然后使用 `source` 导入它们。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@ -120,7 +114,7 @@ via: https://opensource.com/article/20/6/bash-source-command
|
||||
作者:[Seth Kenlon][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -1,5 +1,5 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: translator: ( nophDog)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
@ -0,0 +1,450 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (A surprising way to do data science with Node.js)
|
||||
[#]: via: (https://opensource.com/article/20/6/server-side-data-science-nodejs)
|
||||
[#]: author: (Cristiano L. Fontana https://opensource.com/users/cristianofontana)
|
||||
|
||||
A surprising way to do data science with Node.js
|
||||
======
|
||||
Do a common data science task with Node.js and D3.js.
|
||||
![Computer screen with files or windows open][1]
|
||||
|
||||
[JavaScript][2] (also known as JS) is the [lingua franca][3] of the web, as it is supported by all the major web browsers—the other languages that run in browsers are [transpiled][4] (or translated) to JavaScript. Sometimes JS [can be confusing][5], but I find it pleasant to use because I try to stick to the [good parts][6]. JavaScript was created to run in a browser, but it can also be used in other contexts, such as an [embedded language][7] or for [server-side applications][8].
|
||||
|
||||
In this tutorial, I will explain how to write a program that will run in Node.js, which is a runtime environment that can execute JavaScript applications. What I like the most about Node.js is its [event-driven architecture][9] for [asynchronous programming][10]. With this approach, functions (aka callbacks) can be attached to certain events; when the attached event occurs, the callback executes. This way, the developer does not have to write a main loop because the runtime takes care of that.
|
||||
|
||||
JavaScript also has new [async functions][11] that use a different syntax, but I think they hide the event-driven architecture too well to use them in a how-to article. So, in this tutorial, I will use the traditional callbacks approach, even though it is not necessary for this case.
|
||||
|
||||
### Understanding the program task
|
||||
|
||||
The program task in this tutorial is to:
|
||||
|
||||
* Read some data from a [CSV file][12] that contains the [Anscombe's quartet][13] dataset
|
||||
* Interpolate the data with a straight line (i.e., _f(x) = m·x + q_)
|
||||
* Plot the result to an image file
|
||||
|
||||
|
||||
|
||||
For more details about this task, you can read the previous articles in this series, which do the same task in [Python and GNU Octave][14] and [C and C++][15]. The full source code for all the examples is available in my [polyglot_fit repository][16] on GitLab.
|
||||
|
||||
### Installing
|
||||
|
||||
Before you can run this example, you must install Node.js and its package manager [npm][17]. To install them on [Fedora][18], run:
|
||||
|
||||
|
||||
```
|
||||
`$ sudo dnf install nodejs npm`
|
||||
```
|
||||
|
||||
On Ubuntu:
|
||||
|
||||
|
||||
```
|
||||
`$ sudo apt install nodejs npm`
|
||||
```
|
||||
|
||||
Next, use `npm` to install the required packages. Packages are installed in a local [`node_modules` subdirectory][19], so Node.js can search for packages in that folder. The required packages are:
|
||||
|
||||
* [CSV Parse][20] for parsing the CSV file
|
||||
* [Simple Statistics][21] for calculating the data correlation factor
|
||||
* [Regression-js][22] for determining the fitting line
|
||||
* [D3-Node][23] for server-side plotting
|
||||
|
||||
|
||||
|
||||
Run npm to install the packages:
|
||||
|
||||
|
||||
```
|
||||
`$ npm install csv-parse simple-statistics regression d3-node`
|
||||
```
|
||||
|
||||
### Commenting code
|
||||
|
||||
Just like in C, in JavaScript, you can insert [comments][24] by putting `//` before your comment, and the interpreter will discard the rest of the line. Another option: JavaScript will discard anything between `/*` and `*/`:
|
||||
|
||||
|
||||
```
|
||||
// This is a comment ignored by the interpreter.
|
||||
/* Also this is ignored */
|
||||
```
|
||||
|
||||
### Loading modules
|
||||
|
||||
You can load modules with the [`require()` function][25]. The function returns an object that contains a module's functions:
|
||||
|
||||
|
||||
```
|
||||
const EventEmitter = require('events');
|
||||
const fs = require('fs');
|
||||
const csv = require('csv-parser');
|
||||
const regression = require('regression');
|
||||
const ss = require('simple-statistics');
|
||||
const D3Node = require('d3-node');
|
||||
```
|
||||
|
||||
Some of these modules are part of the Node.js standard library, so you do not need to install them with npm.
|
||||
|
||||
### Defining variables
|
||||
|
||||
Variables do not have to be declared before they are used, but if they are used without a declaration, they will be defined as global variables. Generally, global variables are considered bad practice, as they could lead to [bugs][26] if they're used carelessly. To declare a variable, you can use the [var][27], [let][28], and [const][29] statements. Variables can contain any kind of data (even functions!). You can create some objects by applying the [`new` operator][30] to a constructor function:
|
||||
|
||||
|
||||
```
|
||||
const inputFileName = "anscombe.csv";
|
||||
const delimiter = "\t";
|
||||
const skipHeader = 3;
|
||||
const columnX = String(0);
|
||||
const columnY = String(1);
|
||||
|
||||
const d3n = new D3Node();
|
||||
const d3 = d3n.d3;
|
||||
|
||||
var data = [];
|
||||
```
|
||||
|
||||
Data read from the CSV file is stored in the `data` array. Arrays are dynamic, so you do not have to decide their size beforehand.
|
||||
|
||||
### Defining functions
|
||||
|
||||
There are several ways to define functions in JavaScript. For example, the [function declaration][31] allows you to directly define a function:
|
||||
|
||||
|
||||
```
|
||||
function triplify(x) {
|
||||
return 3 * x;
|
||||
}
|
||||
|
||||
// The function call is:
|
||||
triplify(3);
|
||||
```
|
||||
|
||||
You can also declare a function with an [expression][32] and store it in a variable:
|
||||
|
||||
|
||||
```
|
||||
var triplify = function (x) {
|
||||
return 3 * x;
|
||||
}
|
||||
|
||||
// The function call is still:
|
||||
triplify(3);
|
||||
```
|
||||
|
||||
Finally, you can use the [arrow function expression][33], a syntactically short version of a function expression, but it has [some limitations][33]. It is generally used for concise functions that do simple calculations on its arguments:
|
||||
|
||||
|
||||
```
|
||||
var triplify = (x) => 3 * x;
|
||||
|
||||
// The function call is still:
|
||||
triplify(3);
|
||||
```
|
||||
|
||||
### Printing output
|
||||
|
||||
In order to print on the terminal, you can use the built-in [`console` object][34] in the Node.js standard library. The [`log()` method][35] prints on the terminal (adding a newline at the end of the string):
|
||||
|
||||
|
||||
```
|
||||
`console.log("#### Anscombe's first set with JavaScript in Node.js ####");`
|
||||
```
|
||||
|
||||
The `console` object is a more powerful facility than just printing output; for instance, it can also print [warnings][36] and [errors][37]. If you want to print the value of a variable, you can convert it to a string and use `console.log()`:
|
||||
|
||||
|
||||
```
|
||||
`console.log("Slope: " + slope.toString());`
|
||||
```
|
||||
|
||||
### Reading data
|
||||
|
||||
Input/output in Node.js uses a [very interesting approach][38]; you can choose either a synchronous or an asynchronous approach. The former uses blocking function calls, and the latter uses non-blocking function calls. In a blocking function, the program stops there and waits until the function finishes its task, whereas non-blocking functions do not stop the execution but continue their task somehow and somewhere else.
|
||||
|
||||
You have a couple of options here: you could periodically check whether the function ended, or the function could notify you when it ends. This tutorial uses the second approach: it employs [an `EventEmitter`][39] that generates an [event][40] associated with a callback function. The callback executes when the event is triggered.
|
||||
|
||||
First, generate the `EventEmitter`:
|
||||
|
||||
|
||||
```
|
||||
`const myEmitter = new EventEmitter();`
|
||||
```
|
||||
|
||||
Then associate the file-reading's end with an event called `myEmitter`. Although you do not need to follow this path for this simple example—you could use a simple blocking call—it is a very powerful approach that can be very useful in other situations. Before doing that, add another piece to this section for using the CSV Parse library to do the data reading. This library provides [several approaches][41] you can choose from, but this example uses the [stream API][42] with a [pipe][43]. The library needs some configuration, which is defined in an object:
|
||||
|
||||
|
||||
```
|
||||
const csvOptions = {'separator': delimiter,
|
||||
'skipLines': skipHeader,
|
||||
'headers': false};
|
||||
```
|
||||
|
||||
Since you've defined the options, you can read the file:
|
||||
|
||||
|
||||
```
|
||||
fs.createReadStream(inputFileName)
|
||||
.pipe(csv(csvOptions))
|
||||
.on('data', (datum) => data.push({'x': Number(datum[columnX]), 'y': Number(datum[columnY])}))
|
||||
.on('end', () => myEmitter.emit('reading-end'));
|
||||
```
|
||||
|
||||
I'll walk through each line of this short, dense code snippet:
|
||||
|
||||
* `fs.createReadStream(inputFileName)` opens a [stream of data][44] that is read from the file. A stream gradually reads a file in chunks.
|
||||
* `.pipe(csv(csvOptions))` forwards the stream to the CSV Parse library that handles the difficult task of reading the file and parsing it.
|
||||
* `.on('data', (datum) => data.push({'x': Number(datum[columnX]), 'y': Number(datum[columnY])}))` is rather dense, so I will break it out:
|
||||
* `(datum) => ...` defines a function to which each row of the CSV file will be passed.
|
||||
* `data.push(...` adds the newly read data to the `data` array.
|
||||
* `{'x': ..., 'y': ...}` constructs a new data point with `x` and `y` members.
|
||||
* `Number(datum[columnX])` converts the element in `columnX` to a number.
|
||||
* `.on('end', () => myEmitter.emit('reading-end'));` uses the emitter you created to notify you when the file-reading finishes.
|
||||
|
||||
|
||||
|
||||
When the emitter emits the `reading-end` event, you know that the file was completely parsed and its contents are in the `data` array.
|
||||
|
||||
### Fitting data
|
||||
|
||||
Now that you filled the `data` array, you can analyze the data in it. The function that carries out the analysis is associated with the `reading-end` event of the emitter you defined, so you can be sure that the data is ready. The emitter associates a callback function to that event and executes the function when the event is triggered.
|
||||
|
||||
|
||||
```
|
||||
myEmitter.on('reading-end', function () {
|
||||
const fit_data = data.map((datum) => [datum.x, datum.y]);
|
||||
|
||||
const result = regression.linear(fit_data);
|
||||
const slope = result.equation[0];
|
||||
const intercept = result.equation[1];
|
||||
|
||||
console.log("Slope: " + slope.toString());
|
||||
console.log("Intercept: " + intercept.toString());
|
||||
|
||||
const x = data.map((datum) => datum.x);
|
||||
const y = data.map((datum) => datum.y);
|
||||
|
||||
const r_value = ss.sampleCorrelation(x, y);
|
||||
|
||||
console.log("Correlation coefficient: " + r_value.toString());
|
||||
|
||||
myEmitter.emit('analysis-end', data, slope, intercept);
|
||||
});
|
||||
```
|
||||
|
||||
The statistics libraries expect data in different formats, so employ the [`map()` method][45] of the `data` array. `map()` creates a new array from an existing one and applies a function to each array element. The arrow functions are very practical in this context due to their conciseness. When the analysis finishes, you can trigger a new event to continue in a new callback. You could also directly plot the data in this function, but I opted to continue in a new one because the analysis could be a very lengthy process. By emitting the `analysis-end` event, you also pass the relevant data from this function to the next callback.
|
||||
|
||||
### Plotting
|
||||
|
||||
[D3.js][46] is a [very powerful][47] library for plotting data. The learning curve is rather steep, probably because it is a [misunderstood library][48], but it is the best open source option I've found for server-side plotting. My favorite D3.js feature is probably that it works on SVG images. D3.js was designed to run in a web browser, so it assumes it has a web page to handle. Working server-side is a very different environment, and you need a [virtual web page][49] to work on. Luckily, [D3-Node][50] makes this process very simple.
|
||||
|
||||
Begin by defining some useful measurements that will be required later:
|
||||
|
||||
|
||||
```
|
||||
const figDPI = 100;
|
||||
const figWidth = 7 * figDPI;
|
||||
const figHeight = figWidth / 16 * 9;
|
||||
const margins = {top: 20, right: 20, bottom: 50, left: 50};
|
||||
|
||||
let plotWidth = figWidth - margins.left - margins.right;
|
||||
let plotHeight = figHeight - margins.top - margins.bottom;
|
||||
|
||||
let minX = d3.min(data, (datum) => datum.x);
|
||||
let maxX = d3.max(data, (datum) => datum.x);
|
||||
let minY = d3.min(data, (datum) => datum.y);
|
||||
let maxY = d3.max(data, (datum) => datum.y);
|
||||
```
|
||||
|
||||
You have to convert between the data coordinates and the plot (image) coordinates. You can use scales for this conversion: the scale's domain is the data space where you pick the data points, and the scale's range is the image space where you put the points:
|
||||
|
||||
|
||||
```
|
||||
let scaleX = d3.scaleLinear()
|
||||
.range([0, plotWidth])
|
||||
.domain([minX - 1, maxX + 1]);
|
||||
let scaleY = d3.scaleLinear()
|
||||
.range([plotHeight, 0])
|
||||
.domain([minY - 1, maxY + 1]);
|
||||
|
||||
const axisX = d3.axisBottom(scaleX).ticks(10);
|
||||
const axisY = d3.axisLeft(scaleY).ticks(10);
|
||||
```
|
||||
|
||||
Note that the `y` scale has an inverted range because in the SVG standard, the `y` scale's origin is at the top. After defining the scales, start drawing the plot on a newly created SVG image:
|
||||
|
||||
|
||||
```
|
||||
let svg = d3n.createSVG(figWidth, figHeight)
|
||||
|
||||
svg.attr('background-color', 'white');
|
||||
|
||||
svg.append("rect")
|
||||
.attr("width", figWidth)
|
||||
.attr("height", figHeight)
|
||||
.attr("fill", 'white');
|
||||
```
|
||||
|
||||
First, draw the interpolating line appending a `line` element to the SVG image:
|
||||
|
||||
|
||||
```
|
||||
svg.append("g")
|
||||
.attr('transform', `translate(${margins.left}, ${margins.top})`)
|
||||
.append("line")
|
||||
.attr("x1", scaleX(minX - 1))
|
||||
.attr("y1", scaleY((minX - 1) * slope + intercept))
|
||||
.attr("x2", scaleX(maxX + 1))
|
||||
.attr("y2", scaleY((maxX + 1) * slope + intercept))
|
||||
.attr("stroke", "#1f77b4");
|
||||
```
|
||||
|
||||
Then add a `circle` for each data point to the right location. D3.js's key point is that it associates data with SVG elements. Thus, you use the `data()` method to associate the data points to the circles you create. The [`enter()` method][51] tells the library what to do with the newly associated data:
|
||||
|
||||
|
||||
```
|
||||
svg.append("g")
|
||||
.attr('transform', `translate(${margins.left}, ${margins.top})`)
|
||||
.selectAll("circle")
|
||||
.data(data)
|
||||
.enter()
|
||||
.append("circle")
|
||||
.classed("circle", true)
|
||||
.attr("cx", (d) => scaleX(d.x))
|
||||
.attr("cy", (d) => scaleY(d.y))
|
||||
.attr("r", 3)
|
||||
.attr("fill", "#ff7f0e");
|
||||
```
|
||||
|
||||
The last elements you draw are the axes and their labels; this is so you can be sure they overlap the plot lines and circles:
|
||||
|
||||
|
||||
```
|
||||
svg.append("g")
|
||||
.attr('transform', `translate(${margins.left}, ${margins.top + plotHeight})`)
|
||||
.call(axisX);
|
||||
|
||||
svg.append("g")
|
||||
.append("text")
|
||||
.attr("transform", `translate(${margins.left + 0.5 * plotWidth}, ${margins.top + plotHeight + 0.7 * margins.bottom})`)
|
||||
.style("text-anchor", "middle")
|
||||
.text("X");
|
||||
|
||||
svg.append("g")
|
||||
.attr('transform', `translate(${margins.left}, ${margins.top})`)
|
||||
.call(axisY);
|
||||
|
||||
svg.append("g")
|
||||
.attr("transform", `translate(${0.5 * margins.left}, ${margins.top + 0.5 * plotHeight})`)
|
||||
.append("text")
|
||||
.attr("transform", "rotate(-90)")
|
||||
.style("text-anchor", "middle")
|
||||
.text("Y");
|
||||
```
|
||||
|
||||
Finally, save the plot to an SVG file. I opted for a synchronous write of the file, so I could show this [second approach][52]:
|
||||
|
||||
|
||||
```
|
||||
`fs.writeFileSync("fit_node.svg", d3n.svgString());`
|
||||
```
|
||||
|
||||
### Results
|
||||
|
||||
Running the script is as simple as:
|
||||
|
||||
|
||||
```
|
||||
`$ node fitting_node.js`
|
||||
```
|
||||
|
||||
And the command-line output is:
|
||||
|
||||
|
||||
```
|
||||
#### Anscombe's first set with JavaScript in Node.js ####
|
||||
Slope: 0.5
|
||||
Intercept: 3
|
||||
Correlation coefficient: 0.8164205163448399
|
||||
```
|
||||
|
||||
Here is the image I generated with D3.js and Node.js:
|
||||
|
||||
![Plot and fit of the dataset obtained with Node.js][53]
|
||||
|
||||
(Cristiano Fontana, [CC BY-SA 4.0][54])
|
||||
|
||||
### Conclusion
|
||||
|
||||
JavaScript is a very popular language for [serverless computing][55], so this example of server-side data analysis and plotting with Node.js is not unlikely. The two most interesting parts in this tutorial are probably the introduction to the event-driven architecture (for people getting started with Node.js) and the example of server-side plotting (for more knowledgeable readers).
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/6/server-side-data-science-nodejs
|
||||
|
||||
作者:[Cristiano L. Fontana][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/cristianofontana
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/browser_screen_windows_files.png?itok=kLTeQUbY (Computer screen with files or windows open)
|
||||
[2]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/About_JavaScript
|
||||
[3]: https://en.wikipedia.org/wiki/Lingua_franca
|
||||
[4]: https://en.wikipedia.org/wiki/Source-to-source_compiler
|
||||
[5]: https://www.destroyallsoftware.com/talks/wat
|
||||
[6]: https://www.youtube.com/watch?v=_DKkVvOt6dk
|
||||
[7]: https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey
|
||||
[8]: https://nodejs.org/en/
|
||||
[9]: https://en.wikipedia.org/wiki/Event-driven_architecture
|
||||
[10]: https://en.wikipedia.org/wiki/Asynchrony_%28computer_programming%29
|
||||
[11]: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Async_await
|
||||
[12]: https://en.wikipedia.org/wiki/Comma-separated_values
|
||||
[13]: https://en.wikipedia.org/wiki/Anscombe%27s_quartet
|
||||
[14]: https://opensource.com/article/20/2/python-gnu-octave-data-science
|
||||
[15]: https://opensource.com/article/20/2/c-data-science
|
||||
[16]: https://gitlab.com/cristiano.fontana/polyglot_fit
|
||||
[17]: https://www.npmjs.com/
|
||||
[18]: https://getfedora.org/
|
||||
[19]: https://docs.npmjs.com/configuring-npm/folders.html
|
||||
[20]: https://csv.js.org/parse/
|
||||
[21]: https://simplestatistics.org/
|
||||
[22]: http://tom-alexander.github.io/regression-js/
|
||||
[23]: https://bradoyler.com/projects/d3-node/
|
||||
[24]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Comments
|
||||
[25]: https://nodejs.org/en/knowledge/getting-started/what-is-require/
|
||||
[26]: https://gist.github.com/hallettj/64478
|
||||
[27]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var
|
||||
[28]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
|
||||
[29]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const
|
||||
[30]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new
|
||||
[31]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function
|
||||
[32]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function
|
||||
[33]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
|
||||
[34]: https://nodejs.org/api/console.html
|
||||
[35]: https://nodejs.org/api/console.html#console_console_log_data_args
|
||||
[36]: https://nodejs.org/api/console.html#console_console_warn_data_args
|
||||
[37]: https://nodejs.org/api/console.html#console_console_error_data_args
|
||||
[38]: https://nodejs.org/en/docs/guides/blocking-vs-non-blocking/
|
||||
[39]: https://nodejs.org/api/events.html#events_class_eventemitter
|
||||
[40]: https://nodejs.org/api/events.html#events_events
|
||||
[41]: https://csv.js.org/parse/api/
|
||||
[42]: https://csv.js.org/parse/api/stream/
|
||||
[43]: https://csv.js.org/parse/recipies/stream_pipe/
|
||||
[44]: https://nodejs.org/api/stream.html#stream_stream
|
||||
[45]: https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Global_Objects/Array/map
|
||||
[46]: https://d3js.org/
|
||||
[47]: https://observablehq.com/@d3/gallery
|
||||
[48]: https://medium.com/dailyjs/the-trouble-with-d3-4a84f7de011f
|
||||
[49]: https://github.com/jsdom/jsdom
|
||||
[50]: https://github.com/d3-node/d3-node
|
||||
[51]: https://www.d3indepth.com/enterexit/
|
||||
[52]: https://nodejs.org/api/fs.html#fs_fs_writefilesync_file_data_options
|
||||
[53]: https://opensource.com/sites/default/files/uploads/fit_node.jpg (Plot and fit of the dataset obtained with Node.js)
|
||||
[54]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[55]: https://en.wikipedia.org/wiki/Serverless_computing
|
@ -0,0 +1,110 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (Yufei-Yan)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Customize your Raspberry Pi operating system for everyday use)
|
||||
[#]: via: (https://opensource.com/article/20/6/custom-raspberry-pi)
|
||||
[#]: author: (Patrick H. Mullins https://opensource.com/users/pmullins)
|
||||
|
||||
Customize your Raspberry Pi operating system for everyday use
|
||||
======
|
||||
Lighten up your Raspberry Pi even more by installing Raspberry Pi OS
|
||||
Lite.
|
||||
![Cartoon graphic of Raspberry Pi board][1]
|
||||
|
||||
If you have a Raspberry Pi running [Raspberry Pi OS][2] (previously known as Raspbian) operating system, you know it's an awesome little computer with a great operating system for beginners that includes just about everything you could possibly want. However, once you become familiar with the Pi and want to start using it for other things, you might want an operating system (OS) that doesn't include everything in the default build.
|
||||
|
||||
When that happens, you have two choices: You can pull your hair out trying to uninstall all the cruft you don't want, or you can use Raspberry Pi OS Lite to build your own custom, lightweight operating system tailored to your exact specs. I suggest saving yourself some time and aggravation and going with the latter option.
|
||||
|
||||
### Raspberry Pi OS Lite
|
||||
|
||||
The "Lite" version of Raspberry Pi OS is really nothing more than a minimal image based on the latest version of [Debian][3]. This image contains only the core operating system and boots to a command line instead of a desktop. Consider this the foundation of your custom Raspberry Pi OS. Everything from here on builds on this core.
|
||||
|
||||
Head over to the Raspberry Pi Foundation's website and [download][2] the Lite image. After that's complete, check out the detailed [installation guide][4] covering how to burn a Raspberry Pi operating system image to an SD card using Linux, Windows, or macOS.
|
||||
|
||||
If you plan to use your Pi for a minimalist system to run scripts and services, you're pretty much done. If you want to do more, keep reading.
|
||||
|
||||
### X Windows
|
||||
|
||||
To start, it's good to have a windowing system for the occasional time you want to connect to a Raspberry Pi with a graphical user interface (GUI).
|
||||
|
||||
The [X Window System][5], sometimes referred to as X11, is a basic windowing system common on Unix computer operating systems. X11 provides the basic framework for a GUI desktop environment. It is what allows you to interact with the computer using windows, a mouse, and a keyboard.
|
||||
|
||||
#### Install X Windows
|
||||
|
||||
The following line will install the minimal set of packages needed to get X11 going:
|
||||
|
||||
|
||||
```
|
||||
`sudo apt install -y --no-install-recommends xserver-xorg-core xserver-xorg xfonts-base xinit`
|
||||
```
|
||||
|
||||
With `--no-install-recommends`, only the main dependencies (the packages in the depends field) are installed. This saves a ton of space because the other recommended—but not necessarily needed—packages are not installed.
|
||||
|
||||
### Go a step further with Xfce Desktop Environment
|
||||
|
||||
You could stop here and use X Windows as your desktop, if you want. However, I wouldn't recommend it. The windows manager that comes with X Windows is minimalist in a way that feels outdated. Instead, I recommend installing a modern desktop environment like Xfce, GNOME, or KDE. When it comes to microcomputers, I prefer [Xfce][6] over the others because it's designed to work well on systems with limited resources, and you can customize the way it looks via themes, icons, and more.
|
||||
|
||||
#### Install Xfce
|
||||
|
||||
Installing the Xfce desktop environment is super easy. Just use:
|
||||
|
||||
|
||||
```
|
||||
`sudo apt install -y --no-install-recommends xfce4 desktop-base lightdm`
|
||||
```
|
||||
|
||||
That's it! You now have X Windows (X11) and Xfce installed. Now it's time to customize the environment and install some essential applications.
|
||||
|
||||
### Essential applications
|
||||
|
||||
So far, you've installed X Windows (X11), the Xfce Desktop Environment, and LightDM (a display manager, added with Xfce). At this point, you have a complete, lightweight system that you can boot into and use normally. However, there are a few essential applications that I always like to install to round things out.
|
||||
|
||||
The following command installs a terminal app, the [Audacious][7] audio player, the [Ristretto][8] image viewer, the [Mousepad][9] text editor, the [File Roller][10] archive manager, and the [Thunar][11] volume manager:
|
||||
|
||||
|
||||
```
|
||||
sudo apt install -y --no-install-recommends xfce4-terminal audacious ristretto
|
||||
sudo apt install -y --no-install-recommends mousepad file-roller thunar-volman
|
||||
```
|
||||
|
||||
#### Optional goodies
|
||||
|
||||
Some other goodies you might want to install are a good network manager, task manager, PDF viewer, and notification agent, as well as a wallpaper manager, screen-capture tool, some new icons, and new cursor themes. In short, these are practical additions for day-to-day usage if the Raspberry Pi will be your go-to system:
|
||||
|
||||
|
||||
```
|
||||
sudo apt install -y --no-install-recommends network-manager xfce4-taskmanager xfce4-notifyd
|
||||
sudo apt install -y --no-install-recommends xpdf gnome-icon-theme dmz-cursor-theme
|
||||
```
|
||||
|
||||
### Where to go from here?
|
||||
|
||||
If everything worked correctly, you now have a Raspberry Pi running a super-lightweight operating system based on Xfce 4 and Debian Lite. I suggest heading over to the Xfce website and checking out all the other cool [goodies][12] you can install and use. Where you go from there is totally up to you!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/6/custom-raspberry-pi
|
||||
|
||||
作者:[Patrick H. Mullins][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/pmullins
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/raspberrypi_cartoon.png?itok=m3TcBONJ (Cartoon graphic of Raspberry Pi board)
|
||||
[2]: https://www.raspberrypi.org/downloads/raspberry-pi-os/
|
||||
[3]: https://www.debian.org/
|
||||
[4]: https://www.raspberrypi.org/documentation/installation/installing-images/README.md
|
||||
[5]: https://en.wikipedia.org/wiki/X_Window_System
|
||||
[6]: http://xfce.org
|
||||
[7]: https://audacious-media-player.org/
|
||||
[8]: https://docs.xfce.org/apps/ristretto/start
|
||||
[9]: https://github.com/codebrainz/mousepad
|
||||
[10]: https://gitlab.gnome.org/GNOME/file-roller
|
||||
[11]: https://docs.xfce.org/xfce/thunar/thunar-volman
|
||||
[12]: https://goodies.xfce.org/
|
@ -7,41 +7,39 @@
|
||||
[#]: via: (https://opensource.com/article/20/5/plotly-python)
|
||||
[#]: author: (Shaun Taylor-Morgan https://opensource.com/users/shaun-taylor-morgan)
|
||||
|
||||
Simplify data visualization in Python with Plotly
|
||||
使用 Plotly 来简化 Python 中的数据可视化
|
||||
======
|
||||
Plotly is a data plotting library with a clean interface designed to
|
||||
allow you to build your own APIs.
|
||||
Plotly 是一个数据绘图库,具有整洁的接口,它旨在允许你构建自己的 API。
|
||||
![Colorful sound wave graph][1]
|
||||
|
||||
Plotly is a plotting ecosystem that allows you to make plots in [Python][2], as well as JavaScript and R. In this series of articles, I'm focusing on [plotting with Python libraries][3].
|
||||
Plotly 是一个绘图生态系统,可以让你在 [Python][2] 以及 JavaScript 和 R 中进行绘图。在本文中,我将重点介绍[使用 Python 库进行绘图][3]。
|
||||
|
||||
Plotly has three different Python APIs, giving you a choice of how to drive it:
|
||||
Plotly 有三种不同的 Python API,你可以选择不同的方法来使用它:
|
||||
|
||||
* An [object-oriented API][4] that feels similar to Matplotlib
|
||||
* A [data-driven API][5] that specifies plots by constructing dictionaries of JSON-like data
|
||||
* A ["Plotly Express" API][6] that gives you high-level plotting functions similar to Seaborn
|
||||
* 类似于 Matplotlib 的[面向对象的 API][4]
|
||||
|
||||
* [数据驱动的 API][5],通过构造类似 JSON 的数据结构来指定绘图
|
||||
|
||||
* 类似于 Seaborn 的高级绘图接口,称为 ["Plotly Express" API][6]
|
||||
|
||||
我将探索使用每个 API 来绘制相同的图:英国大选结果的分组柱状图。
|
||||
|
||||
I'll explore each of these APIs by making the same plot in each one: a grouped bar plot of historical UK election results.
|
||||
### 使用图对象来绘制图
|
||||
|
||||
### Making plots using Graph Objects
|
||||
|
||||
Plotly's object-oriented API is named graph_objects. It's somewhat similar to [Matplotlib's object-oriented API][7].
|
||||
|
||||
To create a multi-bar plot, you can construct a figure object containing four bar plots:
|
||||
Plotly 面向对象的 API 被称为图对象,它有点类似于 [Matplotlib 的面向对象 API][7]。
|
||||
|
||||
要创建一个柱状图,你可以构造一个包含四个柱状图的对象:
|
||||
|
||||
```
|
||||
# Import Plotly and our data
|
||||
# 导入 Plotly 和数据
|
||||
import plotly.graph_objects as go
|
||||
from votes import wide as df
|
||||
|
||||
# Get a convenient list of x-values
|
||||
# 得到 x 列表
|
||||
years = df['year']
|
||||
x = list(range(len(years)))
|
||||
|
||||
# Specify the plots
|
||||
# 指定绘图
|
||||
bar_plots = [
|
||||
go.Bar(x=x, y=df['conservative'], name='Conservative', marker=go.bar.Marker(color='#0343df')),
|
||||
go.Bar(x=x, y=df['labour'], name='Labour', marker=go.bar.Marker(color='#e50000')),
|
||||
@ -49,7 +47,7 @@ To create a multi-bar plot, you can construct a figure object containing four ba
|
||||
go.Bar(x=x, y=df['others'], name='Others', marker=go.bar.Marker(color='#929591')),
|
||||
]
|
||||
|
||||
# Specify the layout
|
||||
# 指定样式
|
||||
layout = go.Layout(
|
||||
title=go.layout.Title(text="Election results", x=0.5),
|
||||
yaxis_title="Seats",
|
||||
@ -58,28 +56,26 @@ To create a multi-bar plot, you can construct a figure object containing four ba
|
||||
xaxis_ticktext=tuple(df['year'].values),
|
||||
)
|
||||
|
||||
# Make the multi-bar plot
|
||||
# 绘制柱状图
|
||||
fig = go.Figure(data=bar_plots, layout=layout)
|
||||
|
||||
# Tell Plotly to render it
|
||||
# 告诉 Plotly 去渲染
|
||||
fig.show()
|
||||
```
|
||||
|
||||
Unlike in Matplotlib, there's no need to calculate the x-positions of the bars manually; Plotly takes care of that for you.
|
||||
与 Matplotlib 不同的是,你无需手动计算柱状图的 x 轴位置,Plotly 会帮你适配。
|
||||
|
||||
Here's the final plot:
|
||||
最终结果图:
|
||||
|
||||
![A multi-bar plot made using Graph Objects][8]
|
||||
|
||||
A multi-bar plot made using Graph Objects (© 2019 [Anvil][9])
|
||||
|
||||
### Making plots using Python data structures
|
||||
|
||||
You can also specify your plot using basic Python data structures with the same structure as the object-oriented API. This corresponds directly to the JSON API for Plotly's JavaScript implementation.
|
||||
### 使用 Python 数据结构来绘图
|
||||
|
||||
你还可以使用 Python 基本数据结构来指定绘图,它与面对对象 API 具有相同的结构。这直接对应于 Plotly 的 JavaScript 实现的 JSON API。
|
||||
|
||||
```
|
||||
# Specify the plots
|
||||
# 指定绘图数据
|
||||
fig = {
|
||||
'data': [
|
||||
{'type': 'bar', 'x': x, 'y': df['conservative'], 'name': 'Conservative', 'marker': {'color': '#0343df'}},
|
||||
@ -98,29 +94,28 @@ You can also specify your plot using basic Python data structures with the same
|
||||
}
|
||||
}
|
||||
|
||||
# Tell Plotly to render it
|
||||
# 告诉 Plotly 去渲染它
|
||||
pio.show(fig)
|
||||
```
|
||||
|
||||
The final plot looks exactly the same as the previous plot:
|
||||
最终结果与上次完全相同:
|
||||
|
||||
![A multi-bar plot made using JSON-like data structures][10]
|
||||
|
||||
A multi-bar plot made using JSON-like data structures (© 2019 [Anvil][9])
|
||||
|
||||
### Making plots using Plotly Express
|
||||
#### 使用 Plotly Express 进行绘图
|
||||
|
||||
[Plotly Express][11] is a high-level API that wraps Graph Objects.
|
||||
|
||||
You can make a multi-bar plot in Plotly Express using (almost) a single line:
|
||||
[Plotly Express][11] 是对图对象进行封装的高级 API。
|
||||
|
||||
你可以使用一行代码来绘制柱状图:
|
||||
|
||||
```
|
||||
# Import Plotly and our data
|
||||
# 导入 Plotly 和数据
|
||||
import plotly.express as px
|
||||
from votes import long as df
|
||||
|
||||
# Define the colourmap to get custom bar colours
|
||||
# 定义颜色字典获得自定义栏颜色
|
||||
cmap = {
|
||||
'Conservative': '#0343df',
|
||||
'Labour': '#e50000',
|
||||
@ -128,15 +123,14 @@ You can make a multi-bar plot in Plotly Express using (almost) a single line:
|
||||
'Others': '#929591',
|
||||
}
|
||||
|
||||
# Make the plot!
|
||||
# 生成图
|
||||
fig = px.bar(df, x="year", y="seats", color="party", barmode="group", color_discrete_map=cmap)
|
||||
```
|
||||
|
||||
This makes use of the data in [Long Form][12], also known as "tidy data." The columns are year, party, and seats, rather than being split by party. It's very similar to making a multi-bar plot in [Seaborn][13].
|
||||
|
||||
这里使用了 [Long Form][12] 数据,也称为“整洁数据”。这些列代表年份、政党和席位,而不是按政党划分。这与在 [Seaborn][13] 中制作柱状图非常相似。
|
||||
|
||||
```
|
||||
>> print(long)
|
||||
>> print(long)
|
||||
year party seats
|
||||
0 1922 Conservative 344
|
||||
1 1923 Conservative 258
|
||||
@ -153,11 +147,10 @@ This makes use of the data in [Long Form][12], also known as "tidy data." The co
|
||||
[108 rows x 3 columns]
|
||||
```
|
||||
|
||||
You can access the underlying Graph Objects API to make detailed tweaks. Add a title and a y-axis label:
|
||||
|
||||
你可以访问底层的图对象 API 进行详细调整。如添加标题和 y 轴标签:
|
||||
|
||||
```
|
||||
# Use the Graph Objects API to tweak our plot
|
||||
# 使用图对象 API 来调整绘图
|
||||
import plotly.graph_objects as go
|
||||
fig.layout = go.Layout(
|
||||
title=go.layout.Title(text="Election results", x=0.5),
|
||||
@ -165,42 +158,39 @@ You can access the underlying Graph Objects API to make detailed tweaks. Add a t
|
||||
)
|
||||
```
|
||||
|
||||
And finally, ask Plotly to show it to you:
|
||||
|
||||
最后,让 Plotly 渲染:
|
||||
|
||||
```
|
||||
# Tell Plotly to render it
|
||||
fig.show()
|
||||
```
|
||||
|
||||
This runs a temporary web server on an unused port and opens the default web browser to view the plot (the webserver is immediately torn down).
|
||||
这将在未使用的端口上运行一个临时 Web 服务器,并打开默认的 Web 浏览器来查看图像(Web 服务器将会马上被关闭)。
|
||||
|
||||
Unfortunately, the result is not perfect. The x-axis is treated as an integer, so the groups are far apart and small. This makes it quite difficult to see trends.
|
||||
不幸的是,结果并不完美。x 轴被视为整数,因此两组之间的距离很远且很小,这使得我们很难看到趋势。
|
||||
|
||||
![A multi-bar plot made using Plotly Express][14]
|
||||
![使用 Plotly Express 制作的柱状图][14]
|
||||
|
||||
A multi-bar plot made using Plotly Express (© 2019 [Anvil][9])
|
||||
|
||||
You might try to encourage Plotly Express to treat the x-values as strings by casting them to strings. You might expect this to result in them being plotted with even spacing and lexical ordering. Unfortunately, you still get them helpfully spaced numerically. Setting the xaxis_tickvals does not work as it did in graph_objects, either.
|
||||
你可能会尝试通过将 x 值转换为字符串来使 Plotly Express 将其视为字符串,这样它就会以均匀的间隔和词法顺序来绘制。不幸的是,它们的间隔还是很大,设置 x 值不像在图对象中那样设置。
|
||||
|
||||
Unlike the similar example in [Seaborn][13], in this case, the abstraction does not appear to provide sufficient [escape hatches][15] to provide things exactly how you want them. But perhaps you could write your _own_ API?
|
||||
与 [Seaborn][13] 中的类似示例不同,在这种情况下,抽象似乎没有提供足够的[应急方案][15]来提供你想要的东西,但是也许你可以编写 _自己_ 的 API?
|
||||
|
||||
### Building your own Plotly API
|
||||
### 构建自己的 Plotly API
|
||||
|
||||
Not happy with how Plotly does something? Build your own Plotly API!
|
||||
对 Plotly 的操作方式不满意?构建自己的 Plotly API!
|
||||
|
||||
At its core, Plotly is a JavaScript library that makes plots using [D3][16] and [stack.gl][17]. The JavaScript library has an interface that consumes JSON structures that specify plots. So you just need to output JSON structures that the JavaScript library likes to consume.
|
||||
Plotly 的核心是一个 JavaScript 库,它使用 [D3][16] 和 [stack.gl][17] 进行绘图。JavaScript 库的接口使用指定的 JSON 结构来绘图。因此,你只需要输出 JavaScript 库喜欢使用的 JSON 结构就好了。
|
||||
|
||||
Anvil did that to create a Python Plotly API that works entirely in the browser.
|
||||
Anvil 这样做是为了创建一个完全在浏览器中工作的 Python Plotly API。
|
||||
|
||||
![Plotly uses a JavaScript library to create plots, driven by libraries in other languages via JSON][18]
|
||||
![Ployly 使用 JavaScript 库创建图形,由其它语言库通过 JSON 使用][18]
|
||||
|
||||
Plotly uses a JavaScript library to create plots, driven by libraries in other languages via JSON (© 2019 [Anvil][9])
|
||||
|
||||
In the Anvil version, you can use both the Graph Objects API and the Python data structure approach explained above. You run exactly the same commands, assigning the data and layout to a [Plot component][19] in your Anvil app.
|
||||
|
||||
Here's the multi-bar plot written in Anvil's client-side Python API:
|
||||
在 Anvil 版本中,你可以同时使用图对象 API 和上面介绍的 Python 数据结构方法。运行完全相同的命令,将数据和布局分配给 Anvil 应用程序中的 [Plot 组件][19]。
|
||||
|
||||
这是用 Anvil 的客户端 Python API 绘制的柱状图:
|
||||
|
||||
```
|
||||
# Import Anvil libraries
|
||||
@ -247,21 +237,22 @@ class Entrypoint(EntrypointTemplate):
|
||||
self.plot_1.layout = layout
|
||||
```
|
||||
|
||||
The plotting logic is the same as above, but it's running _entirely in the web browser_—the plot is created by the Plotly JavaScript library on the user's machine! This is a big advantage over all the other [Python plotting libraries][3] in this series. All the other Python libraries need to run on a server.
|
||||
绘图逻辑与上面相同,但是它完全在 Web 浏览器中运行,绘图是由用户计算机上的 Plotly JavaScript 库完成的!与本系列的所有其它 [Python 绘图库][3]相比,这是一个很大的优势。因为其它 Python 库都需要在服务器上运行。
|
||||
|
||||
Here's the interactive Plotly plot running in an Anvil app:
|
||||
这是在 Anvil 应用中运行的交互式 Plotly 图:
|
||||
|
||||
![The election plot on the web using Anvil's client-side-Python Plotly library][20]
|
||||
|
||||
The election plot on the web using Anvil's [client-side-Python][21] Plotly library (© 2019 [Anvil][9])
|
||||
使用 Anvil 的 [Python 客户端][21] Plotly 库在网络上进行选举的情节 (© 2019 [Anvil][9])
|
||||
|
||||
You can [copy this example][22] as an Anvil app (Note: Anvil requires registration to use).
|
||||
你可以[复制此示例][22]作为一个 Anvil 应用程序(注意:Anvil 需要注册才能使用)。
|
||||
|
||||
Running Plotly in the frontend has another advantage: it opens up many more options for customizing interactive behavior.
|
||||
在前端运行 Plotly 还有另一个优势:它为自定义交互行为提供了更多选项。
|
||||
|
||||
### Customizing interactivity in Plotly
|
||||
### 在 Plotly 中自定义交互
|
||||
|
||||
Plotly plots aren't just dynamic; you can customize their interactive behavior. For example, you can customize the format of tool-tips using hovertemplate in each bar plot:
|
||||
Plotly 绘图不仅是动态的,你可以自定义它们的互动行为。例如,你可以在每个条形图中使用 hovertemplate 自定义工具提示的格式:
|
||||
|
||||
|
||||
```
|
||||
@ -274,20 +265,20 @@ Plotly plots aren't just dynamic; you can customize their interactive behavior.
|
||||
),
|
||||
```
|
||||
|
||||
Here's what you get when you apply this to each bar plot:
|
||||
当你把这个应用到每个柱状图时,你会看到以下结果:
|
||||
|
||||
![A multi-bar plot with custom tool-tips][23]
|
||||
|
||||
A multi-bar plot with custom tool-tips (© 2019 [Anvil][9])
|
||||
|
||||
This is useful, but it would be even better if you could execute any code you want when certain events happen—like when a user hovers over the bar and you want to display an information box about the relevant election. In Anvil's Plotly library, you can bind event handlers to events such as hover, which makes that sort of complex interactivity possible!
|
||||
这很有用,当你想要在某些事件发生时执行另一些事件时它会表现的更好(例如,当用户将鼠标悬停在栏上,你想要显示有关相关选择的信息框)。在 Anvil 的 Plotly 库中,你可以将事件处理程序绑定到诸如悬停之类的事件,这使得复杂的交互成为可能。
|
||||
|
||||
![A multi-bar plot with a hover event handler][24]
|
||||
|
||||
A multi-bar plot with a hover event handler (© 2019 [Anvil][9])
|
||||
|
||||
You can achieve this by binding a method to the plot's hover event:
|
||||
|
||||
你可以通过将方法绑定到绘图的悬停事件来实现:
|
||||
|
||||
```
|
||||
def plot_1_hover(self, points, **event_args):
|
||||
@ -303,19 +294,18 @@ You can achieve this by binding a method to the plot's hover event:
|
||||
self.link_more_info.url = url
|
||||
```
|
||||
|
||||
This is a rather extreme level of interactivity, and from the developer's point of view, an extreme level of customizability. It's all thanks to Plotly's architecture—Plotly has a clean interface that is explicitly designed to allow you to build your own APIs. It would be helpful to see this kind of great design everywhere!
|
||||
这是一种相当极端的交互性,从开发人员的角度来看,也是一种极端的可定制性。这都要归功于 Plotly 的架构 - 它有一个整洁的接口,明确设计用于构建自己的 API。到处都可以看到这种出色的设计!
|
||||
|
||||
### Custom interactivity using Bokeh
|
||||
### 使用 Bokeh 进行自定义交互
|
||||
|
||||
You've seen how Plotly uses JavaScript to create dynamic plots, and you can edit them live in the browser using Anvil's client-side Python code.
|
||||
现在你已经了解了 Plotly 如何使用 JavaScript 来创建动态图,并且可以使用 Anvil 的客户端编写 Python 代码在浏览器中实时编辑它们。
|
||||
|
||||
Bokeh is another Python plotting library that outputs an HTML document you can embed in a web app and get similar dynamic features to those provided by Plotly. (That's "BOE-kay," if you're wondering how to pronounce it.)
|
||||
Bokeh 是另一个 Python 绘图库,它输出可嵌入 Web 应用程序的 HTML 文档,并获得与 Plotly 提供的功能类似的动态功能(如果你想知道如何发音,那就是 "BOE-kay")。
|
||||
|
||||
Enjoy customizing charts and share tips and tricks in the comments below.
|
||||
|
||||
* * *
|
||||
|
||||
_This article is based on [How to make plots using Plotly][9] on Anvil's blog and is reused with permission._
|
||||
_本文基于 Anvil 博客中的 [如何使用 Plotly 来绘图][9]一文,已允许使用。_
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@ -323,7 +313,7 @@ via: https://opensource.com/article/20/5/plotly-python
|
||||
|
||||
作者:[Shaun Taylor-Morgan][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
译者:[MjSeven](https://github.com/MjSeven)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
Loading…
Reference in New Issue
Block a user