标签归档:pyqt

PyQt应用程序中的线程:使用Qt线程还是Python线程?

问题:PyQt应用程序中的线程:使用Qt线程还是Python线程?

我正在编写一个GUI应用程序,该应用程序通过Web连接定期检索数据。由于此检索需要一段时间,因此会导致UI在检索过程中无响应(无法拆分成较小的部分)。这就是为什么我想将Web连接外包给单独的工作线程。

[是的,我知道,现在我有两个问题。]

无论如何,该应用程序使用PyQt4,所以我想知道更好的选择是:使用Qt的线程还是使用Python threading模块?各自的优点/缺点是什么?还是您有完全不同的建议?

编辑(赏金):虽然在我的特定情况下,解决方案可能会使用非阻塞网络请求,例如Jeff OberLukášLalinský建议的(所以基本上将并发性问题留给了网络实现),但我仍然想要更多深入回答一般问题:

与本地Python线程(来自threading模块)相比,使用PyQt4(即Qt)线程有什么优缺点?


编辑2:谢谢大家的回答。尽管没有达成100%的协议,但似乎普遍的共识是答案是“使用Qt”,因为这样做的优点是可以与库的其余部分集成,而不会造成任何实际的缺点。

对于希望在这两种线程实现之间进行选择的任何人,我强烈建议他们阅读此处提供的所有答案,包括方丈链接到的PyQt邮件列表线程。

我考虑了一些悬赏的答案;最后,我选择了方丈作为非常相关的外部参考;然而,这是一个密切的电话。

再次感谢。

I’m writing a GUI application that regularly retrieves data through a web connection. Since this retrieval takes a while, this causes the UI to be unresponsive during the retrieval process (it cannot be split into smaller parts). This is why I’d like to outsource the web connection to a separate worker thread.

[Yes, I know, now I have two problems.]

Anyway, the application uses PyQt4, so I’d like to know what the better choice is: Use Qt’s threads or use the Python threading module? What are advantages / disadvantages of each? Or do you have a totally different suggestion?

Edit (re bounty): While the solution in my particular case will probably be using a non-blocking network request like Jeff Ober and Lukáš Lalinský suggested (so basically leaving the concurrency problems to the networking implementation), I’d still like a more in-depth answer to the general question:

What are advantages and disadvantages of using PyQt4’s (i.e. Qt’s) threads over native Python threads (from the threading module)?


Edit 2: Thanks all for you answers. Although there’s no 100% agreement, there seems to be widespread consensus that the answer is “use Qt”, since the advantage of that is integration with the rest of the library, while causing no real disadvantages.

For anyone looking to choose between the two threading implementations, I highly recommend they read all the answers provided here, including the PyQt mailing list thread that abbot links to.

There were several answers I considered for the bounty; in the end I chose abbot’s for the very relevant external reference; it was, however, a close call.

Thanks again.


回答 0

不久前在PyQt邮件列表中对此进行了讨论。引用乔凡尼·巴霍(Giovanni Bajo)对这个问题的评论

大致相同。主要区别在于QThreads与Qt(异步信号/插槽,事件循环等)更好地集成在一起。另外,您不能在Python线程中使用Qt(例如,不能通过QApplication.postEvent将事件发布到主线程):您需要一个QThread才能工作。

一般的经验法则是,如果您要以某种方式与Qt进行交互,则可以使用QThreads;否则,请使用Python线程。

PyQt的作者对此主题有较早的评论:“它们都是相同的本机线程实现的包装器”。两种实现都以相同的方式使用GIL。

This was discussed not too long ago in PyQt mailing list. Quoting Giovanni Bajo’s comments on the subject:

It’s mostly the same. The main difference is that QThreads are better integrated with Qt (asynchrnous signals/slots, event loop, etc.). Also, you can’t use Qt from a Python thread (you can’t for instance post event to the main thread through QApplication.postEvent): you need a QThread for that to work.

A general rule of thumb might be to use QThreads if you’re going to interact somehow with Qt, and use Python threads otherwise.

And some earlier comment on this subject from PyQt’s author: “they are both wrappers around the same native thread implementations”. And both implementations use GIL in the same way.


回答 1

