Merge pull request #2 from LCTT/master

与上游同步
This commit is contained in:
jx.zeng 2020-06-26 08:57:24 +08:00 committed by GitHub
commit b58122d425
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 825 additions and 125 deletions

View File

@ -1,8 +1,8 @@
[#]: collector: (lujun9972)
[#]: translator: (wxy)
[#]: reviewer: (wxy)
[#]: publisher: ( )
[#]: url: ( )
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12347-1.html)
[#]: subject: (How I stream video with OBS and WebSockets)
[#]: via: (https://opensource.com/article/20/6/obs-websockets-streaming)
[#]: author: (Kevin Sonney https://opensource.com/users/ksonney)
@ -12,7 +12,7 @@
> 用这些简化了 WebSockets 的开源支持工具来控制你的流媒体。
![老式摄像机][1]
![](https://img.linux.net.cn/data/attachment/album/202006/25/105128sdod30qqu4z5oooo.jpg)
[OBS][2] 是现在视频直播的主流之一。它是直播流媒体到 Twitch 的首选软件Twitch 是近来最受欢迎的视频直播网站之一。有一些非常好的附加组件,可以让流媒体人从他们的手机或另一个屏幕上进行控制,而不影响正在运行的视频。事实证明,使用 [Node-RED][3] 和 [obs-websockets][4] 插件来构建自己的控制面板真的很容易。
@ -20,9 +20,9 @@
*我的 OBS 控制仪表盘*
我知道你们很多人在想什么 —— “他在同一句话中提到了 WebSockets 和简单?”很多人在设置和使用 WebSockets 时遇到了困难WebSockets 允许通过 Web 服务器的单一连接进行双向通信。 Node-RED 内置了对 WebSockets 的支持,是让这一切变得简单的原因之一,至少与编写自己的客户端/服务器相比是如此。
我知道你们很多人在想什么 —— “他在同一句话中提到了 WebSockets 和简单?”很多人在设置和使用 WebSockets 时遇到了困难WebSockets 允许通过 Web 服务器的单一连接进行双向通信。Node-RED 内置了对 WebSockets 的支持,是让这一切变得简单的原因之一,至少与编写自己的客户端/服务器相比是如此。
在开始之前,请确保你已经安装和配置了 OBS。首先下载并安装[最新稳定版的 obs-websockets][6]插件。对于本文来说,默认的设置就可以了,但我强烈建议你之后按照说明来保护 obs-websockets 的安全。
在开始之前,请确保你已经安装和配置了 OBS。首先下载并安装[最新稳定版的 obs-websockets][6]插件。对于本文来说,默认的设置就可以了,但我强烈建议你之后按照说明来保护 obs-websockets 的安全。
接下来,[下载并安装 Node-RED][7],可以在同一个系统上,也可以在不同的系统上(比如树莓派)。同样,默认的安装对我们这篇文章来说是够了,但最好按照他们网站上的指示进行安全安装。

View File

@ -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/) 荣誉推出

View File

@ -1,16 +1,18 @@
[#]: collector: (lujun9972)
[#]: translator: (geekpi)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12350-1.html)
[#]: subject: (How to dump the GOSSAFUNC graph for a method)
[#]: via: (https://dave.cheney.net/2020/06/19/how-to-dump-the-gossafunc-graph-for-a-method)
[#]: author: (Dave Cheney https://dave.cheney.net/author/davecheney)
如何转储一个方法的 GOSSAFUNC 图
在 Go 中如何转储一个方法的 GOSSAFUNC 图
======
Go 编译器的 SSA 后端包含一种工具,可以生成编译阶段的 HTML 调试输出。这篇文章介绍了如何为函数_和_方法打印 SSA 输出。
![](https://img.linux.net.cn/data/attachment/album/202006/26/083943vymvmc67p7s3oman.jpg)
Go 编译器的 SSA 后端包含一种工具,可以生成编译阶段的 HTML 调试输出。这篇文章介绍了如何为函数*和*方法打印 SSA 输出。
让我们从一个包含函数、值方法和指针方法的示例程序开始:
@ -47,7 +49,7 @@ func main() {
}
```
通过 `GOSSAFUNC` 环境变量控制 SSA 调试输出。此变量含有要转储的函数的名称。这_不是_函数的完全限定名。对于上面的 `func main`,函数名称为 `main` _而不是_ `main.main`
通过 `GOSSAFUNC` 环境变量控制 SSA 调试输出。此变量含有要转储的函数的名称。这*不是*函数的完全限定名。对于上面的 `func main`,函数名称为 `main` *而不是* `main.main`
```
% env GOSSAFUNC=main go build
@ -57,11 +59,11 @@ t
dumped SSA to ./ssa.html
```
在这个例子中,`GOSSAFUNC=main` 同时匹配了 `main.main` 和一个名为 `runtime.main` 的函数。[1][1]这有点不走运,但是实际上可能没什么大不了的,因为如果你要对代码进行性能调整,它就不会出现在 `func main` 中的巨大的意大利面块中。
在这个例子中,`GOSSAFUNC=main` 同时匹配了 `main.main` 和一个名为 `runtime.main` 的函数。[^1]这有点不走运,但是实际上可能没什么大不了的,因为如果你要对代码进行性能调整,它就不会出现在 `func main` 中的巨大的意大利面块中。
你的代码更有可能在_方法_中,你可能已经看到这篇文章,并寻找能够转储方法的 SSA 输出。
你的代码更有可能在*方法*中,你可能已经看到这篇文章,并寻找能够转储方法的 SSA 输出。
要为指针方法 `func (n *Numbers) Add` 打印 SSA 调试,等效函数名为 `(*Numbers).Add`[2][2]
要为指针方法 `func (n *Numbers) Add` 打印 SSA 调试,等效函数名为 `(*Numbers).Add`[^2]
```
% env "GOSSAFUNC=(*Numbers).Add" go build
@ -69,7 +71,7 @@ t
dumped SSA to ./ssa.html
```
要为值方法 `func (n Numbers) Average` 打印 SSA 调试,等效函数名为 `(*Numbers).Average`_即使这是一个值方法_
要为值方法 `func (n Numbers) Average` 打印 SSA 调试,等效函数名为 `(*Numbers).Average`*即使这是一个值方法*
```
% env "GOSSAFUNC=(*Numbers).Average" go build
@ -77,9 +79,8 @@ t
dumped SSA to ./ssa.html
```
1. 如果你没有从源码构建 Go那么 `runtime` 软件包的路径可能是只读的,并且可能会收到错误消息。请不要使用 `sudo` 来解决此问题。
2. 请注意 shell 引用
[^1]: 如果你没有从源码构建 Go那么 `runtime` 软件包的路径可能是只读的,并且可能会收到错误消息。请不要使用 `sudo` 来解决此问题。
[^2]: 请注意 shell 引用
--------------------------------------------------------------------------------
@ -89,11 +90,10 @@ via: https://dave.cheney.net/2020/06/19/how-to-dump-the-gossafunc-graph-for-a-me
作者:[Dave Cheney][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/) 荣誉推出
[a]: https://dave.cheney.net/author/davecheney
[b]: https://github.com/lujun9972
[1]: tmp.kLSHpQXzhr#easy-footnote-bottom-1-4188 (If you didnt build Go from source then the path to the <code>runtime</code> package may be read only and you might receive an error. Please dont use the <code>sudo</code> hammer to fix this.)
[2]: tmp.kLSHpQXzhr#easy-footnote-bottom-2-4188 (Please pay attention to the shell quoting.)

View File

@ -1,5 +1,5 @@
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: translator: (MjSeven)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )

View File

@ -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) =&gt; 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) =&gt; data.push({'x': Number(datum[columnX]), 'y': Number(datum[columnY])}))
  .on('end', () =&gt; 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) =&gt; [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) =&gt; datum.x);
    const y = data.map((datum) =&gt; 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) =&gt; datum.x);
let maxX = d3.max(data, (datum) =&gt; datum.x);
let minY = d3.min(data, (datum) =&gt; datum.y);
let maxY = d3.max(data, (datum) =&gt; 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) =&gt; scaleX(d.x))
   .attr("cy", (d) =&gt; 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

View File

@ -0,0 +1,156 @@
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (Make Bash history more useful with these tips)
[#]: via: (https://opensource.com/article/20/6/bash-history-control)
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
Make Bash history more useful with these tips
======
Tell Bash what you want it to remember—or even rewrite history by
deleting entries you don't want or need.
![A person programming][1]
A Linux terminal running [Bash][2] has a built-in history that you can use to track what you've been doing lately. To view a history of your Bash session, use the built-in command `history`:
```
$ echo "foo"
foo
$ echo "bar"
bar
$ history
  1  echo "foo"
  2  echo "bar"
  3  history
```
The `history` command isn't an executable file on your filesystem, like most commands, but a function of Bash. You can verify this by using the `type` command:
```
$ type history
history is a shell builtin
```
### History control
The upper limit of lines in your shell history is defined by the `HISTSIZE` variable. You can set this variable in your `.bashrc` file. The following sets your history to 3,000 lines, after which the oldest line is removed to make room for the newest command, placed at the bottom of the list:
```
`export HISTSIZE=3000`
```
There are other history-related variables, too. The `HISTCONTROL` variable controls what history is stored. You can force Bash to exclude commands starting with empty space by placing this in your `.bashrc` file:
```
`export HISTCONTROL=$HISTCONTROL:ignorespace`
```
Now, if you type a command starting with a space, that command won't get recorded in history:
```
$ echo "hello"
$     mysql -u bogus -h badpassword123 mydatabase
$ echo "world"
$ history
  1  echo "hello"
  2  echo "world"
  3  history
```
You can avoid duplicate entries, too:
```
`export HISTCONTROL=$HISTCONTROL:ignoredups`
```
Now, if you type two commands, one after another, only one appears in history:
```
$ ls
$ ls
$ ls
$ history
  1  ls
  2  history
```
If you like both of these ignores, you can just use `ignoreboth`:
```
`export HISTCONTROL=$HISTCONTROL:ignoreboth`
```
### Remove a command from history
Sometimes you make a mistake and type something sensitive into your shell, or maybe you just want to clean up your history so that it more accurately represents the steps you took to get something working correctly. If you want to delete a command from your history in Bash, use the `-d` option with the line number of the item you want to remove:
```
$ echo "foo"
foo
$ echo "bar"
bar
$ history | tail
  535  echo "foo"
  536  echo "bar"
  537  history | tail
$ history -d 536
$ history | tail
  535  echo "foo"
  536  history | tail
  537  history -d 536
  538  history | tail
```
To stop adding `history` entries, you can place a `space` before the command, as long as you have `ignorespace` in your `HISTCONTROL` environment variable:
```
$  history | tail
  535  echo "foo"
  536  echo "bar"
$  history -d 536
$  history | tail
  535  echo "foo"
```
You can clear your entire session history with the `-c` option:
```
$ history -c
$  history
$
```
### History lessons
Manipulating history is usually less dangerous than it sounds, especially when you're curating it with a purpose in mind. For instance, if you're documenting a complex problem, it's often best to use your session history to record your commands because, by slotting them into your history, you're running them and thereby testing the process. Very often, documenting without doing leads to overlooking small steps or writing minor details wrong.
Use your history sessions as needed, and exercise your power over history wisely. Happy history hacking!
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/6/bash-history-control
作者:[Seth Kenlon][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/seth
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/computer_keyboard_laptop_development_code_woman.png?itok=vbYz6jjb (A person programming)
[2]: https://opensource.com/resources/what-bash

View File

@ -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] 中制作柱状图非常相似。
```
&gt;&gt; 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/) 荣誉推出

View File

@ -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)
定制你的树莓派Raspberry Pi用于日常使用
======
安装 Raspberry Pi OS Lite 可以更加轻量化你的树莓派Raspberry Pi
![Cartoon graphic of Raspberry Pi board][1]
如果你有一个运行 [Raspberry Pi OS][2](以前称为 Raspbian操作系统的树莓派Raspberry Pi的话你懂的他就是一个运行了可以为初学者提供一切可能的伟大操作系统的小电脑这个电脑简直太棒了。然而一旦你开始熟悉他并且想开始用他干一些别的事情的时候你可能不再想要那个默认包含了所有东西的操作系统。
当这种情况发生的时候,你两个选择:要么你可以尽可能的把所有你不需要的东西都删干净,要么你还可以用 Raspberry Pi OS Lite 来构建专门为你的需求而定制的轻量级操作系统。我的建议是,用第二种方法,既简便又节省时间。
### Raspberry Pi OS Lite
Raspberry Pi OS 的“Lite”版本其实没什么特别的就是一个基于最新 [Debian][3] 版本的最小化镜像。这个镜像仅包含了操作系统核心和启动到命令行的部分,而不会进入图形桌面。考虑用这个作为你的定制 Raspberry Pi OS 的基础吧。这之后的所有东西都是建立在这个核心之上的。
到树莓派基金会Raspberry Pi Foundation的网站上[下载][2]这个轻量级镜像。下载完成后,查看详细的[安装指南][4],这里面介绍了在 Linux、Windows 或者 macOS 下如何烧制一个树莓派Raspberry Pi操作系统的 SD 卡。
如果你计划用树莓派作为一个最小化操作系统运行一些脚本和服务的话,差不多这么多就够了。如果你还想干更多事,那继续往下读。
### X Windows
首先为了偶尔需要通过用户界面GUI连接到你的树莓派Raspberry Pi安装一个可视化的系统还是不错的。
[X Window 系统][5],有时候称为 X11是 Unix 操作系统上一个很常见且基础的可视化系统。X11提供了一套 GUI 桌面环境下的基础框架。它可以让你通过窗口、鼠标和键盘与计算机交互。
#### 安装 X Windows
下面这一行安装了能让 X11 运行的最少的包。
```
`sudo apt install -y --no-install-recommends xserver-xorg-core xserver-xorg xfonts-base xinit`
```
通过 `--no-install-recommends`只安装了主要的一些依赖Depends 字段中的包)。这样可以节省很多空间,因为没有安装那些建议却不需要的包。
### 进阶:使用 Xfce 桌面环境
如果你喜欢的话,可以就此停下了,然后开始使用 X Windows 作为你的桌面。然而, 我并不建议这么做。X Windows自带的这种最小化的窗口管理工具某种程度上让人感觉过时了。相反我建议安装现代化的桌面环境比如说像 Xfce、GNOME 或者 KDE。当我们说的是微型计算机的时候我更倾向于 [Xfce][6] 而不是其他的,因为他就是为资源有限的系统设计的,而且你可以通过主题、图标或者其他东西对他进行定制。
#### Install Xfce
#### 安装 Xfce
安装 Xfce 桌面环境相当简单。只需要:
```
`sudo apt install -y --no-install-recommends xfce4 desktop-base lightdm`
```
这就够了。你现在安装了 X Windows X11和 Xfce 了。现在是时候来定制一下环境并且安装一些核心的应用了。
### 核心应用
目前为止,你已经安装了 X WindowsX11Xfce 桌面环境,和 LightDM一个 Xfce 自带的显示管理器)。现在,你已经有了一个可以启动并且正常使用的轻量、完整的系统。然而,在彻底完成之前,我还是喜欢装一些核心应用。
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:
下面这条命令安装了一个终端程序,[Audacious][7] 音乐播放器,[Ristretto][8] 图像浏览器,[Mousepad][9] 文本编辑器,[File Roller][10] 文档管理器和 [Thunar][11] 容量管理器。
```
sudo apt install -y --no-install-recommends xfce4-terminal audacious ristretto
sudo apt install -y --no-install-recommends mousepad file-roller thunar-volman
```
#### 其他可选项
其他一些你可能想安装的东西包括一个好的网络管理器任务管理器PDF 阅读器和通知工具再加上桌面背景管理器截图工具一些新的图标和光标主题。简单来说如果树莓派Raspberry Pi是你的首选系统这些都算是日常工作的一些补充。
```
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
```
### 下一步该做什么?
如果一切都正常工作的话,你现在就有一个基于 Xfce 和 Debian Lite 超轻量级操作系统的树莓派了Raspberry Pi。我建议现在上 Xfce 网站上查看其他所有不错的工具,这些东西你都可以安装并使用。下一步做什么完全由你决定!
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/6/custom-raspberry-pi
作者:[Patrick H. Mullins][a]
选题:[lujun9972][b]
译者:[Yufei-Yan](https://github.com/Yufei-Yan)
校对:[校对者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/