Python的线程将更简单,更安全,并且由于它用于基于I / O的应用程序,因此它们能够绕过GIL。也就是说,您是否考虑过使用Twisted或非阻塞套接字/选择的非阻塞I / O?

编辑:更多关于线程

Python线程

Python的线程是系统线程。但是,Python使用全局解释器锁(GIL)来确保解释器一次只执行一定大小的字节码指令块。幸运的是,Python在输入/输出操作期间释放了GIL,使线程可用于模拟非阻塞I / O。

重要警告:这可能会引起误解,因为字节码指令的数量与程序中的行数对应。在Python中,即使是单个分配也可能不是原子分配的,因此对于必须原子执行的任何代码块,即使使用GIL,也需要互斥锁。

QT线程

当Python将控制权交给第三方编译模块时,它将释放GIL。在需要时,确保原子性成为模块的责任。当控制权回传时,Python将使用GIL。这可能会使第3方库与线程混淆一起使用。使用外部线程库更加困难,因为它增加了控制权在何时何地掌握在模块和解释器之间的不确定性。

QT线程在释放GIL的情况下运行。QT线程能够同时执行QT库代码(以及其他不获取GIL的已编译模块代码)。然而,QT线程的上下文中执行的Python代码仍然取得GIL,现在你必须要管理2台逻辑的锁定你的代码。

最后,QT线程和Python线程都是系统线程的包装器。Python线程使用起来稍微安全些,因为那些不是用Python编写的部分(隐式使用GIL)在任何情况下都使用GIL(尽管上面的警告仍然适用)。

非阻塞I / O

线程给您的应用程序增加了极大的复杂性。特别是在处理Python解释器和已编译模块代码之间已经很复杂的交互时。尽管许多人发现很难遵循基于事件的编程,但是基于事件的非阻塞I / O通常比线程难得多。

使用异步I / O,您始终可以确保对于每个打开的描述符,执行路径是一致且有序的。显然,有一些必须解决的问题,例如当代码取决于一个打开的通道时该怎么办进一步取决于当另一个打开的通道返回数据时要调用的代码结果。

新的Diesel库是基于事件的非阻塞I / O的一种不错的解决方案。目前,它仅限于Linux,但是它非常快且非常优雅。

还值得您花时间学习pyevent,它是一个出色的libevent库的包装器,它为系统使用最快的可用方法(在编译时确定)提供了基于事件的编程的基本框架。

Python’s threads will be simpler and safer, and since it is for an I/O-based application, they are able to bypass the GIL. That said, have you considered non-blocking I/O using Twisted or non-blocking sockets/select?

EDIT: more on threads

Python threads

Python’s threads are system threads. However, Python uses a global interpreter lock (GIL) to ensure that the interpreter is only ever executing a certain size block of byte-code instructions at a time. Luckily, Python releases the GIL during input/output operations, making threads useful for simulating non-blocking I/O.

Important caveat: This can be misleading, since the number of byte-code instructions does not correspond to the number of lines in a program. Even a single assignment may not be atomic in Python, so a mutex lock is necessary for any block of code that must be executed atomically, even with the GIL.

QT threads

When Python hands off control to a 3rd party compiled module, it releases the GIL. It becomes the responsibility of the module to ensure atomicity where required. When control is passed back, Python will use the GIL. This can make using 3rd party libraries in conjunction with threads confusing. It is even more difficult to use an external threading library because it adds uncertainty as to where and when control is in the hands of the module vs the interpreter.

QT threads operate with the GIL released. QT threads are able to execute QT library code (and other compiled module code that does not acquire the GIL) concurrently. However, the Python code executed within the context of a QT thread still acquires the GIL, and now you have to manage two sets of logic for locking your code.

In the end, both QT threads and Python threads are wrappers around system threads. Python threads are marginally safer to use, since those parts that are not written in Python (implicitly using the GIL) use the GIL in any case (although the caveat above still applies.)

Non-blocking I/O

Threads add extraordinarily complexity to your application. Especially when dealing with the already complex interaction between the Python interpreter and compiled module code. While many find event-based programming difficult to follow, event-based, non-blocking I/O is often much less difficult to reason about than threads.

With asynchronous I/O, you can always be sure that, for each open descriptor, the path of execution is consistent and orderly. There are, obviously, issues that must be addressed, such as what to do when code depending on one open channel further depends on the results of code to be called when another open channel returns data.

One nice solution for event-based, non-blocking I/O is the new Diesel library. It is restricted to Linux at the moment, but it is extraordinarily fast and quite elegant.

It is also worth your time to learn pyevent, a wrapper around the wonderful libevent library, which provides a basic framework for event-based programming using the fastest available method for your system (determined at compile time).


回答 2

优点QThread是它与Qt库的其余部分集成在一起。也就是说,Qt中的线程感知方法将需要知道它们在哪个线程中运行,并且需要在线程之间移动对象QThread。另一个有用的功能是在线程中运行您自己的事件循环。

如果要访问HTTP服务器,则应考虑QNetworkAccessManager

The advantage of QThread is that it’s integrated with the rest of the Qt library. That is, thread-aware methods in Qt will need to know in which thread they run, and to move objects between threads, you will need to use QThread. Another useful feature is running your own event loop in a thread.

If you are accessing a HTTP server, you should consider QNetworkAccessManager.


回答 3

PyTalk上工作时,我问了同样的问题。

如果您使用的是Qt,则需要使用QThread能够使用Qt框架,尤其是信号/插槽系统。

使用信号/插槽引擎,您将能够从一个线程与另一个线程以及项目的每个部分进行对话。

而且,由于这两者都是C ++绑定,因此对于此选择没有太大的性能问题。

这是我对PyQt和线程的经验。

我鼓励你使用QThread

I asked myself the same question when I was working to PyTalk.

If you are using Qt, you need to use QThread to be able to use the Qt framework and expecially the signal/slot system.

With the signal/slot engine, you will be able to talk from a thread to another and with every part of your project.

Moreover, there is not very performance question about this choice since both are a C++ bindings.

Here is my experience of PyQt and thread.

I encourage you to use QThread.


回答 4

杰夫有一些优点。只有一个主线程可以执行任何GUI更新。如果确实需要从线程内更新GUI,则Qt-4的排队连接信号使跨线程发送数据变得容易,并且如果使用QThread,则将自动调用该信号。我不确定您是否正在使用Python线程,尽管可以轻松地向中添加参数connect()

Jeff has some good points. Only one main thread can do any GUI updates. If you do need to update the GUI from within the thread, Qt-4’s queued connection signals make it easy to send data across threads and will automatically be invoked if you’re using QThread; I’m not sure if they will be if you’re using Python threads, although it’s easy to add a parameter to connect().


回答 5

我也不能真正推荐,但是我可以尝试描述CPython和Qt线程之间的区别。

首先,CPython线程不能并发运行,至少不是Python代码。是的,它们确实为每个Python线程创建了系统线程,但是仅允许当前持有“全局解释器锁”的线程运行(C扩展名和FFI代码可能会绕过它,但是当线程不持有GIL时不执行Python字节码)。

另一方面,我们有Qt线程,它们基本上是系统线程上的通用层,没有全局解释器锁定,因此能够并行运行。我不确定PyQt如何处理它,但是除非您的Qt线程调用Python代码,否则它们应该能够并发运行(可能会在各种结构中实现的各种额外锁)。

为了进行额外的微调,您可以修改在切换GIL所有权之前解释的字节码指令的数量-较低的值意味着更多的上下文切换(并且可能会有更高的响应度),但是每个单独线程的性能较低(如果您需要尝试切换每条指令,这对提高速度没有帮助。)

希望它可以帮助您解决问题:)

I can’t really recommend either, but I can try describing differences between CPython and Qt threads.

First of all, CPython threads do not run concurrently, at least not Python code. Yes, they do create system threads for each Python thread, however only the thread currently holding Global Interpreter Lock is allowed to run (C extensions and FFI code might bypass it, but Python bytecode is not executed while thread doesn’t hold GIL).

On the other hand, we have Qt threads, which are basically common layer over system threads, don’t have Global Interpreter Lock, and thus are capable of running concurrently. I’m not sure how PyQt deals with it, however unless your Qt threads call Python code, they should be able to run concurrently (bar various extra locks that might be implemented in various structures).

For extra fine-tuning, you can modify the amount of bytecode instructions that are interpreted before switching ownership of GIL – lower values mean more context switching (and possibly higher responsiveness) but lower performance per individual thread (context switches have their cost – if you try switching every few instructions it doesn’t help speed.)

Hope it helps with your problems :)


回答 6

我无法评论Python和PyQt线程之间的确切差异,但我一直在使用尝试做您想做的事情QThreadQNetworkAcessManager并确保QApplication.processEvents()在线程运行时调用它。如果GUI响应确实是您要解决的问题,则稍后的内容会有所帮助。

I can’t comment on the exact differences between Python and PyQt threads, but I’ve been doing what you’re attempting to do using QThread, QNetworkAcessManager and making sure to call QApplication.processEvents() while the thread is alive. If GUI responsiveness is really the issue you’re trying to solve, the later will help.


如何使用pip在Windows上安装PyQt4?

问题:如何使用pip在Windows上安装PyQt4?

我在Windows上使用Python 3.4。当我运行脚本时,它抱怨

ImportError: No Module named 'PyQt4'

所以我尝试安装它,但是pip install PyQt4

找不到符合要求PyQt4的下载

尽管我跑步时确实会出现pip search PyQt4。我尝试pip install python-qt安装成功,但这并不能解决问题。

我究竟做错了什么?

I’m using Python 3.4 on Windows. When I run a script, it complains

ImportError: No Module named 'PyQt4'

So I tried to install it, but pip install PyQt4 gives

Could not find any downloads that satisfy the requirement PyQt4

although it does show up when I run pip search PyQt4. I tried to pip install python-qt, which installed successfully but that didn’t solve the problem.

What am I doing wrong?


回答 0

这是Chris Golke构建的Windows wheel软件包-Python Windows Binary软件包 -PyQt

在文件名中cp27表示C-python版本2.7,cp35表示python 3.5等。

由于Qt是一个更复杂的系统,它在python接口的基础上提供了已编译的C ++代码库,因此它的构建可能比仅纯python代码包要复杂得多,这意味着很难从源代码安装它。

确保获取正确的Windows wheel文件(python版本,32/64位),然后使用pip进行安装-例如:

C:\path\where\wheel\is\> pip install PyQt4-4.11.4-cp35-none-win_amd64.whl

如果您运行的是Python 3.5的x64版本,则应正确安装。

Here are Windows wheel packages built by Chris Golke – Python Windows Binary packages – PyQt

In the filenames cp27 means C-python version 2.7, cp35 means python 3.5, etc.

Since Qt is a more complicated system with a compiled C++ codebase underlying the python interface it provides you, it can be more complex to build than just a pure python code package, which means it can be hard to install it from source.

Make sure you grab the correct Windows wheel file (python version, 32/64 bit), and then use pip to install it – e.g:

C:\path\where\wheel\is\> pip install PyQt4-4.11.4-cp35-none-win_amd64.whl

Should properly install if you are running an x64 build of Python 3.5.


回答 1

QT不再支持PyQt4,但是您可以通过pip安装PyQt5:

pip install PyQt5

QT no longer supports PyQt4, but you can install PyQt5 with pip:

pip install PyQt5

回答 2

你不能使用点子。您必须从Riverbank网站下载并运行适用于您的python版本的安装程序。如果您的版本没有安装,则必须为可用的安装程序之一安装Python,或者从源代码进行构建(这涉及到)。其他答案和评论都有链接。

You can’t use pip. You have to download from the Riverbank website and run the installer for your version of python. If there is no install for your version, you will have to install Python for one of the available installers, or build from source (which is rather involved). Other answers and comments have the links.


回答 3

如果您在Windows上安装PyQt4,则默认情况下文件会在此处结束:

C:\ Python27 \ Lib \ site-packages \ PyQt4 *。*

但它还会在此处保留文件:

C:\ Python27 \ Lib \ site-packages \ sip.pyd

如果将sip.pyd和PyQt4文件夹都复制到virtualenv中,则一切正常。

例如:

mkdir c:\code
cd c:\code
virtualenv BACKUP
cd c:\code\BACKUP\scripts
activate

然后使用Windows资源管理器从C:\Python27\Lib\site-packages上述文件(sip.pyd)和文件夹(PyQt4)复制到C:\code\BACKUP\Lib\site-packages\

然后回到CLI:

cd ..                 
(c:\code\BACKUP)
python backup.py

尝试启动从virtualenv内部调用PyQt4的脚本的问题在于virtualenv没有安装PyQt4,并且不知道如何引用上述默认安装。但是,请按照以下步骤将PyQt4复制到您的virtualenv中,并且一切正常。

If you install PyQt4 on Windows, files wind up here by default:

C:\Python27\Lib\site-packages\PyQt4*.*

but it also leaves a file here:

C:\Python27\Lib\site-packages\sip.pyd

If you copy the both the sip.pyd and PyQt4 folder into your virtualenv things will work fine.

For example:

mkdir c:\code
cd c:\code
virtualenv BACKUP
cd c:\code\BACKUP\scripts
activate

Then with windows explorer copy from C:\Python27\Lib\site-packages the file (sip.pyd) and folder (PyQt4) mentioned above to C:\code\BACKUP\Lib\site-packages\

Then back at CLI:

cd ..                 
(c:\code\BACKUP)
python backup.py

The problem with trying to launch a script which calls PyQt4 from within virtualenv is that the virtualenv does not have PyQt4 installed and it doesn’t know how to reference the default installation described above. But follow these steps to copy PyQt4 into your virtualenv and things should work great.


回答 4

可以从网站下载页面直接获得较早的PyQt .exe安装程序。现在,随着PyQt4.12的发布,安装程序已被弃用。您可以通过编译它们使库以某种方式工作,但这意味着要花很多时间。

否则,您可以使用以前的发行版来解决您的目的。可以从以下网站下载.exe Windows安装程序:

https://sourceforge.net/projects/pyqt/files/PyQt4/PyQt-4.11.4/

Earlier PyQt .exe installers were available directly from the website download page. Now with the release of PyQt4.12 , installers have been deprecated. You can make the libraries work somehow by compiling them but that would mean going to great lengths of trouble.

Otherwise you can use the previous distributions to solve your purpose. The .exe windows installers can be downloaded from :

https://sourceforge.net/projects/pyqt/files/PyQt4/PyQt-4.11.4/


回答 5

看来您可能需要对PyQt4进行一些手动安装。

http://pyqt.sourceforge.net/Docs/PyQt4/installation.html

这可能会有所帮助,在教程/逐步设置格式中可能会有所帮助:

http://movingthelamppost.com/blog/html/2013/07/12/installing_pyqt____因为_it_s_too_good_for_pip_or_easy_install_.html

It looks like you may have to do a bit of manual installation for PyQt4.

http://pyqt.sourceforge.net/Docs/PyQt4/installation.html

This might help a bit more, it’s a bit more in a tutorial/set-by-step format:

http://movingthelamppost.com/blog/html/2013/07/12/installing_pyqt____because_it_s_too_good_for_pip_or_easy_install_.html


回答 6

使用当前最新的python 3.6.5

pip3 install PyQt5

工作良好

With current latest python 3.6.5

pip3 install PyQt5

works fine


回答 7

尝试使用PyQt5:

pip install PyQt5

链接上将操作系统用于PyQt4。

或在链接上为您的平台下载支持的车轮。

否则,链接可用于Windows可执行安装程序。希望这可以帮助您安装PyQt4或PyQt5。

Try this for PyQt5:

pip install PyQt5

Use the operating system on this link for PyQt4.

Or download the supported wheel for your platform on this link.

Else use this link for the windows executable installer. Hopefully this helps you to install either PyQt4 or PyQt5.


回答 8

对于Windows:

从此处下载适当版本的PyQt4:

并使用pip进行安装(Python3.6的示例-64位)

 pip install PyQt44.11.4cp36cp36mwin_amd64.whl 

For Windows:

download the appropriate version of the PyQt4 from here:

and install it using pip (example for Python3.6 – 64bit)

 pip install PyQt4‑4.11.4‑cp36‑cp36m‑win_amd64.whl 

回答 9

为Windows 10和python 3.5+安装PyQt5。

点安装PyQt5

install PyQt5 for Windows 10 and python 3.5+.

pip install PyQt5


回答 10

如果在安装PyQt4时出错。

错误:此平台不支持PyQt4-4.11.4-cp27-cp27m-win_amd64.whl。

我的系统类型是64位,但要解决这个错误我已经安装了32位Windows系统的PyQt4的,即PyQt4-4.11.4-cp27-cp27m-win32.whl点击这里查看更多版本

请根据您安装的python版本选择合适的PyQt4版本。

If you have error while installing PyQt4.

Error: PyQt4-4.11.4-cp27-cp27m-win_amd64.whl is not a supported wheel on this platform.

My system type is 64 bit, But to solve this error I have installed PyQt4 of 32 bit windows system, i.e PyQt4-4.11.4-cp27-cp27m-win32.whlclick here to see more versions.

Kindly select appropriate version of PyQt4 according to your installed python version.


回答 11

您也可以使用此命令来安装PyQt5。

pip3 install PyQt5

You can also use this command to install PyQt5.

pip3 install PyQt5

回答 12

我正在使用PyCharm,并且能够安装PyQt5。

PyQt4以及PyQt4Enhanced和windows_whl都无法安装,我猜这是因为不再支持Qt4。

I am using PyCharm, and was able to install PyQt5.

PyQt4, as well as PyQt4Enhanced and windows_whl both failed to install, I’m guessing that’s because Qt4 is no longer supported.


更改matplotlib中图的轴,刻度和标签的颜色

问题:更改matplotlib中图的轴,刻度和标签的颜色

我想更改轴的颜色,以及我使用matplotlib和PyQt所做的绘图的刻度和值标签。

有任何想法吗?

I’d like to Change the color of the axis, as well as ticks and value-labels for a plot I did using matplotlib an PyQt.

Any ideas?


回答 0

举一个快速的例子(使用比可能重复的问题稍微干净的方法):

import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.add_subplot(111)

ax.plot(range(10))
ax.set_xlabel('X-axis')
ax.set_ylabel('Y-axis')

ax.spines['bottom'].set_color('red')
ax.spines['top'].set_color('red')
ax.xaxis.label.set_color('red')
ax.tick_params(axis='x', colors='red')

plt.show()

As a quick example (using a slightly cleaner method than the potentially duplicate question):

import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.add_subplot(111)

ax.plot(range(10))
ax.set_xlabel('X-axis')
ax.set_ylabel('Y-axis')

ax.spines['bottom'].set_color('red')
ax.spines['top'].set_color('red')
ax.xaxis.label.set_color('red')
ax.tick_params(axis='x', colors='red')

plt.show()


回答 1

如果您要修改多个图形或子图,则使用matplotlib上下文管理器来更改颜色可能会有所帮助,而不是分别更改每个颜色或子图。上下文管理器允许您仅针对紧随其后的缩进代码临时更改rc参数,但不影响全局rc参数。

此代码段产生两个图形,第一个图形具有修改的轴,刻度线和刻度标签颜色,第二个图形具有默认的rc参数。

import matplotlib.pyplot as plt
with plt.rc_context({'axes.edgecolor':'orange', 'xtick.color':'red', 'ytick.color':'green', 'figure.facecolor':'white'}):
    # Temporary rc parameters in effect
    fig, (ax1, ax2) = plt.subplots(1,2)
    ax1.plot(range(10))
    ax2.plot(range(10))
# Back to default rc parameters
fig, ax = plt.subplots()
ax.plot(range(10))

您可以键入plt.rcParams以查看所有可用的rc参数,并使用列表推导来搜索关键字:

# Search for all parameters containing the word 'color'
[(param, value) for param, value in plt.rcParams.items() if 'color' in param]

If you have several figures or subplots that you want to modify, it can be helpful to use the matplotlib context manager to change the color, instead of changing each one individually. The context manager allows you to temporarily change the rc parameters only for the immediately following indented code, but does not affect the global rc parameters.

This snippet yields two figures, the first one with modified colors for the axis, ticks and ticklabels, and the second one with the default rc parameters.

import matplotlib.pyplot as plt
with plt.rc_context({'axes.edgecolor':'orange', 'xtick.color':'red', 'ytick.color':'green', 'figure.facecolor':'white'}):
    # Temporary rc parameters in effect
    fig, (ax1, ax2) = plt.subplots(1,2)
    ax1.plot(range(10))
    ax2.plot(range(10))
# Back to default rc parameters
fig, ax = plt.subplots()
ax.plot(range(10))

You can type plt.rcParams to view all available rc parameters, and use list comprehension to search for keywords:

# Search for all parameters containing the word 'color'
[(param, value) for param, value in plt.rcParams.items() if 'color' in param]

回答 2

在以前的贡献者的激励下,这是三个轴的示例。

import matplotlib.pyplot as plt

x_values1=[1,2,3,4,5]
y_values1=[1,2,2,4,1]

x_values2=[-1000,-800,-600,-400,-200]
y_values2=[10,20,39,40,50]

x_values3=[150,200,250,300,350]
y_values3=[-10,-20,-30,-40,-50]


fig=plt.figure()
ax=fig.add_subplot(111, label="1")
ax2=fig.add_subplot(111, label="2", frame_on=False)
ax3=fig.add_subplot(111, label="3", frame_on=False)

ax.plot(x_values1, y_values1, color="C0")
ax.set_xlabel("x label 1", color="C0")
ax.set_ylabel("y label 1", color="C0")
ax.tick_params(axis='x', colors="C0")
ax.tick_params(axis='y', colors="C0")

ax2.scatter(x_values2, y_values2, color="C1")
ax2.set_xlabel('x label 2', color="C1") 
ax2.xaxis.set_label_position('bottom') # set the position of the second x-axis to bottom
ax2.spines['bottom'].set_position(('outward', 36))
ax2.tick_params(axis='x', colors="C1")
ax2.set_ylabel('y label 2', color="C1")       
ax2.yaxis.tick_right()
ax2.yaxis.set_label_position('right') 
ax2.tick_params(axis='y', colors="C1")

ax3.plot(x_values3, y_values3, color="C2")
ax3.set_xlabel('x label 3', color='C2')
ax3.xaxis.set_label_position('bottom')
ax3.spines['bottom'].set_position(('outward', 72))
ax3.tick_params(axis='x', colors='C2')
ax3.set_ylabel('y label 3', color='C2')
ax3.yaxis.tick_right()
ax3.yaxis.set_label_position('right') 
ax3.spines['right'].set_position(('outward', 36))
ax3.tick_params(axis='y', colors='C2')


plt.show()

motivated by previous contributors, this is an example of three axes.

import matplotlib.pyplot as plt

x_values1=[1,2,3,4,5]
y_values1=[1,2,2,4,1]

x_values2=[-1000,-800,-600,-400,-200]
y_values2=[10,20,39,40,50]

x_values3=[150,200,250,300,350]
y_values3=[-10,-20,-30,-40,-50]


fig=plt.figure()
ax=fig.add_subplot(111, label="1")
ax2=fig.add_subplot(111, label="2", frame_on=False)
ax3=fig.add_subplot(111, label="3", frame_on=False)

ax.plot(x_values1, y_values1, color="C0")
ax.set_xlabel("x label 1", color="C0")
ax.set_ylabel("y label 1", color="C0")
ax.tick_params(axis='x', colors="C0")
ax.tick_params(axis='y', colors="C0")

ax2.scatter(x_values2, y_values2, color="C1")
ax2.set_xlabel('x label 2', color="C1") 
ax2.xaxis.set_label_position('bottom') # set the position of the second x-axis to bottom
ax2.spines['bottom'].set_position(('outward', 36))
ax2.tick_params(axis='x', colors="C1")
ax2.set_ylabel('y label 2', color="C1")       
ax2.yaxis.tick_right()
ax2.yaxis.set_label_position('right') 
ax2.tick_params(axis='y', colors="C1")

ax3.plot(x_values3, y_values3, color="C2")
ax3.set_xlabel('x label 3', color='C2')
ax3.xaxis.set_label_position('bottom')
ax3.spines['bottom'].set_position(('outward', 72))
ax3.tick_params(axis='x', colors='C2')
ax3.set_ylabel('y label 3', color='C2')
ax3.yaxis.tick_right()
ax3.yaxis.set_label_position('right') 
ax3.spines['right'].set_position(('outward', 36))
ax3.tick_params(axis='y', colors='C2')


plt.show()