标签归档:matplotlib

将x和y标签添加到熊猫图

问题:将x和y标签添加到熊猫图

假设我有以下代码使用pandas绘制了一些非常简单的图形:

import pandas as pd
values = [[1, 2], [2, 5]]
df2 = pd.DataFrame(values, columns=['Type A', 'Type B'], 
                   index=['Index 1', 'Index 2'])
df2.plot(lw=2, colormap='jet', marker='.', markersize=10, 
         title='Video streaming dropout by category')

输出量

如何在保留我使用特定颜色图的能力的同时轻松设置x和y标签?我注意到,plot()pandas DataFrames 的包装没有采用任何特定于此的参数。

Suppose I have the following code that plots something very simple using pandas:

import pandas as pd
values = [[1, 2], [2, 5]]
df2 = pd.DataFrame(values, columns=['Type A', 'Type B'], 
                   index=['Index 1', 'Index 2'])
df2.plot(lw=2, colormap='jet', marker='.', markersize=10, 
         title='Video streaming dropout by category')

Output

How do I easily set x and y-labels while preserving my ability to use specific colormaps? I noticed that the plot() wrapper for pandas DataFrames doesn’t take any parameters specific for that.


回答 0

df.plot()函数返回一个matplotlib.axes.AxesSubplot对象。您可以在该对象上设置标签。

ax = df2.plot(lw=2, colormap='jet', marker='.', markersize=10, title='Video streaming dropout by category')
ax.set_xlabel("x label")
ax.set_ylabel("y label")

在此处输入图片说明

或者,更简洁地说:ax.set(xlabel="x label", ylabel="y label")

或者,索引x轴标签(如果有的话)会自动设置为索引名称。所以df2.index.name = 'x label'也可以。

The df.plot() function returns a matplotlib.axes.AxesSubplot object. You can set the labels on that object.

ax = df2.plot(lw=2, colormap='jet', marker='.', markersize=10, title='Video streaming dropout by category')
ax.set_xlabel("x label")
ax.set_ylabel("y label")

enter image description here

Or, more succinctly: ax.set(xlabel="x label", ylabel="y label").

Alternatively, the index x-axis label is automatically set to the Index name, if it has one. so df2.index.name = 'x label' would work too.


回答 1

您可以像这样使用它:

import matplotlib.pyplot as plt 
import pandas as pd

plt.figure()
values = [[1, 2], [2, 5]]
df2 = pd.DataFrame(values, columns=['Type A', 'Type B'], 
                   index=['Index 1', 'Index 2'])
df2.plot(lw=2, colormap='jet', marker='.', markersize=10,
         title='Video streaming dropout by category')
plt.xlabel('xlabel')
plt.ylabel('ylabel')
plt.show()

显然,您必须将字符串’xlabel’和’ylabel’替换为您想要的名称。

You can use do it like this:

import matplotlib.pyplot as plt 
import pandas as pd

plt.figure()
values = [[1, 2], [2, 5]]
df2 = pd.DataFrame(values, columns=['Type A', 'Type B'], 
                   index=['Index 1', 'Index 2'])
df2.plot(lw=2, colormap='jet', marker='.', markersize=10,
         title='Video streaming dropout by category')
plt.xlabel('xlabel')
plt.ylabel('ylabel')
plt.show()

Obviously you have to replace the strings ‘xlabel’ and ‘ylabel’ with what you want them to be.


回答 2

如果您为DataFrame的列和索引添加标签,熊猫将自动提供适当的标签:

import pandas as pd
values = [[1, 2], [2, 5]]
df = pd.DataFrame(values, columns=['Type A', 'Type B'], 
                  index=['Index 1', 'Index 2'])
df.columns.name = 'Type'
df.index.name = 'Index'
df.plot(lw=2, colormap='jet', marker='.', markersize=10, 
        title='Video streaming dropout by category')

在此处输入图片说明

在这种情况下,您仍然需要手动提供y标签(例如,通过plt.ylabel其他答案所示)。

If you label the columns and index of your DataFrame, pandas will automatically supply appropriate labels:

import pandas as pd
values = [[1, 2], [2, 5]]
df = pd.DataFrame(values, columns=['Type A', 'Type B'], 
                  index=['Index 1', 'Index 2'])
df.columns.name = 'Type'
df.index.name = 'Index'
df.plot(lw=2, colormap='jet', marker='.', markersize=10, 
        title='Video streaming dropout by category')

enter image description here

In this case, you’ll still need to supply y-labels manually (e.g., via plt.ylabel as shown in the other answers).


回答 3

可以同时设置两个标签和axis.set功能。查找示例:

import pandas as pd
import matplotlib.pyplot as plt
values = [[1,2], [2,5]]
df2 = pd.DataFrame(values, columns=['Type A', 'Type B'], index=['Index 1','Index 2'])
ax = df2.plot(lw=2,colormap='jet',marker='.',markersize=10,title='Video streaming dropout by category')
# set labels for both axes
ax.set(xlabel='x axis', ylabel='y axis')
plt.show()

在此处输入图片说明

It is possible to set both labels together with axis.set function. Look for the example:

import pandas as pd
import matplotlib.pyplot as plt
values = [[1,2], [2,5]]
df2 = pd.DataFrame(values, columns=['Type A', 'Type B'], index=['Index 1','Index 2'])
ax = df2.plot(lw=2,colormap='jet',marker='.',markersize=10,title='Video streaming dropout by category')
# set labels for both axes
ax.set(xlabel='x axis', ylabel='y axis')
plt.show()

enter image description here


回答 4

对于您使用的情况pandas.DataFrame.hist

plt = df.Column_A.hist(bins=10)

请注意,您得到的是图的阵列,而不是图。因此,要设置x标签,您将需要执行以下操作

plt[0][0].set_xlabel("column A")

For cases where you use pandas.DataFrame.hist:

plt = df.Column_A.hist(bins=10)

Note that you get an ARRAY of plots, rather than a plot. Thus to set the x label you will need to do something like this

plt[0][0].set_xlabel("column A")

回答 5

关于什么 …

import pandas as pd
import matplotlib.pyplot as plt

values = [[1,2], [2,5]]

df2 = pd.DataFrame(values, columns=['Type A', 'Type B'], index=['Index 1','Index 2'])

(df2.plot(lw=2,
          colormap='jet',
          marker='.',
          markersize=10,
          title='Video streaming dropout by category')
    .set(xlabel='x axis',
         ylabel='y axis'))

plt.show()

what about …

import pandas as pd
import matplotlib.pyplot as plt

values = [[1,2], [2,5]]

df2 = pd.DataFrame(values, columns=['Type A', 'Type B'], index=['Index 1','Index 2'])

(df2.plot(lw=2,
          colormap='jet',
          marker='.',
          markersize=10,
          title='Video streaming dropout by category')
    .set(xlabel='x axis',
         ylabel='y axis'))

plt.show()

回答 6

pandas使用matplotlib基本数据帧图。因此,如果您pandas用于基本绘图,则可以使用matplotlib进行绘图自定义。但是,我在这里提出了一种替代方法,使用seaborn该方法可以对图进行更多的自定义,而不必进入的基本层次matplotlib

工作代码:

import pandas as pd
import seaborn as sns
values = [[1, 2], [2, 5]]
df2 = pd.DataFrame(values, columns=['Type A', 'Type B'], 
                   index=['Index 1', 'Index 2'])
ax= sns.lineplot(data=df2, markers= True)
ax.set(xlabel='xlabel', ylabel='ylabel', title='Video streaming dropout by category') 

在此处输入图片说明

pandas uses matplotlib for basic dataframe plots. So, if you are using pandas for basic plot you can use matplotlib for plot customization. However, I propose an alternative method here using seaborn which allows more customization of the plot while not going into the basic level of matplotlib.

Working Code:

import pandas as pd
import seaborn as sns
values = [[1, 2], [2, 5]]
df2 = pd.DataFrame(values, columns=['Type A', 'Type B'], 
                   index=['Index 1', 'Index 2'])
ax= sns.lineplot(data=df2, markers= True)
ax.set(xlabel='xlabel', ylabel='ylabel', title='Video streaming dropout by category') 

enter image description here


matplotlib错误-没有名为tkinter的模块

问题:matplotlib错误-没有名为tkinter的模块

当我运行以下代码时,我尝试通过Windows 10上的Pycharm IDE使用matplotlib软件包:

from matplotlib import pyplot

我收到以下错误:

ImportError: No module named 'tkinter'

我知道在python 2.x中它叫做Tkinter,但这不是问题-我刚安装了一个全新的python 3.5.1。

编辑:此外,我还尝试导入’tkinter’和’Tkinter’-这些都不起作用(都返回了我提到的错误消息)。

I tried to use the matplotlib package via Pycharm IDE on windows 10. when I run this code:

from matplotlib import pyplot

I get the following error:

ImportError: No module named 'tkinter'

I know that in python 2.x it was called Tkinter, but that is not the problem – I just installed a brand new python 3.5.1.

EDIT: in addition, I also tried to import ‘tkinter’ and ‘Tkinter’ – neither of these worked (both returned the error message I mentioned).


回答 0

sudo apt-get install python3-tk

然后,

>> import tkinter # all fine

编辑

对于Windows,我认为问题是您没有安装完整的Python软件包。由于Tkinter应该随Python一起提供。请参阅:http : //www.tkdocs.com/tutorial/install.html

我建议安装ipython,它也提供功能强大的shell和必要的软件包。

sudo apt-get install python3-tk

Then,

>> import tkinter # all fine

Edit:

For Windows, I think the problem is you didn’t install complete Python package. Since Tkinter should be shipped with Python out of box. See: http://www.tkdocs.com/tutorial/install.html

I suggest install ipython, which provides powerful shell and necessary packages as well.


回答 1

您可以使用

import matplotlib
matplotlib.use('agg')
import matplotlib.pyplot as plt

如果您tkinter根本不想使用。

%matplotlib inline如果要使用笔记本,也不要忘记在笔记本顶部使用。

编辑:agg是不同的后端,如tkintermatplotlib。

you can use

import matplotlib
matplotlib.use('agg')
import matplotlib.pyplot as plt

if you dont want to use tkinter at all.

Also dont forget to use %matplotlib inline at the top of your notebook if using one.

EDIT: agg is a different backend like tkinter for matplotlib.


回答 2

在Centos上,软件包名称和命令是不同的。您需要执行以下操作:

sudo yum install tkinter

解决问题。

On Centos, the package names and commands are different. You’ll need to do:

sudo yum install tkinter

To fix the problem.


回答 3

对于Windows用户,无需再次下载安装程序。只需执行以下操作:

  1. 进入开始菜单,输入“ 程序和功能”
  2. 选择Python版本(对我来说是Python 3.6.5(64位)),
  3. 右键单击,按更改
  4. 点击修改
  5. 选择td / tk和IDLE(将安装tkinter),然后单击下一步

等待安装,您就完成了。

For Windows users, there’s no need to download the installer again. Just do the following:

  1. Go to start menu, type Apps & features,
  2. Search for “python” in the search box,
  3. Select the Python version (e.g. Python 3.8.3rc1(32-bit)) and click Modify,
  4. On the Modify Setup page click Modify,
  5. Tick td/tk and IDLE checkbox (which installs tkinter) and click next.

Wait for installation and you’re done.


回答 4

我搜索此问题的几乎所有答案都说Windows上的Python随附了tkinter和tcl,并且我没有运气尝试使用pip或actviestate.com网站下载或安装它们。我最终发现,当我使用二进制安装程序安装python时,我没有选中与TCL和tkinter相关的模块。因此,我再次运行二进制安装程序,并选择了这次选择此选项来修改我的python版本。然后,无需手动执行任何操作。如果您转到python终端,则以下命令应显示与Python一起安装的tkinter版本:

import tkinter
import _tkinter
tkinter._test()

Almost all answers I searched for this issue say that Python on Windows comes with tkinter and tcl already installed, and I had no luck trying to download or install them using pip, or actviestate.com site. I eventually found that when I was installing python using the binary installer, I had unchecked the module related to TCL and tkinter. So, I ran the binary installer again and chose to modify my python version by this time selecting this option. No need to do anything manually then. If you go to your python terminal, then the following commands should show you version of tkinter installed with your Python:

import tkinter
import _tkinter
tkinter._test()

回答 5

如果您使用的是fedora,请先安装tkinter

sudo dnf install python3-tkinter

我不认为您以后需要导入tkinter我也建议您使用virtualenv

$ python3 -m venv myvenv
$ source myvenv/bin/activate

并使用pip添加必要的软件包

If you are using fedora then first install tkinter

sudo dnf install python3-tkinter

I don’t think you need to import tkinter afterwards I also suggest you to use virtualenv

$ python3 -m venv myvenv
$ source myvenv/bin/activate

And add the necessary packages using pip


回答 6

在CentOS 7和Python 3.4上,命令是 sudo yum install python34-tkinter

在具有Python 3.6的Redhat 7.4上,命令为 sudo yum install rh-python36-python-tkinter

On CentOS 7 and Python 3.4, the command is sudo yum install python34-tkinter

On Redhat 7.4 with Python 3.6, the command is sudo yum install rh-python36-python-tkinter


回答 7

对于Windows用户,请重新运行安装程序。选择修改。选中tcl / tk和IDLE框。此说明说“ Installs tkinter”

For windows users, re-run the installer. Select Modify. Check the box for tcl/tk and IDLE. The description for this says “Installs tkinter”


回答 8

在Ubuntu上,2018年初,python3.6-tkUbuntu的(xenial / 16.04)正态发行版上python-tk没有任何版本,因此即使您拥有较早的版本也无法使用。

我的解决方案是使用设置所有内容python 3.5

 sudo apt install python3.5-tk
 virtualenv --python=`which python3.5` python-env
 source python-env/bin/activate
 pip install -r requirements.txt

现在matplotlib可以找到tkinter

编辑

毕竟我只需要3.6,诀窍是:

sudo apt install tk-dev

然后 之后重建python3.6 tk-dev,例如:

./configure
make
make install

On Ubuntu, early 2018, there is no python3.6-tk on ubuntu’s (xenial/16.04) normal distributions, so even if you have earlier versions of python-tk this won’t work.

My solution was to use set everything up with python 3.5:

 sudo apt install python3.5-tk
 virtualenv --python=`which python3.5` python-env
 source python-env/bin/activate
 pip install -r requirements.txt

And now matplotlib can find tkinter.

EDIT:

I just needed 3.6 afterall, and the trick was to:

sudo apt install tk-dev

and then rebuild python3.6, after tk-dev, eg:

./configure
make
make install

回答 9

如果您使用的是python 3.6,则对我有用:

sudo apt-get install python3.6-tk

代替

sudo apt-get install python3-tk

适用于其他版本的python3

If you are using python 3.6, this worked for me:

sudo apt-get install python3.6-tk

instead of

sudo apt-get install python3-tk

Which works for other versions of python3


回答 10

对于像我这样的可怜人,使用python 3.7。您需要python3.7-tk包装。

sudo apt install python3.7-tk

$ python
Python 3.7.4 (default, Sep  2 2019, 20:44:09)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import tkinter
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'tkinter'
>>> exit()

注意。python3-tk已安装。但是不是python3.7-tk

$ sudo apt install python3.7-tk
Reading package lists... Done
Building dependency tree
Reading state information... Done
Suggested packages:
  tix python3.7-tk-dbg
The following NEW packages will be installed:
  python3.7-tk
0 upgraded, 1 newly installed, 0 to remove and 34 not upgraded.
Need to get 143 kB of archives.
After this operation, 534 kB of additional disk space will be used.
Get:1 http://ppa.launchpad.net/deadsnakes/ppa/ubuntu xenial/main amd64 python3.7-tk amd64 3.7.4-1+xenial2 [143
kB]
Fetched 143 kB in 0s (364 kB/s)
Selecting previously unselected package python3.7-tk:amd64.
(Reading database ... 256375 files and directories currently installed.)
Preparing to unpack .../python3.7-tk_3.7.4-1+xenial2_amd64.deb ...
Unpacking python3.7-tk:amd64 (3.7.4-1+xenial2) ...
Setting up python3.7-tk:amd64 (3.7.4-1+xenial2) ...

安装后,一切都很好。

$ python3
Python 3.7.4 (default, Sep  2 2019, 20:44:09)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import tkinter
>>> exit()

For the poor guys like me using python 3.7. You need the python3.7-tk package.

sudo apt install python3.7-tk

$ python
Python 3.7.4 (default, Sep  2 2019, 20:44:09)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import tkinter
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'tkinter'
>>> exit()

Note. python3-tk is installed. But not python3.7-tk.

$ sudo apt install python3.7-tk
Reading package lists... Done
Building dependency tree
Reading state information... Done
Suggested packages:
  tix python3.7-tk-dbg
The following NEW packages will be installed:
  python3.7-tk
0 upgraded, 1 newly installed, 0 to remove and 34 not upgraded.
Need to get 143 kB of archives.
After this operation, 534 kB of additional disk space will be used.
Get:1 http://ppa.launchpad.net/deadsnakes/ppa/ubuntu xenial/main amd64 python3.7-tk amd64 3.7.4-1+xenial2 [143
kB]
Fetched 143 kB in 0s (364 kB/s)
Selecting previously unselected package python3.7-tk:amd64.
(Reading database ... 256375 files and directories currently installed.)
Preparing to unpack .../python3.7-tk_3.7.4-1+xenial2_amd64.deb ...
Unpacking python3.7-tk:amd64 (3.7.4-1+xenial2) ...
Setting up python3.7-tk:amd64 (3.7.4-1+xenial2) ...

After installing it, all good.

$ python3
Python 3.7.4 (default, Sep  2 2019, 20:44:09)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import tkinter
>>> exit()

回答 11

在带有python 2.7的CentOS 6.5上,我需要这样做: yum install python27-tkinter

On CentOS 6.5 with python 2.7 I needed to do: yum install python27-tkinter


回答 12

有时(例如在osgeo4w发行版中)tkinter被删除。

尝试改变matplotlib后台编辑matplotlibrc位于文件[python install dir]/matplotlib/mpl-data/matplotlibrc变化的后台参数来自backend: TkAgg于其他类似的东西backend: Qt4Agg如下所述:http://matplotlib.org/faq/usage_faq.html#what-is-a-backend

Sometimes (for example in osgeo4w distribution) tkinter is removed.

Try changing matplotlib backend editing matplotlibrc file located in [python install dir]/matplotlib/mpl-data/matplotlibrc changing The backend parameter from backend: TkAgg to something other like backend: Qt4Aggas described here: http://matplotlib.org/faq/usage_faq.html#what-is-a-backend


回答 13

由于我在Ubuntu上使用Python 3.7,因此必须使用:

sudo apt-get install python3.7-tk

Since I’m using Python 3.7 on Ubuntu I had to use:

sudo apt-get install python3.7-tk

回答 14

也许您从源代码安装了python。在这种情况下,您可以在支持tcl / tk的情况下重新编译python。

  1. 从以下位置编译并安装tcl / tk http://www.tcl.tk/software/tcltk/download.html,我假设您在安装了python /home/xxx/local/tcl-tk/
# install tcl
wget -c https://prdownloads.sourceforge.net/tcl/tcl8.6.9-src.tar.gz
tar -xvzf tcl8.6.9-src.tar.gz
cd tcl8.6.9
./configure --prefix=/home/xxx/local/tcl-tk/
make
make install

# install tk
wget -c https://prdownloads.sourceforge.net/tcl/tk8.6.9.1-src.tar.gz
tar -xvzf tk8.6.9.1-src.tar.gz
cd tk8.6.9.1
./configure --prefix=/home/xxx/local/tcl-tk/
make
make install
  1. 使用支持的tcl / tk重新编译python,例如:
# download the source code of python and decompress it first.

cd <your-python-src-dir>
./configure --prefix=/home/xxx/local/python \
 --with-tcltk-includes=/home/xxx/local/tcl-tk/include \
 --with-tcltk-libs=/home/xxx/local/tcl-tk/lib
make 
make install

Maybe you installed python from source. In this case, you can recompile python with tcl/tk supported.

  1. Complie and install tcl/tk from http://www.tcl.tk/software/tcltk/download.html, I’ll suppose you installed python at /home/xxx/local/tcl-tk/.
# install tcl
wget -c https://prdownloads.sourceforge.net/tcl/tcl8.6.9-src.tar.gz
tar -xvzf tcl8.6.9-src.tar.gz
cd tcl8.6.9
./configure --prefix=/home/xxx/local/tcl-tk/
make
make install

# install tk
wget -c https://prdownloads.sourceforge.net/tcl/tk8.6.9.1-src.tar.gz
tar -xvzf tk8.6.9.1-src.tar.gz
cd tk8.6.9.1
./configure --prefix=/home/xxx/local/tcl-tk/
make
make install
  1. Recompile python with tcl/tk supported, for example:
# download the source code of python and decompress it first.

cd <your-python-src-dir>
./configure --prefix=/home/xxx/local/python \
 --with-tcltk-includes=/home/xxx/local/tcl-tk/include \
 --with-tcltk-libs=/home/xxx/local/tcl-tk/lib
make 
make install

_tkinter.TclError:没有显示名称并且没有$ DISPLAY环境变量

问题:_tkinter.TclError:没有显示名称并且没有$ DISPLAY环境变量

我在服务器中运行一个简单的python脚本:

import matplotlib.pyplot as plt
import numpy as np

x = np.random.randn(60)
y = np.random.randn(60)

plt.scatter(x, y, s=20)

out_png = 'path/to/store/out_file.png'
plt.savefig(out_png, dpi=150)

我尝试python example.py在已安装matplotlib 1.5.1的服务器中使用该命令,但失败并显示以下错误:

Traceback (most recent call last):
  File "example.py", line 7, in <module>
    plt.scatter(x, y, s=20)
  File "/home/USER/.virtualenvs/nnet/lib/python2.7/site-packages/matplotlib/pyplot.py", line 3241, in scatter
    ax = gca()
  File "/home/USER/.virtualenvs/nnet/lib/python2.7/site-packages/matplotlib/pyplot.py", line 928, in gca
    return gcf().gca(**kwargs)
  File "/home/USER/.virtualenvs/nnet/lib/python2.7/site-packages/matplotlib/pyplot.py", line 578, in gcf
    return figure()
  File "/home/USER/.virtualenvs/nnet/lib/python2.7/site-packages/matplotlib/pyplot.py", line 527, in figure
**kwargs)
  File "/home/USER/.virtualenvs/nnet/lib/python2.7/site-packages/matplotlib/backends/backend_tkagg.py", line 84, in new_figure_manager
    return new_figure_manager_given_figure(num, figure)
  File "/home/USER/.virtualenvs/nnet/lib/python2.7/site-packages/matplotlib/backends/backend_tkagg.py", line 92, in new_figure_manager_given_figure
    window = Tk.Tk()
  File "/usr/local/lib/python2.7/lib-tk/Tkinter.py", line 1810, in __init__
    self.tk = _tkinter.create(screenName, baseName, className, interactive, wantobjects, useTk, sync, use)
_tkinter.TclError: no display name and no $DISPLAY environment variable

这是怎么回事

I am running a simple python script in the server:

import matplotlib.pyplot as plt
import numpy as np

x = np.random.randn(60)
y = np.random.randn(60)

plt.scatter(x, y, s=20)

out_png = 'path/to/store/out_file.png'
plt.savefig(out_png, dpi=150)

I try to use the command python example.py in this server which has matplotlib 1.5.1 installed it fails with the error:

Traceback (most recent call last):
  File "example.py", line 7, in <module>
    plt.scatter(x, y, s=20)
  File "/home/USER/.virtualenvs/nnet/lib/python2.7/site-packages/matplotlib/pyplot.py", line 3241, in scatter
    ax = gca()
  File "/home/USER/.virtualenvs/nnet/lib/python2.7/site-packages/matplotlib/pyplot.py", line 928, in gca
    return gcf().gca(**kwargs)
  File "/home/USER/.virtualenvs/nnet/lib/python2.7/site-packages/matplotlib/pyplot.py", line 578, in gcf
    return figure()
  File "/home/USER/.virtualenvs/nnet/lib/python2.7/site-packages/matplotlib/pyplot.py", line 527, in figure
**kwargs)
  File "/home/USER/.virtualenvs/nnet/lib/python2.7/site-packages/matplotlib/backends/backend_tkagg.py", line 84, in new_figure_manager
    return new_figure_manager_given_figure(num, figure)
  File "/home/USER/.virtualenvs/nnet/lib/python2.7/site-packages/matplotlib/backends/backend_tkagg.py", line 92, in new_figure_manager_given_figure
    window = Tk.Tk()
  File "/usr/local/lib/python2.7/lib-tk/Tkinter.py", line 1810, in __init__
    self.tk = _tkinter.create(screenName, baseName, className, interactive, wantobjects, useTk, sync, use)
_tkinter.TclError: no display name and no $DISPLAY environment variable

What is happening here?


回答 0

Matplotlib默认情况下选择Xwindows后端。您需要将matplotlib设置为不使用Xwindows后端。

将此代码添加到脚本的开头(在导入pyplot之前),然后重试:

import matplotlib
matplotlib.use('Agg')

或添加到.config/matplotlib/matplotlibrcbackend: Agg以使用非交互式后端。

echo "backend: Agg" > ~/.config/matplotlib/matplotlibrc

或者在连接到服务器时使用ssh -X remoteMachine命令来使用Xwindows。

您也可以尝试导出显示:export DISPLAY=mymachine.com:0.0

有关更多信息:https : //matplotlib.org/faq/howto_faq.html#matplotlib-in-a-web-application-server

Matplotlib chooses Xwindows backend by default. You need to set matplotlib to not use the Xwindows backend.

Add this code to the start of your script (before importing pyplot) and try again:

import matplotlib
matplotlib.use('Agg')

Or add to .config/matplotlib/matplotlibrc line backend: Agg to use non-interactive backend.

echo "backend: Agg" > ~/.config/matplotlib/matplotlibrc

Or when connect to server use ssh -X remoteMachine command to use Xwindows.

Also you may try to export display: export DISPLAY=mymachine.com:0.0.

For more info: https://matplotlib.org/faq/howto_faq.html#matplotlib-in-a-web-application-server


回答 1

您可以通过在.py脚本的非常开头添加这两行来解决此问题。

import matplotlib
matplotlib.use('Agg')

PS:如果在源代码的开头没有添加这两行,则错误仍然存​​在。

You can solve it by adding these two lines in the VERY beginning of your .py script.

import matplotlib
matplotlib.use('Agg')

PS: The error will still exists if these two lines are not added in the very beginning of the source code.


回答 2

为了加总答案,我在所需脚本的开头使用了它。因此它可以在不同的环境下平稳运行。

import os
import matplotlib as mpl
if os.environ.get('DISPLAY','') == '':
    print('no display found. Using non-interactive Agg backend')
    mpl.use('Agg')
import matplotlib.pyplot as plt

因为我不希望它总是使用'Agg'后端,所以仅当它通过Travis CI时才如此。

To add up on the answer, I used this at the beginning of the needed script. So it runs smoothly on different environments.

import os
import matplotlib as mpl
if os.environ.get('DISPLAY','') == '':
    print('no display found. Using non-interactive Agg backend')
    mpl.use('Agg')
import matplotlib.pyplot as plt

Because I didn’t want it to be alsways using the 'Agg' backend, only when it would go through Travis CI for example.


回答 3

我在尝试在Raspberry Pi上远程运行一个简单的tkinter应用程序时遇到了同样的问题。就我而言,我确实希望在pi显示器上显示tkinter GUI,但是我希望能够从主机通过SSH执行它。我也没有使用matplotlib,所以这不是造成我问题的原因。我可以通过将DISPLAY环境变量设置为错误来解决该问题,该错误表明了以下命令:

export DISPLAY=:0.0

可以在此处找到有关显示环境变量的功能以及语法为何如此奇怪的很好的解释:https : //askubuntu.com/questions/432255/what-is-display-environment-variable

I had this same issue trying to run a simple tkinter app remotely on a Raspberry Pi. In my case I did want to display the tkinter GUI on the pi display, but I want to be able to execute it over SSH from my host machine. I was also not using matplotlib, so that wasn’t the cause of my issue. I was able to resolve the issue by setting the DISPLAY environment variable as the error suggests with the command:

export DISPLAY=:0.0

A good explanation of what the display environment variable is doing and why the syntax is so odd can be found here: https://askubuntu.com/questions/432255/what-is-display-environment-variable


回答 4

另一个解决方案是安装Xvfb,然后将显示导出到该文件。即:

disp=:8
screen=0
geom=640x480x24
exec Xvfb $disp -screen $screen $geom 2>/tmp/Xvfb.log &

然后

$ export DISPLAY =:8

$ ./example.py

Another solution is to install Xvfb, and export your display to it. ie:

disp=:8
screen=0
geom=640x480x24
exec Xvfb $disp -screen $screen $geom 2>/tmp/Xvfb.log &

Then

$ export DISPLAY=:8

$ ./example.py


回答 5

在使用Xshell连接Linux服务器时,我也遇到了这个问题。

在寻找方法之后,我找到了Xming + Xshell来解决matplotlib的图像显示问题。

如果上述解决方案不能解决您的问题,请尝试在使用Xshell的条件下下载Xming。然后在Xshell中设置属性,SSH->隧道-> X11transfer->选择X DISPLAY localhost:0.0

I also met this problem while using Xshell to connect Linux server.

After seaching for methods, I find Xming + Xshell to solve image imshow problem with matplotlib.

If solutions aboved can’t solve your problem, just try to download Xming under the condition you’re using Xshell. Then set the attribute in Xshell, SSH->tunnel->X11transfer->choose X DISPLAY localhost:0.0


回答 6

为了查看图像,图解以及远程计算机的Windows上显示的所有内容,您需要像这样连接到它:

ssh -X user@hostname

这样,您就可以访问X服务器。X服务器是X窗口系统中的程序,可在本地计算机(即用户直接使用的计算机)上运行,并处理对这些计算机上的图形卡,显示屏和输入设备(通常是键盘和鼠标)的所有访问。

更多信息在这里

In order to see images, plots and anything displayed on windows on your remote machine you need to connect to it like this:

ssh -X user@hostname

That way you enable the access to the X server. The X server is a program in the X Window System that runs on local machines (i.e., the computers used directly by users) and handles all access to the graphics cards, display screens and input devices (typically a keyboard and mouse) on those computers.

More info here.


使用散点数据集在MatPlotLib中生成热图

问题:使用散点数据集在MatPlotLib中生成热图

我有一组X,Y数据点(大约10k),易于绘制为散点图,但我想将其表示为热图。

我浏览了MatPlotLib中的示例,它们似乎都已经从热图单元格值开始以生成图像。

有没有一种方法可以将所有不同的x,y转换为热图(其中x,y的频率较高的区域会“变暖”)?

I have a set of X,Y data points (about 10k) that are easy to plot as a scatter plot but that I would like to represent as a heatmap.

I looked through the examples in MatPlotLib and they all seem to already start with heatmap cell values to generate the image.

Is there a method that converts a bunch of x,y, all different, to a heatmap (where zones with higher frequency of x,y would be “warmer”)?


回答 0

如果您不想要六角形,可以使用numpy的histogram2d函数:

import numpy as np
import numpy.random
import matplotlib.pyplot as plt

# Generate some test data
x = np.random.randn(8873)
y = np.random.randn(8873)

heatmap, xedges, yedges = np.histogram2d(x, y, bins=50)
extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]]

plt.clf()
plt.imshow(heatmap.T, extent=extent, origin='lower')
plt.show()

这将产生50×50的热图。如果您想要512×384,则可以bins=(512, 384)拨打histogram2d

例: Matplotlib热图示例

If you don’t want hexagons, you can use numpy’s histogram2d function:

import numpy as np
import numpy.random
import matplotlib.pyplot as plt

# Generate some test data
x = np.random.randn(8873)
y = np.random.randn(8873)

heatmap, xedges, yedges = np.histogram2d(x, y, bins=50)
extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]]

plt.clf()
plt.imshow(heatmap.T, extent=extent, origin='lower')
plt.show()

This makes a 50×50 heatmap. If you want, say, 512×384, you can put bins=(512, 384) in the call to histogram2d.

Example: Matplotlib heat map example


回答 1

Matplotlib词典中,我认为您想要一个十六进制图。

如果您对这种类型的图不熟悉,它只是一个二元直方图,其中xy平面由六边形的规则网格细分。

因此,从直方图中,您可以仅计算落在每个六边形中的点数,将绘制区域离散为一组窗口,将每个点分配给这些窗口中的一个;最后,将窗口映射到颜色数组上,您将获得一个六边形图。

尽管不如圆形或正方形那样普遍使用,但对于合并容器的几何形状来说,六角形是更好的选择,这很直观:

  • 六边形具有最近邻对称性(例如,正方形容器不对称,例如,正方形边界的点到该正方形内的点的距离并不都相等),并且

  • 六角形是提供规则平面细分的最高n多边形(即,您可以安全地用六角形瓷砖重新建模厨房地板,因为完成后在瓷砖之间将没有任何空隙空间-对于所有其他高-n,n> = 7,多边形)。

Matplotlib使用术语hexbin plot;(AFAIK)也使用R的所有绘图库 ;我仍然不知道这是否是此类绘图的公认术语,尽管我怀疑hexbin很短用于六角装仓,它描述了准备显示数据的基本步骤。)


from matplotlib import pyplot as PLT
from matplotlib import cm as CM
from matplotlib import mlab as ML
import numpy as NP

n = 1e5
x = y = NP.linspace(-5, 5, 100)
X, Y = NP.meshgrid(x, y)
Z1 = ML.bivariate_normal(X, Y, 2, 2, 0, 0)
Z2 = ML.bivariate_normal(X, Y, 4, 1, 1, 1)
ZD = Z2 - Z1
x = X.ravel()
y = Y.ravel()
z = ZD.ravel()
gridsize=30
PLT.subplot(111)

# if 'bins=None', then color of each hexagon corresponds directly to its count
# 'C' is optional--it maps values to x-y coordinates; if 'C' is None (default) then 
# the result is a pure 2D histogram 

PLT.hexbin(x, y, C=z, gridsize=gridsize, cmap=CM.jet, bins=None)
PLT.axis([x.min(), x.max(), y.min(), y.max()])

cb = PLT.colorbar()
cb.set_label('mean value')
PLT.show()   

在此处输入图片说明

In Matplotlib lexicon, i think you want a hexbin plot.

If you’re not familiar with this type of plot, it’s just a bivariate histogram in which the xy-plane is tessellated by a regular grid of hexagons.

So from a histogram, you can just count the number of points falling in each hexagon, discretiize the plotting region as a set of windows, assign each point to one of these windows; finally, map the windows onto a color array, and you’ve got a hexbin diagram.

Though less commonly used than e.g., circles, or squares, that hexagons are a better choice for the geometry of the binning container is intuitive:

  • hexagons have nearest-neighbor symmetry (e.g., square bins don’t, e.g., the distance from a point on a square’s border to a point inside that square is not everywhere equal) and

  • hexagon is the highest n-polygon that gives regular plane tessellation (i.e., you can safely re-model your kitchen floor with hexagonal-shaped tiles because you won’t have any void space between the tiles when you are finished–not true for all other higher-n, n >= 7, polygons).

(Matplotlib uses the term hexbin plot; so do (AFAIK) all of the plotting libraries for R; still i don’t know if this is the generally accepted term for plots of this type, though i suspect it’s likely given that hexbin is short for hexagonal binning, which is describes the essential step in preparing the data for display.)


from matplotlib import pyplot as PLT
from matplotlib import cm as CM
from matplotlib import mlab as ML
import numpy as NP

n = 1e5
x = y = NP.linspace(-5, 5, 100)
X, Y = NP.meshgrid(x, y)
Z1 = ML.bivariate_normal(X, Y, 2, 2, 0, 0)
Z2 = ML.bivariate_normal(X, Y, 4, 1, 1, 1)
ZD = Z2 - Z1
x = X.ravel()
y = Y.ravel()
z = ZD.ravel()
gridsize=30
PLT.subplot(111)

# if 'bins=None', then color of each hexagon corresponds directly to its count
# 'C' is optional--it maps values to x-y coordinates; if 'C' is None (default) then 
# the result is a pure 2D histogram 

PLT.hexbin(x, y, C=z, gridsize=gridsize, cmap=CM.jet, bins=None)
PLT.axis([x.min(), x.max(), y.min(), y.max()])

cb = PLT.colorbar()
cb.set_label('mean value')
PLT.show()   

enter image description here


回答 2

编辑:对于亚历杭德罗的答案的更好的近似,请参见下文。

我知道这是一个古老的问题,但是想在Alejandro的anwser中添加一些内容:如果您想要一个很好的平滑图像而不使用py-sphviewer,则可以使用np.histogram2d高斯滤镜并将其应用于scipy.ndimage.filters热图:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from scipy.ndimage.filters import gaussian_filter


def myplot(x, y, s, bins=1000):
    heatmap, xedges, yedges = np.histogram2d(x, y, bins=bins)
    heatmap = gaussian_filter(heatmap, sigma=s)

    extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]]
    return heatmap.T, extent


fig, axs = plt.subplots(2, 2)

# Generate some test data
x = np.random.randn(1000)
y = np.random.randn(1000)

sigmas = [0, 16, 32, 64]

for ax, s in zip(axs.flatten(), sigmas):
    if s == 0:
        ax.plot(x, y, 'k.', markersize=5)
        ax.set_title("Scatter plot")
    else:
        img, extent = myplot(x, y, s)
        ax.imshow(img, extent=extent, origin='lower', cmap=cm.jet)
        ax.set_title("Smoothing with  $\sigma$ = %d" % s)

plt.show()

生成:

输出图像

Agape Gal’lo的散点图和s = 16画在彼此的顶部(单击以获得更好的视图):

在彼此之上


我在高斯滤波器方法和亚历杭德罗方法中注意到的一个区别是,他的方法显示的局部结构比我的方法好得多。因此,我在像素级别实现了一个简单的最近邻方法。该方法为每个像素计算距离的倒数和。n数据中最接近点。这种方法的高分辨率计算量很大,我认为有一种更快的方法,因此,如果您有任何改进,请告诉我。

更新:我怀疑,使用Scipy’s的方法要快得多scipy.cKDTree。有关实现,请参见加百利的答案

无论如何,这是我的代码:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm


def data_coord2view_coord(p, vlen, pmin, pmax):
    dp = pmax - pmin
    dv = (p - pmin) / dp * vlen
    return dv


def nearest_neighbours(xs, ys, reso, n_neighbours):
    im = np.zeros([reso, reso])
    extent = [np.min(xs), np.max(xs), np.min(ys), np.max(ys)]

    xv = data_coord2view_coord(xs, reso, extent[0], extent[1])
    yv = data_coord2view_coord(ys, reso, extent[2], extent[3])
    for x in range(reso):
        for y in range(reso):
            xp = (xv - x)
            yp = (yv - y)

            d = np.sqrt(xp**2 + yp**2)

            im[y][x] = 1 / np.sum(d[np.argpartition(d.ravel(), n_neighbours)[:n_neighbours]])

    return im, extent


n = 1000
xs = np.random.randn(n)
ys = np.random.randn(n)
resolution = 250

fig, axes = plt.subplots(2, 2)

for ax, neighbours in zip(axes.flatten(), [0, 16, 32, 64]):
    if neighbours == 0:
        ax.plot(xs, ys, 'k.', markersize=2)
        ax.set_aspect('equal')
        ax.set_title("Scatter Plot")
    else:
        im, extent = nearest_neighbours(xs, ys, resolution, neighbours)
        ax.imshow(im, origin='lower', extent=extent, cmap=cm.jet)
        ax.set_title("Smoothing over %d neighbours" % neighbours)
        ax.set_xlim(extent[0], extent[1])
        ax.set_ylim(extent[2], extent[3])
plt.show()

结果:

最近邻平滑

Edit: For a better approximation of Alejandro’s answer, see below.

I know this is an old question, but wanted to add something to Alejandro’s anwser: If you want a nice smoothed image without using py-sphviewer you can instead use np.histogram2d and apply a gaussian filter (from scipy.ndimage.filters) to the heatmap:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from scipy.ndimage.filters import gaussian_filter


def myplot(x, y, s, bins=1000):
    heatmap, xedges, yedges = np.histogram2d(x, y, bins=bins)
    heatmap = gaussian_filter(heatmap, sigma=s)

    extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]]
    return heatmap.T, extent


fig, axs = plt.subplots(2, 2)

# Generate some test data
x = np.random.randn(1000)
y = np.random.randn(1000)

sigmas = [0, 16, 32, 64]

for ax, s in zip(axs.flatten(), sigmas):
    if s == 0:
        ax.plot(x, y, 'k.', markersize=5)
        ax.set_title("Scatter plot")
    else:
        img, extent = myplot(x, y, s)
        ax.imshow(img, extent=extent, origin='lower', cmap=cm.jet)
        ax.set_title("Smoothing with  $\sigma$ = %d" % s)

plt.show()

Produces:

Output images

The scatter plot and s=16 plotted on top of eachother for Agape Gal’lo (click for better view):

On top of eachother


One difference I noticed with my gaussian filter approach and Alejandro’s approach was that his method shows local structures much better than mine. Therefore I implemented a simple nearest neighbour method at pixel level. This method calculates for each pixel the inverse sum of the distances of the n closest points in the data. This method is at a high resolution pretty computationally expensive and I think there’s a quicker way, so let me know if you have any improvements.

Update: As I suspected, there’s a much faster method using Scipy’s scipy.cKDTree. See Gabriel’s answer for the implementation.

Anyway, here’s my code:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm


def data_coord2view_coord(p, vlen, pmin, pmax):
    dp = pmax - pmin
    dv = (p - pmin) / dp * vlen
    return dv


def nearest_neighbours(xs, ys, reso, n_neighbours):
    im = np.zeros([reso, reso])
    extent = [np.min(xs), np.max(xs), np.min(ys), np.max(ys)]

    xv = data_coord2view_coord(xs, reso, extent[0], extent[1])
    yv = data_coord2view_coord(ys, reso, extent[2], extent[3])
    for x in range(reso):
        for y in range(reso):
            xp = (xv - x)
            yp = (yv - y)

            d = np.sqrt(xp**2 + yp**2)

            im[y][x] = 1 / np.sum(d[np.argpartition(d.ravel(), n_neighbours)[:n_neighbours]])

    return im, extent


n = 1000
xs = np.random.randn(n)
ys = np.random.randn(n)
resolution = 250

fig, axes = plt.subplots(2, 2)

for ax, neighbours in zip(axes.flatten(), [0, 16, 32, 64]):
    if neighbours == 0:
        ax.plot(xs, ys, 'k.', markersize=2)
        ax.set_aspect('equal')
        ax.set_title("Scatter Plot")
    else:
        im, extent = nearest_neighbours(xs, ys, resolution, neighbours)
        ax.imshow(im, origin='lower', extent=extent, cmap=cm.jet)
        ax.set_title("Smoothing over %d neighbours" % neighbours)
        ax.set_xlim(extent[0], extent[1])
        ax.set_ylim(extent[2], extent[3])
plt.show()

Result:

Nearest Neighbour Smoothing


回答 3

我不想使用np.hist2d(通常会产生非常难看的直方图),而是要回收py-sphviewer,这是一个使用自适应平滑内核渲染粒子模拟的python包,可以从pip轻松安装(请参阅网页文档)。考虑以下基于示例的代码:

import numpy as np
import numpy.random
import matplotlib.pyplot as plt
import sphviewer as sph

def myplot(x, y, nb=32, xsize=500, ysize=500):   
    xmin = np.min(x)
    xmax = np.max(x)
    ymin = np.min(y)
    ymax = np.max(y)

    x0 = (xmin+xmax)/2.
    y0 = (ymin+ymax)/2.

    pos = np.zeros([3, len(x)])
    pos[0,:] = x
    pos[1,:] = y
    w = np.ones(len(x))

    P = sph.Particles(pos, w, nb=nb)
    S = sph.Scene(P)
    S.update_camera(r='infinity', x=x0, y=y0, z=0, 
                    xsize=xsize, ysize=ysize)
    R = sph.Render(S)
    R.set_logscale()
    img = R.get_image()
    extent = R.get_extent()
    for i, j in zip(xrange(4), [x0,x0,y0,y0]):
        extent[i] += j
    print extent
    return img, extent

fig = plt.figure(1, figsize=(10,10))
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222)
ax3 = fig.add_subplot(223)
ax4 = fig.add_subplot(224)


# Generate some test data
x = np.random.randn(1000)
y = np.random.randn(1000)

#Plotting a regular scatter plot
ax1.plot(x,y,'k.', markersize=5)
ax1.set_xlim(-3,3)
ax1.set_ylim(-3,3)

heatmap_16, extent_16 = myplot(x,y, nb=16)
heatmap_32, extent_32 = myplot(x,y, nb=32)
heatmap_64, extent_64 = myplot(x,y, nb=64)

ax2.imshow(heatmap_16, extent=extent_16, origin='lower', aspect='auto')
ax2.set_title("Smoothing over 16 neighbors")

ax3.imshow(heatmap_32, extent=extent_32, origin='lower', aspect='auto')
ax3.set_title("Smoothing over 32 neighbors")

#Make the heatmap using a smoothing over 64 neighbors
ax4.imshow(heatmap_64, extent=extent_64, origin='lower', aspect='auto')
ax4.set_title("Smoothing over 64 neighbors")

plt.show()

产生以下图像:

在此处输入图片说明

如您所见,图像看起来非常漂亮,并且我们能够在其上标识不同的子结构。这些图像被构造成在一定范围内为每个点散布给定的权重,该权重由平滑长度定义,而平滑长度又由与更近的nb个邻居的距离给出(示例中,我选择了16、32和64)。因此,与较低密度的区域相比,较高密度的区域通常分布在较小的区域。

函数myplot只是我编写的一个非常简单的函数,用于将x,y数据提供给py-sphviewer进行处理。

Instead of using np.hist2d, which in general produces quite ugly histograms, I would like to recycle py-sphviewer, a python package for rendering particle simulations using an adaptive smoothing kernel and that can be easily installed from pip (see webpage documentation). Consider the following code, which is based on the example:

import numpy as np
import numpy.random
import matplotlib.pyplot as plt
import sphviewer as sph

def myplot(x, y, nb=32, xsize=500, ysize=500):   
    xmin = np.min(x)
    xmax = np.max(x)
    ymin = np.min(y)
    ymax = np.max(y)

    x0 = (xmin+xmax)/2.
    y0 = (ymin+ymax)/2.

    pos = np.zeros([3, len(x)])
    pos[0,:] = x
    pos[1,:] = y
    w = np.ones(len(x))

    P = sph.Particles(pos, w, nb=nb)
    S = sph.Scene(P)
    S.update_camera(r='infinity', x=x0, y=y0, z=0, 
                    xsize=xsize, ysize=ysize)
    R = sph.Render(S)
    R.set_logscale()
    img = R.get_image()
    extent = R.get_extent()
    for i, j in zip(xrange(4), [x0,x0,y0,y0]):
        extent[i] += j
    print extent
    return img, extent

fig = plt.figure(1, figsize=(10,10))
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222)
ax3 = fig.add_subplot(223)
ax4 = fig.add_subplot(224)


# Generate some test data
x = np.random.randn(1000)
y = np.random.randn(1000)

#Plotting a regular scatter plot
ax1.plot(x,y,'k.', markersize=5)
ax1.set_xlim(-3,3)
ax1.set_ylim(-3,3)

heatmap_16, extent_16 = myplot(x,y, nb=16)
heatmap_32, extent_32 = myplot(x,y, nb=32)
heatmap_64, extent_64 = myplot(x,y, nb=64)

ax2.imshow(heatmap_16, extent=extent_16, origin='lower', aspect='auto')
ax2.set_title("Smoothing over 16 neighbors")

ax3.imshow(heatmap_32, extent=extent_32, origin='lower', aspect='auto')
ax3.set_title("Smoothing over 32 neighbors")

#Make the heatmap using a smoothing over 64 neighbors
ax4.imshow(heatmap_64, extent=extent_64, origin='lower', aspect='auto')
ax4.set_title("Smoothing over 64 neighbors")

plt.show()

which produces the following image:

enter image description here

As you see, the images look pretty nice, and we are able to identify different substructures on it. These images are constructed spreading a given weight for every point within a certain domain, defined by the smoothing length, which in turns is given by the distance to the closer nb neighbor (I’ve chosen 16, 32 and 64 for the examples). So, higher density regions typically are spread over smaller regions compared to lower density regions.

The function myplot is just a very simple function that I’ve written in order to give the x,y data to py-sphviewer to do the magic.


回答 4

如果您使用的是1.2.x

import numpy as np
import matplotlib.pyplot as plt

x = np.random.randn(100000)
y = np.random.randn(100000)
plt.hist2d(x,y,bins=100)
plt.show()

gaussian_2d_heat_map

If you are using 1.2.x

import numpy as np
import matplotlib.pyplot as plt

x = np.random.randn(100000)
y = np.random.randn(100000)
plt.hist2d(x,y,bins=100)
plt.show()

gaussian_2d_heat_map


回答 5

Seaborn现在具有jointplot函数,在这里应该可以很好地工作:

import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt

# Generate some test data
x = np.random.randn(8873)
y = np.random.randn(8873)

sns.jointplot(x=x, y=y, kind='hex')
plt.show()

演示图片

Seaborn now has the jointplot function which should work nicely here:

import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt

# Generate some test data
x = np.random.randn(8873)
y = np.random.randn(8873)

sns.jointplot(x=x, y=y, kind='hex')
plt.show()

demo image


回答 6

最初的问题是…如何将分散值转换为网格值,对吗? histogram2d确实会计算每个单元格的频率,但是,如果每个单元格除频率之外还有其他数据,则需要做一些额外的工作。

x = data_x # between -10 and 4, log-gamma of an svc
y = data_y # between -4 and 11, log-C of an svc
z = data_z #between 0 and 0.78, f1-values from a difficult dataset

因此,我有一个Z值的X和Y坐标数据集。但是,我在计算感兴趣区域之外的几个点(较大的差距),而在很小的感兴趣区域中计算出很多点。

是的,这里变得更加困难,但同时也更加有趣。一些库(对不起):

from matplotlib import pyplot as plt
from matplotlib import cm
import numpy as np
from scipy.interpolate import griddata

pyplot是我今天的图形引擎,cm是一系列颜色图,其中包含一些令人鼓舞的选择。numpy用于计算,griddata用于将值附加到固定网格。

最后一个很重要,特别是因为xy点的频率在我的数据中分布不均。首先,让我们从适合我的数据的边界和任意的网格大小开始。原始数据的数据点也在这些x和y边界之外。

#determine grid boundaries
gridsize = 500
x_min = -8
x_max = 2.5
y_min = -2
y_max = 7

因此,我们定义了一个在x和y的最小值和最大值之间具有500个像素的网格。

在我的数据中,最受关注的领域有500多个可用值。而在低息区域,整个网格中甚至没有200个值;的图形边界之间x_min,并x_max有更小。

因此,为了获得良好的画面,任务是获取高利息值的平均值并填补其他地方的空白。

我现在定义网格。对于每个xx-yy对,我想要一种颜色。

xx = np.linspace(x_min, x_max, gridsize) # array of x values
yy = np.linspace(y_min, y_max, gridsize) # array of y values
grid = np.array(np.meshgrid(xx, yy.T))
grid = grid.reshape(2, grid.shape[1]*grid.shape[2]).T

为什么形状奇怪?scipy.griddata的形状为(n,D)。

Griddata通过预定义的方法为网格中的每个点计算一个值。我选择“最近”-空的网格点将填充最近邻居的值。这看起来好像信息较少的区域具有较大的单元格(即使不是这种情况)。人们可以选择插值“线性”,然后信息较少的区域看起来不那么清晰。味道很重要。

points = np.array([x, y]).T # because griddata wants it that way
z_grid2 = griddata(points, z, grid, method='nearest')
# you get a 1D vector as result. Reshape to picture format!
z_grid2 = z_grid2.reshape(xx.shape[0], yy.shape[0])

跳,我们移交给matplotlib显示图

fig = plt.figure(1, figsize=(10, 10))
ax1 = fig.add_subplot(111)
ax1.imshow(z_grid2, extent=[x_min, x_max,y_min, y_max,  ],
            origin='lower', cmap=cm.magma)
ax1.set_title("SVC: empty spots filled by nearest neighbours")
ax1.set_xlabel('log gamma')
ax1.set_ylabel('log C')
plt.show()

在V形的尖角部分周围,您会发现在寻找最佳点时我做了很多计算,而几乎其他任何地方的不那么有趣的部分的分辨率都较低。

高分辨率SVC的热图

and the initial question was… how to convert scatter values to grid values, right? histogram2d does count the frequency per cell, however, if you have other data per cell than just the frequency, you’d need some additional work to do.

x = data_x # between -10 and 4, log-gamma of an svc
y = data_y # between -4 and 11, log-C of an svc
z = data_z #between 0 and 0.78, f1-values from a difficult dataset

So, I have a dataset with Z-results for X and Y coordinates. However, I was calculating few points outside the area of interest (large gaps), and heaps of points in a small area of interest.

Yes here it becomes more difficult but also more fun. Some libraries (sorry):

from matplotlib import pyplot as plt
from matplotlib import cm
import numpy as np
from scipy.interpolate import griddata

pyplot is my graphic engine today, cm is a range of color maps with some initeresting choice. numpy for the calculations, and griddata for attaching values to a fixed grid.

The last one is important especially because the frequency of xy points is not equally distributed in my data. First, let’s start with some boundaries fitting to my data and an arbitrary grid size. The original data has datapoints also outside those x and y boundaries.

#determine grid boundaries
gridsize = 500
x_min = -8
x_max = 2.5
y_min = -2
y_max = 7

So we have defined a grid with 500 pixels between the min and max values of x and y.

In my data, there are lots more than the 500 values available in the area of high interest; whereas in the low-interest-area, there are not even 200 values in the total grid; between the graphic boundaries of x_min and x_max there are even less.

So for getting a nice picture, the task is to get an average for the high interest values and to fill the gaps elsewhere.

I define my grid now. For each xx-yy pair, i want to have a color.

xx = np.linspace(x_min, x_max, gridsize) # array of x values
yy = np.linspace(y_min, y_max, gridsize) # array of y values
grid = np.array(np.meshgrid(xx, yy.T))
grid = grid.reshape(2, grid.shape[1]*grid.shape[2]).T

Why the strange shape? scipy.griddata wants a shape of (n, D).

Griddata calculates one value per point in the grid, by a predefined method. I choose “nearest” – empty grid points will be filled with values from the nearest neighbor. This looks as if the areas with less information have bigger cells (even if it is not the case). One could choose to interpolate “linear”, then areas with less information look less sharp. Matter of taste, really.

points = np.array([x, y]).T # because griddata wants it that way
z_grid2 = griddata(points, z, grid, method='nearest')
# you get a 1D vector as result. Reshape to picture format!
z_grid2 = z_grid2.reshape(xx.shape[0], yy.shape[0])

And hop, we hand over to matplotlib to display the plot

fig = plt.figure(1, figsize=(10, 10))
ax1 = fig.add_subplot(111)
ax1.imshow(z_grid2, extent=[x_min, x_max,y_min, y_max,  ],
            origin='lower', cmap=cm.magma)
ax1.set_title("SVC: empty spots filled by nearest neighbours")
ax1.set_xlabel('log gamma')
ax1.set_ylabel('log C')
plt.show()

Around the pointy part of the V-Shape, you see I did a lot of calculations during my search for the sweet spot, whereas the less interesting parts almost everywhere else have a lower resolution.

Heatmap of a SVC in high resolution


回答 7

这是Jurgy最理想的最近邻居方法,但使用scipy.cKDTree实现。在我的测试中,速度提高了约100倍。

在此处输入图片说明

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from scipy.spatial import cKDTree


def data_coord2view_coord(p, resolution, pmin, pmax):
    dp = pmax - pmin
    dv = (p - pmin) / dp * resolution
    return dv


n = 1000
xs = np.random.randn(n)
ys = np.random.randn(n)

resolution = 250

extent = [np.min(xs), np.max(xs), np.min(ys), np.max(ys)]
xv = data_coord2view_coord(xs, resolution, extent[0], extent[1])
yv = data_coord2view_coord(ys, resolution, extent[2], extent[3])


def kNN2DDens(xv, yv, resolution, neighbours, dim=2):
    """
    """
    # Create the tree
    tree = cKDTree(np.array([xv, yv]).T)
    # Find the closest nnmax-1 neighbors (first entry is the point itself)
    grid = np.mgrid[0:resolution, 0:resolution].T.reshape(resolution**2, dim)
    dists = tree.query(grid, neighbours)
    # Inverse of the sum of distances to each grid point.
    inv_sum_dists = 1. / dists[0].sum(1)

    # Reshape
    im = inv_sum_dists.reshape(resolution, resolution)
    return im


fig, axes = plt.subplots(2, 2, figsize=(15, 15))
for ax, neighbours in zip(axes.flatten(), [0, 16, 32, 63]):

    if neighbours == 0:
        ax.plot(xs, ys, 'k.', markersize=5)
        ax.set_aspect('equal')
        ax.set_title("Scatter Plot")
    else:

        im = kNN2DDens(xv, yv, resolution, neighbours)

        ax.imshow(im, origin='lower', extent=extent, cmap=cm.Blues)
        ax.set_title("Smoothing over %d neighbours" % neighbours)
        ax.set_xlim(extent[0], extent[1])
        ax.set_ylim(extent[2], extent[3])

plt.savefig('new.png', dpi=150, bbox_inches='tight')

Here’s Jurgy’s great nearest neighbour approach but implemented using scipy.cKDTree. In my tests it’s about 100x faster.

enter image description here

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from scipy.spatial import cKDTree


def data_coord2view_coord(p, resolution, pmin, pmax):
    dp = pmax - pmin
    dv = (p - pmin) / dp * resolution
    return dv


n = 1000
xs = np.random.randn(n)
ys = np.random.randn(n)

resolution = 250

extent = [np.min(xs), np.max(xs), np.min(ys), np.max(ys)]
xv = data_coord2view_coord(xs, resolution, extent[0], extent[1])
yv = data_coord2view_coord(ys, resolution, extent[2], extent[3])


def kNN2DDens(xv, yv, resolution, neighbours, dim=2):
    """
    """
    # Create the tree
    tree = cKDTree(np.array([xv, yv]).T)
    # Find the closest nnmax-1 neighbors (first entry is the point itself)
    grid = np.mgrid[0:resolution, 0:resolution].T.reshape(resolution**2, dim)
    dists = tree.query(grid, neighbours)
    # Inverse of the sum of distances to each grid point.
    inv_sum_dists = 1. / dists[0].sum(1)

    # Reshape
    im = inv_sum_dists.reshape(resolution, resolution)
    return im


fig, axes = plt.subplots(2, 2, figsize=(15, 15))
for ax, neighbours in zip(axes.flatten(), [0, 16, 32, 63]):

    if neighbours == 0:
        ax.plot(xs, ys, 'k.', markersize=5)
        ax.set_aspect('equal')
        ax.set_title("Scatter Plot")
    else:

        im = kNN2DDens(xv, yv, resolution, neighbours)

        ax.imshow(im, origin='lower', extent=extent, cmap=cm.Blues)
        ax.set_title("Smoothing over %d neighbours" % neighbours)
        ax.set_xlim(extent[0], extent[1])
        ax.set_ylim(extent[2], extent[3])

plt.savefig('new.png', dpi=150, bbox_inches='tight')

回答 8

制作一个与最终图像中的单元格相对应的二维数组,称为say,heatmap_cells并将其实例化为全零。

选择两个缩放因子,它们定义每个维度的实际单位中每个数组元素之间的差异,例如x_scaley_scale。选择这些,使您的所有数据点都落在热图数组的范围内。

对于每个带有x_value和的原始数据点y_value

heatmap_cells[floor(x_value/x_scale),floor(y_value/y_scale)]+=1

Make a 2-dimensional array that corresponds to the cells in your final image, called say heatmap_cells and instantiate it as all zeroes.

Choose two scaling factors that define the difference between each array element in real units, for each dimension, say x_scale and y_scale. Choose these such that all your datapoints will fall within the bounds of the heatmap array.

For each raw datapoint with x_value and y_value:

heatmap_cells[floor(x_value/x_scale),floor(y_value/y_scale)]+=1


回答 9

在此处输入图片说明

这是我在100万个点集上制作的,其中包括3个类别(红色,绿色和蓝色)。如果您想尝试使用此功能,请点击这里。Github回购

histplot(
    X,
    Y,
    labels,
    bins=2000,
    range=((-3,3),(-3,3)),
    normalize_each_label=True,
    colors = [
        [1,0,0],
        [0,1,0],
        [0,0,1]],
    gain=50)

enter image description here

Here’s one I made on a 1 Million point set with 3 categories (colored Red, Green, and Blue). Here’s a link to the repository if you’d like to try the function. Github Repo

histplot(
    X,
    Y,
    labels,
    bins=2000,
    range=((-3,3),(-3,3)),
    normalize_each_label=True,
    colors = [
        [1,0,0],
        [0,1,0],
        [0,0,1]],
    gain=50)

回答 10

@Piti的答案非常相似,但是使用1个调用而不是2个调用来生成分数:

import numpy as np
import matplotlib.pyplot as plt

pts = 1000000
mean = [0.0, 0.0]
cov = [[1.0,0.0],[0.0,1.0]]

x,y = np.random.multivariate_normal(mean, cov, pts).T
plt.hist2d(x, y, bins=50, cmap=plt.cm.jet)
plt.show()

输出:

2d_gaussian_heatmap

Very similar to @Piti’s answer, but using 1 call instead of 2 to generate the points:

import numpy as np
import matplotlib.pyplot as plt

pts = 1000000
mean = [0.0, 0.0]
cov = [[1.0,0.0],[0.0,1.0]]

x,y = np.random.multivariate_normal(mean, cov, pts).T
plt.hist2d(x, y, bins=50, cmap=plt.cm.jet)
plt.show()

Output:

2d_gaussian_heatmap


回答 11

恐怕聚会晚了一点,但不久前我也遇到了类似的问题。接受的答案(@ptomato提供)帮助了我,但我也想将其发布,以防有​​人使用。


''' I wanted to create a heatmap resembling a football pitch which would show the different actions performed '''

import numpy as np
import matplotlib.pyplot as plt
import random

#fixing random state for reproducibility
np.random.seed(1234324)

fig = plt.figure(12)
ax1 = fig.add_subplot(121)
ax2 = fig.add_subplot(122)

#Ratio of the pitch with respect to UEFA standards 
hmap= np.full((6, 10), 0)
#print(hmap)

xlist = np.random.uniform(low=0.0, high=100.0, size=(20))
ylist = np.random.uniform(low=0.0, high =100.0, size =(20))

#UEFA Pitch Standards are 105m x 68m
xlist = (xlist/100)*10.5
ylist = (ylist/100)*6.5

ax1.scatter(xlist,ylist)

#int of the co-ordinates to populate the array
xlist_int = xlist.astype (int)
ylist_int = ylist.astype (int)

#print(xlist_int, ylist_int)

for i, j in zip(xlist_int, ylist_int):
    #this populates the array according to the x,y co-ordinate values it encounters 
    hmap[j][i]= hmap[j][i] + 1   

#Reversing the rows is necessary 
hmap = hmap[::-1]

#print(hmap)
im = ax2.imshow(hmap)

这是结果 在此处输入图片说明

I’m afraid I’m a little late to the party but I had a similar question a while ago. The accepted answer (by @ptomato) helped me out but I’d also want to post this in case it’s of use to someone.


''' I wanted to create a heatmap resembling a football pitch which would show the different actions performed '''

import numpy as np
import matplotlib.pyplot as plt
import random

#fixing random state for reproducibility
np.random.seed(1234324)

fig = plt.figure(12)
ax1 = fig.add_subplot(121)
ax2 = fig.add_subplot(122)

#Ratio of the pitch with respect to UEFA standards 
hmap= np.full((6, 10), 0)
#print(hmap)

xlist = np.random.uniform(low=0.0, high=100.0, size=(20))
ylist = np.random.uniform(low=0.0, high =100.0, size =(20))

#UEFA Pitch Standards are 105m x 68m
xlist = (xlist/100)*10.5
ylist = (ylist/100)*6.5

ax1.scatter(xlist,ylist)

#int of the co-ordinates to populate the array
xlist_int = xlist.astype (int)
ylist_int = ylist.astype (int)

#print(xlist_int, ylist_int)

for i, j in zip(xlist_int, ylist_int):
    #this populates the array according to the x,y co-ordinate values it encounters 
    hmap[j][i]= hmap[j][i] + 1   

#Reversing the rows is necessary 
hmap = hmap[::-1]

#print(hmap)
im = ax2.imshow(hmap)


Here’s the result enter image description here


子图的pyplot轴标签

问题:子图的pyplot轴标签

我有以下情节:

import matplotlib.pyplot as plt

fig2 = plt.figure()
ax3 = fig2.add_subplot(2,1,1)
ax4 = fig2.add_subplot(2,1,2)
ax4.loglog(x1, y1)
ax3.loglog(x2, y2)
ax3.set_ylabel('hello')

我希望不仅可以为两个子图中的每个图创建轴标签和标题,而且还可以为跨两个子图的通用标签创建轴标签和标题。例如,由于两个图具有相同的轴,所以我只需要一组x和y轴标签。我确实希望每个子图都有不同的标题。

我尝试了几件事,但都没有成功

I have the following plot:

import matplotlib.pyplot as plt

fig2 = plt.figure()
ax3 = fig2.add_subplot(2,1,1)
ax4 = fig2.add_subplot(2,1,2)
ax4.loglog(x1, y1)
ax3.loglog(x2, y2)
ax3.set_ylabel('hello')

I want to be able to create axes labels and titles not just for each of the two subplots, but also common labels that span both subplots. For example, since both plots have identical axes, I only need one set of x and y- axes labels. I do want different titles for each subplot though.

I tried a few things but none of them worked right


回答 0

您可以创建一个覆盖两个子图的大子图,然后设置公共标签。

import random
import matplotlib.pyplot as plt

x = range(1, 101)
y1 = [random.randint(1, 100) for _ in xrange(len(x))]
y2 = [random.randint(1, 100) for _ in xrange(len(x))]

fig = plt.figure()
ax = fig.add_subplot(111)    # The big subplot
ax1 = fig.add_subplot(211)
ax2 = fig.add_subplot(212)

# Turn off axis lines and ticks of the big subplot
ax.spines['top'].set_color('none')
ax.spines['bottom'].set_color('none')
ax.spines['left'].set_color('none')
ax.spines['right'].set_color('none')
ax.tick_params(labelcolor='w', top=False, bottom=False, left=False, right=False)

ax1.loglog(x, y1)
ax2.loglog(x, y2)

# Set common labels
ax.set_xlabel('common xlabel')
ax.set_ylabel('common ylabel')

ax1.set_title('ax1 title')
ax2.set_title('ax2 title')

plt.savefig('common_labels.png', dpi=300)

common_labels.png

另一种方法是使用fig.text()直接设置公共标签的位置。

import random
import matplotlib.pyplot as plt

x = range(1, 101)
y1 = [random.randint(1, 100) for _ in xrange(len(x))]
y2 = [random.randint(1, 100) for _ in xrange(len(x))]

fig = plt.figure()
ax1 = fig.add_subplot(211)
ax2 = fig.add_subplot(212)

ax1.loglog(x, y1)
ax2.loglog(x, y2)

# Set common labels
fig.text(0.5, 0.04, 'common xlabel', ha='center', va='center')
fig.text(0.06, 0.5, 'common ylabel', ha='center', va='center', rotation='vertical')

ax1.set_title('ax1 title')
ax2.set_title('ax2 title')

plt.savefig('common_labels_text.png', dpi=300)

common_labels_text.png

You can create a big subplot that covers the two subplots and then set the common labels.

import random
import matplotlib.pyplot as plt

x = range(1, 101)
y1 = [random.randint(1, 100) for _ in range(len(x))]
y2 = [random.randint(1, 100) for _ in range(len(x))]

fig = plt.figure()
ax = fig.add_subplot(111)    # The big subplot
ax1 = fig.add_subplot(211)
ax2 = fig.add_subplot(212)

# Turn off axis lines and ticks of the big subplot
ax.spines['top'].set_color('none')
ax.spines['bottom'].set_color('none')
ax.spines['left'].set_color('none')
ax.spines['right'].set_color('none')
ax.tick_params(labelcolor='w', top=False, bottom=False, left=False, right=False)

ax1.loglog(x, y1)
ax2.loglog(x, y2)

# Set common labels
ax.set_xlabel('common xlabel')
ax.set_ylabel('common ylabel')

ax1.set_title('ax1 title')
ax2.set_title('ax2 title')

plt.savefig('common_labels.png', dpi=300)

common_labels.png

Another way is using fig.text() to set the locations of the common labels directly.

import random
import matplotlib.pyplot as plt

x = range(1, 101)
y1 = [random.randint(1, 100) for _ in range(len(x))]
y2 = [random.randint(1, 100) for _ in range(len(x))]

fig = plt.figure()
ax1 = fig.add_subplot(211)
ax2 = fig.add_subplot(212)

ax1.loglog(x, y1)
ax2.loglog(x, y2)

# Set common labels
fig.text(0.5, 0.04, 'common xlabel', ha='center', va='center')
fig.text(0.06, 0.5, 'common ylabel', ha='center', va='center', rotation='vertical')

ax1.set_title('ax1 title')
ax2.set_title('ax2 title')

plt.savefig('common_labels_text.png', dpi=300)

common_labels_text.png


回答 1

一种简单的使用方法subplots

import matplotlib.pyplot as plt

fig, axes = plt.subplots(3, 4, sharex=True, sharey=True)
# add a big axes, hide frame
fig.add_subplot(111, frameon=False)
# hide tick and tick label of the big axes
plt.tick_params(labelcolor='none', top='off', bottom='off', left='off', right='off')
plt.grid(False)
plt.xlabel("common X")
plt.ylabel("common Y")

One simple way using subplots:

import matplotlib.pyplot as plt

fig, axes = plt.subplots(3, 4, sharex=True, sharey=True)
# add a big axes, hide frame
fig.add_subplot(111, frameon=False)
# hide tick and tick label of the big axes
plt.tick_params(labelcolor='none', top=False, bottom=False, left=False, right=False)
plt.grid(False)
plt.xlabel("common X")
plt.ylabel("common Y")

回答 2

如果您不尝试导出矢量图形,或者您设置了matplotlib后端以忽略无色轴,那么廖文伟的答案就很好。否则,隐藏的轴将显示在导出的图形中。

suplabel在这里的答案类似于fig.suptitle使用该fig.text功能的。因此,没有轴画家被创建和制作成无色。但是,如果您尝试多次调用它,则会在彼此之间添加文本(fig.suptitle也是如此)。廖文伟的答案没有,因为fig.add_subplot(111)如果已经创建,它将返回相同的Axes对象。

创建绘图后,也可以调用我的函数。

def suplabel(axis,label,label_prop=None,
             labelpad=5,
             ha='center',va='center'):
    ''' Add super ylabel or xlabel to the figure
    Similar to matplotlib.suptitle
    axis       - string: "x" or "y"
    label      - string
    label_prop - keyword dictionary for Text
    labelpad   - padding from the axis (default: 5)
    ha         - horizontal alignment (default: "center")
    va         - vertical alignment (default: "center")
    '''
    fig = pylab.gcf()
    xmin = []
    ymin = []
    for ax in fig.axes:
        xmin.append(ax.get_position().xmin)
        ymin.append(ax.get_position().ymin)
    xmin,ymin = min(xmin),min(ymin)
    dpi = fig.dpi
    if axis.lower() == "y":
        rotation=90.
        x = xmin-float(labelpad)/dpi
        y = 0.5
    elif axis.lower() == 'x':
        rotation = 0.
        x = 0.5
        y = ymin - float(labelpad)/dpi
    else:
        raise Exception("Unexpected axis: x or y")
    if label_prop is None: 
        label_prop = dict()
    pylab.text(x,y,label,rotation=rotation,
               transform=fig.transFigure,
               ha=ha,va=va,
               **label_prop)

Wen-wei Liao’s answer is good if you are not trying to export vector graphics or that you have set up your matplotlib backends to ignore colorless axes; otherwise the hidden axes would show up in the exported graphic.

My answer suplabel here is similar to the fig.suptitle which uses the fig.text function. Therefore there is no axes artist being created and made colorless. However, if you try to call it multiple times you will get text added on top of each other (as fig.suptitle does too). Wen-wei Liao’s answer doesn’t, because fig.add_subplot(111) will return the same Axes object if it is already created.

My function can also be called after the plots have been created.

def suplabel(axis,label,label_prop=None,
             labelpad=5,
             ha='center',va='center'):
    ''' Add super ylabel or xlabel to the figure
    Similar to matplotlib.suptitle
    axis       - string: "x" or "y"
    label      - string
    label_prop - keyword dictionary for Text
    labelpad   - padding from the axis (default: 5)
    ha         - horizontal alignment (default: "center")
    va         - vertical alignment (default: "center")
    '''
    fig = pylab.gcf()
    xmin = []
    ymin = []
    for ax in fig.axes:
        xmin.append(ax.get_position().xmin)
        ymin.append(ax.get_position().ymin)
    xmin,ymin = min(xmin),min(ymin)
    dpi = fig.dpi
    if axis.lower() == "y":
        rotation=90.
        x = xmin-float(labelpad)/dpi
        y = 0.5
    elif axis.lower() == 'x':
        rotation = 0.
        x = 0.5
        y = ymin - float(labelpad)/dpi
    else:
        raise Exception("Unexpected axis: x or y")
    if label_prop is None: 
        label_prop = dict()
    pylab.text(x,y,label,rotation=rotation,
               transform=fig.transFigure,
               ha=ha,va=va,
               **label_prop)

回答 3

这是一个解决方案,您可以设置其中一个图的ylabel并调整其位置,使其垂直居中。这样可以避免KYC提到的问题。

import numpy as np
import matplotlib.pyplot as plt

def set_shared_ylabel(a, ylabel, labelpad = 0.01):
    """Set a y label shared by multiple axes
    Parameters
    ----------
    a: list of axes
    ylabel: string
    labelpad: float
        Sets the padding between ticklabels and axis label"""

    f = a[0].get_figure()
    f.canvas.draw() #sets f.canvas.renderer needed below

    # get the center position for all plots
    top = a[0].get_position().y1
    bottom = a[-1].get_position().y0

    # get the coordinates of the left side of the tick labels 
    x0 = 1
    for at in a:
        at.set_ylabel('') # just to make sure we don't and up with multiple labels
        bboxes, _ = at.yaxis.get_ticklabel_extents(f.canvas.renderer)
        bboxes = bboxes.inverse_transformed(f.transFigure)
        xt = bboxes.x0
        if xt < x0:
            x0 = xt
    tick_label_left = x0

    # set position of label
    a[-1].set_ylabel(ylabel)
    a[-1].yaxis.set_label_coords(tick_label_left - labelpad,(bottom + top)/2, transform=f.transFigure)

length = 100
x = np.linspace(0,100, length)
y1 = np.random.random(length) * 1000
y2 = np.random.random(length)

f,a = plt.subplots(2, sharex=True, gridspec_kw={'hspace':0})
a[0].plot(x, y1)
a[1].plot(x, y2)
set_shared_ylabel(a, 'shared y label (a. u.)')

在此处输入图片说明

Here is a solution where you set the ylabel of one of the plots and adjust the position of it so it is centered vertically. This way you avoid problems mentioned by KYC.

import numpy as np
import matplotlib.pyplot as plt

def set_shared_ylabel(a, ylabel, labelpad = 0.01):
    """Set a y label shared by multiple axes
    Parameters
    ----------
    a: list of axes
    ylabel: string
    labelpad: float
        Sets the padding between ticklabels and axis label"""

    f = a[0].get_figure()
    f.canvas.draw() #sets f.canvas.renderer needed below

    # get the center position for all plots
    top = a[0].get_position().y1
    bottom = a[-1].get_position().y0

    # get the coordinates of the left side of the tick labels 
    x0 = 1
    for at in a:
        at.set_ylabel('') # just to make sure we don't and up with multiple labels
        bboxes, _ = at.yaxis.get_ticklabel_extents(f.canvas.renderer)
        bboxes = bboxes.inverse_transformed(f.transFigure)
        xt = bboxes.x0
        if xt < x0:
            x0 = xt
    tick_label_left = x0

    # set position of label
    a[-1].set_ylabel(ylabel)
    a[-1].yaxis.set_label_coords(tick_label_left - labelpad,(bottom + top)/2, transform=f.transFigure)

length = 100
x = np.linspace(0,100, length)
y1 = np.random.random(length) * 1000
y2 = np.random.random(length)

f,a = plt.subplots(2, sharex=True, gridspec_kw={'hspace':0})
a[0].plot(x, y1)
a[1].plot(x, y2)
set_shared_ylabel(a, 'shared y label (a. u.)')

enter image description here


回答 4

plt.setp() 将做的工作:

# plot something
fig, axs = plt.subplots(3,3, figsize=(15, 8), sharex=True, sharey=True)
for i, ax in enumerate(axs.flat):
    ax.scatter(*np.random.normal(size=(2,200)))
    ax.set_title(f'Title {i}')

# set labels
plt.setp(axs[-1, :], xlabel='x axis label')
plt.setp(axs[:, 0], ylabel='y axis label')

在此处输入图片说明

plt.setp() will do the job:

# plot something
fig, axs = plt.subplots(3,3, figsize=(15, 8), sharex=True, sharey=True)
for i, ax in enumerate(axs.flat):
    ax.scatter(*np.random.normal(size=(2,200)))
    ax.set_title(f'Title {i}')

# set labels
plt.setp(axs[-1, :], xlabel='x axis label')
plt.setp(axs[:, 0], ylabel='y axis label')

enter image description here


回答 5

# list loss and acc are your data
fig = plt.figure()
ax1 = fig.add_subplot(121)
ax2 = fig.add_subplot(122)

ax1.plot(iteration1, loss)
ax2.plot(iteration2, acc)

ax1.set_title('Training Loss')
ax2.set_title('Training Accuracy')

ax1.set_xlabel('Iteration')
ax1.set_ylabel('Loss')

ax2.set_xlabel('Iteration')
ax2.set_ylabel('Accuracy')
# list loss and acc are your data
fig = plt.figure()
ax1 = fig.add_subplot(121)
ax2 = fig.add_subplot(122)

ax1.plot(iteration1, loss)
ax2.plot(iteration2, acc)

ax1.set_title('Training Loss')
ax2.set_title('Training Accuracy')

ax1.set_xlabel('Iteration')
ax1.set_ylabel('Loss')

ax2.set_xlabel('Iteration')
ax2.set_ylabel('Accuracy')

回答 6

当yticks很大时,其他答案中的方法将无法正常工作。ylabel可能会与刻度线重叠,被剪裁在左侧或完全不可见/在图形外部。

我已经修改了Hagne的答案,因此它适用于xlabel和ylabel的超过一列的子图,并且可以移动图以使ylabel在图中可见。

def set_shared_ylabel(a, xlabel, ylabel, labelpad = 0.01, figleftpad=0.05):
    """Set a y label shared by multiple axes
    Parameters
    ----------
    a: list of axes
    ylabel: string
    labelpad: float
        Sets the padding between ticklabels and axis label"""

    f = a[0,0].get_figure()
    f.canvas.draw() #sets f.canvas.renderer needed below

    # get the center position for all plots
    top = a[0,0].get_position().y1
    bottom = a[-1,-1].get_position().y0

    # get the coordinates of the left side of the tick labels
    x0 = 1
    x1 = 1
    for at_row in a:
        at = at_row[0]
        at.set_ylabel('') # just to make sure we don't and up with multiple labels
        bboxes, _ = at.yaxis.get_ticklabel_extents(f.canvas.renderer)
        bboxes = bboxes.inverse_transformed(f.transFigure)
        xt = bboxes.x0
        if xt < x0:
            x0 = xt
            x1 = bboxes.x1
    tick_label_left = x0

    # shrink plot on left to prevent ylabel clipping
    # (x1 - tick_label_left) is the x coordinate of right end of tick label,
    # basically how much padding is needed to fit tick labels in the figure
    # figleftpad is additional padding to fit the ylabel
    plt.subplots_adjust(left=(x1 - tick_label_left) + figleftpad)

    # set position of label, 
    # note that (figleftpad-labelpad) refers to the middle of the ylabel
    a[-1,-1].set_ylabel(ylabel)
    a[-1,-1].yaxis.set_label_coords(figleftpad-labelpad,(bottom + top)/2, transform=f.transFigure)

    # set xlabel
    y0 = 1
    for at in axes[-1]:
        at.set_xlabel('')  # just to make sure we don't and up with multiple labels
        bboxes, _ = at.xaxis.get_ticklabel_extents(fig.canvas.renderer)
        bboxes = bboxes.inverse_transformed(fig.transFigure)
        yt = bboxes.y0
        if yt < y0:
            y0 = yt
    tick_label_bottom = y0

    axes[-1, -1].set_xlabel(xlabel)
    axes[-1, -1].xaxis.set_label_coords((left + right) / 2, tick_label_bottom - labelpad, transform=fig.transFigure)

它适用于以下示例,而Hagne的答案不会绘制ylabel(因为它在画布之外),而KYC的ylabel与刻度标签重叠:

import matplotlib.pyplot as plt
import itertools

fig, axes = plt.subplots(3, 4, sharey='row', sharex=True, squeeze=False)
fig.subplots_adjust(hspace=.5)
for i, a in enumerate(itertools.chain(*axes)):
    a.plot([0,4**i], [0,4**i])
    a.set_title(i)
set_shared_ylabel(axes, 'common X', 'common Y')
plt.show()

另外,如果您对无色轴没问题,我已经修改了朱利安·陈(Julian Chen)的解决方案,因此ylabel不会与刻度标签重叠。

基本上,我们只需要设置无色的ylim,使其与子图的最大ylim相匹配,因此无色的刻度标签会为ylabel设置正确的位置。

同样,我们必须缩小绘图以防止剪切。在这里,我已经对减少的数量进行了硬编码,但是您可以像上面的方法一样尝试找到适合您的数字或进行计算。

import matplotlib.pyplot as plt
import itertools

fig, axes = plt.subplots(3, 4, sharey='row', sharex=True, squeeze=False)
fig.subplots_adjust(hspace=.5)
miny = maxy = 0
for i, a in enumerate(itertools.chain(*axes)):
    a.plot([0,4**i], [0,4**i])
    a.set_title(i)
    miny = min(miny, a.get_ylim()[0])
    maxy = max(maxy, a.get_ylim()[1])

# add a big axes, hide frame
# set ylim to match the largest range of any subplot
ax_invis = fig.add_subplot(111, frameon=False)
ax_invis.set_ylim([miny, maxy])

# hide tick and tick label of the big axis
plt.tick_params(labelcolor='none', top=False, bottom=False, left=False, right=False)
plt.xlabel("common X")
plt.ylabel("common Y")

# shrink plot to prevent clipping
plt.subplots_adjust(left=0.15)
plt.show()

The methods in the other answers will not work properly when the yticks are large. The ylabel will either overlap with ticks, be clipped on the left or completely invisible/outside of the figure.

I’ve modified Hagne’s answer so it works with more than 1 column of subplots, for both xlabel and ylabel, and it shifts the plot to keep the ylabel visible in the figure.

def set_shared_ylabel(a, xlabel, ylabel, labelpad = 0.01, figleftpad=0.05):
    """Set a y label shared by multiple axes
    Parameters
    ----------
    a: list of axes
    ylabel: string
    labelpad: float
        Sets the padding between ticklabels and axis label"""

    f = a[0,0].get_figure()
    f.canvas.draw() #sets f.canvas.renderer needed below

    # get the center position for all plots
    top = a[0,0].get_position().y1
    bottom = a[-1,-1].get_position().y0

    # get the coordinates of the left side of the tick labels
    x0 = 1
    x1 = 1
    for at_row in a:
        at = at_row[0]
        at.set_ylabel('') # just to make sure we don't and up with multiple labels
        bboxes, _ = at.yaxis.get_ticklabel_extents(f.canvas.renderer)
        bboxes = bboxes.inverse_transformed(f.transFigure)
        xt = bboxes.x0
        if xt < x0:
            x0 = xt
            x1 = bboxes.x1
    tick_label_left = x0

    # shrink plot on left to prevent ylabel clipping
    # (x1 - tick_label_left) is the x coordinate of right end of tick label,
    # basically how much padding is needed to fit tick labels in the figure
    # figleftpad is additional padding to fit the ylabel
    plt.subplots_adjust(left=(x1 - tick_label_left) + figleftpad)

    # set position of label, 
    # note that (figleftpad-labelpad) refers to the middle of the ylabel
    a[-1,-1].set_ylabel(ylabel)
    a[-1,-1].yaxis.set_label_coords(figleftpad-labelpad,(bottom + top)/2, transform=f.transFigure)

    # set xlabel
    y0 = 1
    for at in axes[-1]:
        at.set_xlabel('')  # just to make sure we don't and up with multiple labels
        bboxes, _ = at.xaxis.get_ticklabel_extents(fig.canvas.renderer)
        bboxes = bboxes.inverse_transformed(fig.transFigure)
        yt = bboxes.y0
        if yt < y0:
            y0 = yt
    tick_label_bottom = y0

    axes[-1, -1].set_xlabel(xlabel)
    axes[-1, -1].xaxis.set_label_coords((left + right) / 2, tick_label_bottom - labelpad, transform=fig.transFigure)

It works for the following example, while Hagne’s answer won’t draw ylabel (since it’s outside of the canvas) and KYC’s ylabel overlaps with the tick labels:

import matplotlib.pyplot as plt
import itertools

fig, axes = plt.subplots(3, 4, sharey='row', sharex=True, squeeze=False)
fig.subplots_adjust(hspace=.5)
for i, a in enumerate(itertools.chain(*axes)):
    a.plot([0,4**i], [0,4**i])
    a.set_title(i)
set_shared_ylabel(axes, 'common X', 'common Y')
plt.show()

Alternatively, if you are fine with colorless axis, I’ve modified Julian Chen’s solution so ylabel won’t overlap with tick labels.

Basically, we just have to set ylims of the colorless so it matches the largest ylims of the subplots so the colorless tick labels sets the correct location for the ylabel.

Again, we have to shrink the plot to prevent clipping. Here I’ve hard coded the amount to shrink, but you can play around to find a number that works for you or calculate it like in the method above.

import matplotlib.pyplot as plt
import itertools

fig, axes = plt.subplots(3, 4, sharey='row', sharex=True, squeeze=False)
fig.subplots_adjust(hspace=.5)
miny = maxy = 0
for i, a in enumerate(itertools.chain(*axes)):
    a.plot([0,4**i], [0,4**i])
    a.set_title(i)
    miny = min(miny, a.get_ylim()[0])
    maxy = max(maxy, a.get_ylim()[1])

# add a big axes, hide frame
# set ylim to match the largest range of any subplot
ax_invis = fig.add_subplot(111, frameon=False)
ax_invis.set_ylim([miny, maxy])

# hide tick and tick label of the big axis
plt.tick_params(labelcolor='none', top=False, bottom=False, left=False, right=False)
plt.xlabel("common X")
plt.ylabel("common Y")

# shrink plot to prevent clipping
plt.subplots_adjust(left=0.15)
plt.show()

从字符串变量导入模块

问题:从字符串变量导入模块

我正在编写有关matplotlib(MPL)嵌套库的文档(个人),该文档与感兴趣的子模块包所提供的MPL有所不同。我正在编写Python脚本,希望该脚本可以自动从将来的MPL版本中生成文档。
我选择了感兴趣的子模块/程序包,并希望列出其主要类,然后从中生成列表并进行处理。pydoc

问题是我找不到指示Python从字符串加载子模块的方法。这是我尝试过的示例:

import matplotlib.text as text
x = dir(text)

i = __import__('matplotlib.text')
y = dir(i)

j = __import__('matplotlib')
z = dir(j)

这是通过pprint比较上述列表的三种方式:

在此处输入图片说明

我不明白y对象中加载了什么-它是基础对象matplotlib以及其他内容,但是它缺少我想要的信息,而这正是matplotlib.text包中的主要类。它是屏幕截图中最上面的蓝色部分(x列表)

请不要建议Sphinx作为其他方法。

I’m working on a documentation (personal) for nested matplotlib (MPL) library, which differs from MPL own provided, by interested submodule packages. I’m writing Python script which I hope will automate document generation from future MPL releases.
I selected interested submodules/packages and want to list their main classes from which I’ll generate list and process it with pydoc

Problem is that I can’t find a way to instruct Python to load submodule from string. Here is example of what I tried:

import matplotlib.text as text
x = dir(text)

.

i = __import__('matplotlib.text')
y = dir(i)

.

j = __import__('matplotlib')
z = dir(j)

And here is 3 way comparison of above lists through pprint:

enter image description here

I don’t understand what’s loaded in y object – it’s base matplotlib plus something else, but it lack information that I wanted and that is main classes from matplotlib.text package. It’s top blue coloured part on screenshot (x list)

Please don’t suggest Sphinx as different approach.


回答 0

__import__功能可能有点难以理解。

如果你改变

i = __import__('matplotlib.text')

i = __import__('matplotlib.text', fromlist=[''])

然后i将参考matplotlib.text

在Python 2.7和Python 3.1或更高版本中,可以使用importlib

import importlib

i = importlib.import_module("matplotlib.text")

一些注意事项

  • 如果您尝试从子文件夹(例如)中导入内容./feature/email.py,则代码将如下所示importlib.import_module("feature.email")

  • 如果__init__.py您要导入的文件所在的文件夹中没有任何内容,则无法导入任何内容

The __import__ function can be a bit hard to understand.

If you change

i = __import__('matplotlib.text')

to

i = __import__('matplotlib.text', fromlist=[''])

then i will refer to matplotlib.text.

In Python 2.7 and Python 3.1 or later, you can use importlib:

import importlib

i = importlib.import_module("matplotlib.text")

Some notes

  • If you’re trying to import something from a sub-folder e.g. ./feature/email.py, the code will look like importlib.import_module("feature.email")

  • You can’t import anything if there is no __init__.py in the folder with file you are trying to import


回答 1

importlib.import_module是您要寻找的。它返回导入的模块。(仅适用于Python> = 2.7或3.x):

import importlib

mymodule = importlib.import_module('matplotlib.text')

之后,您可以访问模块中的任何内容mymodule.myclass,例如等等。

importlib.import_module is what you are looking for. It returns the imported module. (Only available for Python >= 2.7 or 3.x):

import importlib

mymodule = importlib.import_module('matplotlib.text')

You can thereafter access anything in the module as mymodule.myclass, etc.


回答 2

花了一些时间尝试从列表中导入模块,而这正是使线程到达我那里的大部分方式-但是我不了解___import____的用法-

因此,这是从字符串导入模块并获得与导入相同的行为的方法。并尝试/排除错误情况。:)

  pipmodules = ['pycurl', 'ansible', 'bad_module_no_beer']
  for module in pipmodules:
      try:
          # because we want to import using a variable, do it this way
          module_obj = __import__(module)
          # create a global object containging our module
          globals()[module] = module_obj
      except ImportError:
          sys.stderr.write("ERROR: missing python module: " + module + "\n")
          sys.exit(1)

是的,对于python 2.7>,您还有其他选择-但是对于2.6 <,这可行。

spent some time trying to import modules from a list, and this is the thread that got me most of the way there – but I didnt grasp the use of ___import____ –

so here’s how to import a module from a string, and get the same behavior as just import. And try/except the error case, too. :)

  pipmodules = ['pycurl', 'ansible', 'bad_module_no_beer']
  for module in pipmodules:
      try:
          # because we want to import using a variable, do it this way
          module_obj = __import__(module)
          # create a global object containging our module
          globals()[module] = module_obj
      except ImportError:
          sys.stderr.write("ERROR: missing python module: " + module + "\n")
          sys.exit(1)

and yes, for python 2.7> you have other options – but for 2.6<, this works.


回答 3

我开发了以下3个有用的功能:

def loadModule(moduleName):
    module = None
    try:
        import sys
        del sys.modules[moduleName]
    except BaseException as err:
        pass
    try:
        import importlib
        module = importlib.import_module(moduleName)
    except BaseException as err:
        serr = str(err)
        print("Error to load the module '" + moduleName + "': " + serr)
    return module

def reloadModule(moduleName):
    module = loadModule(moduleName)
    moduleName, modulePath = str(module).replace("' from '", "||").replace("<module '", '').replace("'>", '').split("||")
    if (modulePath.endswith(".pyc")):
        import os
        os.remove(modulePath)
        module = loadModule(moduleName)
    return module

def getInstance(moduleName, param1, param2, param3):
    module = reloadModule(moduleName)
    instance = eval("module." + moduleName + "(param1, param2, param3)")
    return instance

每次我想重新加载新实例时,都只需要像这样调用getInstance()即可:

myInstance = getInstance("MyModule", myParam1, myParam2, myParam3)

最后,我可以调用新实例中的所有函数:

myInstance.aFunction()

这里唯一的特殊性是自定义实例的参数列表(param1,param2,param3)。

I developed these 3 useful functions:

def loadModule(moduleName):
    module = None
    try:
        import sys
        del sys.modules[moduleName]
    except BaseException as err:
        pass
    try:
        import importlib
        module = importlib.import_module(moduleName)
    except BaseException as err:
        serr = str(err)
        print("Error to load the module '" + moduleName + "': " + serr)
    return module

def reloadModule(moduleName):
    module = loadModule(moduleName)
    moduleName, modulePath = str(module).replace("' from '", "||").replace("<module '", '').replace("'>", '').split("||")
    if (modulePath.endswith(".pyc")):
        import os
        os.remove(modulePath)
        module = loadModule(moduleName)
    return module

def getInstance(moduleName, param1, param2, param3):
    module = reloadModule(moduleName)
    instance = eval("module." + moduleName + "(param1, param2, param3)")
    return instance

And everytime I want to reload a new instance I just have to call getInstance() like this:

myInstance = getInstance("MyModule", myParam1, myParam2, myParam3)

Finally I can call all the functions inside the new Instance:

myInstance.aFunction()

The only specificity here is to customize the params list (param1, param2, param3) of your instance.


回答 4

除了使用importlib一个,还可以使用exec方法从字符串变量导入模块。

在这里,我展示了使用combinations方法从itertools包中导入方法的示例exec

MODULES = [
    ['itertools','combinations'],
]

for ITEM in MODULES:
    import_str = "from {0} import {1}".format(ITEM[0],', '.join(str(i) for i in ITEM[1:]))
    exec(import_str)

ar = list(combinations([1, 2, 3, 4], 2))
for elements in ar:
    print(elements)

输出:

(1, 2)
(1, 3)
(1, 4)
(2, 3)
(2, 4)
(3, 4)

Apart from using the importlib one can also use exec method to import a module from a string variable.

Here I am showing an example of importing the combinations method from itertools package using the exec method:

MODULES = [
    ['itertools','combinations'],
]

for ITEM in MODULES:
    import_str = "from {0} import {1}".format(ITEM[0],', '.join(str(i) for i in ITEM[1:]))
    exec(import_str)

ar = list(combinations([1, 2, 3, 4], 2))
for elements in ar:
    print(elements)

Output:

(1, 2)
(1, 3)
(1, 4)
(2, 3)
(2, 4)
(3, 4)

减少matplotlib图中的左右边距

问题:减少matplotlib图中的左右边距

我正在努力处理matplotlib中的地块边距。我使用下面的代码来生成图表:

plt.imshow(g)
c = plt.colorbar()
c.set_label("Number of Slabs")
plt.savefig("OutputToUse.png")

但是,我得到了一个在绘图的两边都有很多空白的输出图形。我已经搜索过Google并阅读了matplotlib文档,但似乎找不到如何减少这种情况的方法。

I’m struggling to deal with my plot margins in matplotlib. I’ve used the code below to produce my chart:

plt.imshow(g)
c = plt.colorbar()
c.set_label("Number of Slabs")
plt.savefig("OutputToUse.png")

However, I get an output figure with lots of white space on either side of the plot. I’ve searched google and read the matplotlib documentation, but I can’t seem to find how to reduce this.


回答 0

一种自动执行此操作的方法是使用bbox_inches='tight'kwarg plt.savefig

例如

import matplotlib.pyplot as plt
import numpy as np
data = np.arange(3000).reshape((100,30))
plt.imshow(data)
plt.savefig('test.png', bbox_inches='tight')

另一种方法是使用 fig.tight_layout()

import matplotlib.pyplot as plt
import numpy as np

xs = np.linspace(0, 1, 20); ys = np.sin(xs)

fig = plt.figure()
axes = fig.add_subplot(1,1,1)
axes.plot(xs, ys)

# This should be called after all axes have been added
fig.tight_layout()
fig.savefig('test.png')

One way to automatically do this is the bbox_inches='tight' kwarg to plt.savefig.

E.g.

import matplotlib.pyplot as plt
import numpy as np
data = np.arange(3000).reshape((100,30))
plt.imshow(data)
plt.savefig('test.png', bbox_inches='tight')

Another way is to use fig.tight_layout()

import matplotlib.pyplot as plt
import numpy as np

xs = np.linspace(0, 1, 20); ys = np.sin(xs)

fig = plt.figure()
axes = fig.add_subplot(1,1,1)
axes.plot(xs, ys)

# This should be called after all axes have been added
fig.tight_layout()
fig.savefig('test.png')

回答 1

您可以使用subplots_adjust()函数调整matplotlib图形周围的间距:

import matplotlib.pyplot as plt
plt.plot(whatever)
plt.subplots_adjust(left=0.1, right=0.9, top=0.9, bottom=0.1)

这将同时适用于屏幕上的图形并保存到文件中,并且即使在一个图形上没有多个图形,这也是调用的正确功能。

数字是图形尺寸的分数,需要进行调整以允许图形标签。

You can adjust the spacing around matplotlib figures using the subplots_adjust() function:

import matplotlib.pyplot as plt
plt.plot(whatever)
plt.subplots_adjust(left=0.1, right=0.9, top=0.9, bottom=0.1)

This will work for both the figure on screen and saved to a file, and it is the right function to call even if you don’t have multiple plots on the one figure.

The numbers are fractions of the figure dimensions, and will need to be adjusted to allow for the figure labels.


回答 2

所有你需要的是

plt.tight_layout()

在输出之前。

除了减少边距之外,这还将所有子图之间的空间紧密地分组:

x = [1,2,3]
y = [1,4,9]
import matplotlib.pyplot as plt
fig = plt.figure()
subplot1 = fig.add_subplot(121)
subplot1.plot(x,y)
subplot2 = fig.add_subplot(122)
subplot2.plot(y,x)
fig.tight_layout()
plt.show()

All you need is

plt.tight_layout()

before your output.

In addition to cutting down the margins, this also tightly groups the space between any subplots:

x = [1,2,3]
y = [1,4,9]
import matplotlib.pyplot as plt
fig = plt.figure()
subplot1 = fig.add_subplot(121)
subplot1.plot(x,y)
subplot2 = fig.add_subplot(122)
subplot2.plot(y,x)
fig.tight_layout()
plt.show()

回答 3

只要使用ax = fig.add_axes([left, bottom, width, height]) ,如果你想图布局的精确控制。例如。

left = 0.05
bottom = 0.05
width = 0.9
height = 0.9
ax = fig.add_axes([left, bottom, width, height])

Just use ax = fig.add_axes([left, bottom, width, height]) if you want exact control of the figure layout. eg.

left = 0.05
bottom = 0.05
width = 0.9
height = 0.9
ax = fig.add_axes([left, bottom, width, height])

回答 4

如果有人想知道在应用plt.tight_layout()或后如何去除其余的白色边距fig.tight_layout():使用参数pad1.08默认情况下),您可以使其更加紧密:“在图形边缘和子图,仅占字体大小的一部分。” 所以举个例子

plt.tight_layout(pad=0.05)

将其减少到很小的幅度。推杆0对我不起作用,因为它也会使子图的框被剪掉一点。

In case anybody wonders how how to get rid of the rest of the white margin after applying plt.tight_layout() or fig.tight_layout(): With the parameter pad (which is 1.08 by default), you’re able to make it even tighter: “Padding between the figure edge and the edges of subplots, as a fraction of the font size.” So for example

plt.tight_layout(pad=0.05)

will reduce it to a very small margin. Putting 0 doesn’t work for me, as it makes the box of the subplot be cut off a little, too.


回答 5

plt.savefig("circle.png", bbox_inches='tight',pad_inches=-1)
plt.savefig("circle.png", bbox_inches='tight',pad_inches=-1)

回答 6

matplotlibs subplots_adjust的问题在于,您输入的值相对于图形的x和y图大小。本示例是为了正确打印PDF的图形尺寸:

为此,我将相对间距重新计算为绝对值,如下所示:

pyplot.subplots_adjust(left = (5/25.4)/figure.xsize, bottom = (4/25.4)/figure.ysize, right = 1 - (1/25.4)/figure.xsize, top = 1 - (3/25.4)/figure.ysize)

以x维度表示“ figure.xsize”英寸,以y维度表示“ figure.ysize”英寸。因此,整个标签的左侧边距为5 mm,底部边距为4 mm,右侧边距为1 mm,顶部边距为3 mm。完成(x / 25.4)的转换是因为我需要将mm转换为英寸。

请注意,x的纯图表大小将为“ figure.xsize-左边距-右边距”,y的纯图表大小将为“ figure.ysize-底部边距-顶部边距”(以英寸为单位)

其他代码段(不确定这些代码段,我只想提供其他参数)

pyplot.figure(figsize = figureSize, dpi = None)

pyplot.savefig("outputname.eps", dpi = 100)

The problem with matplotlibs subplots_adjust is that the values you enter are relative to the x and y figsize of the figure. This example is for correct figuresizing for printing of a pdf:

For that, I recalculate the relative spacing to absolute values like this:

pyplot.subplots_adjust(left = (5/25.4)/figure.xsize, bottom = (4/25.4)/figure.ysize, right = 1 - (1/25.4)/figure.xsize, top = 1 - (3/25.4)/figure.ysize)

for a figure of ‘figure.xsize’ inches in x-dimension and ‘figure.ysize’ inches in y-dimension. So the whole figure has a left margin of 5 mm, bottom margin of 4 mm, right of 1 mm and top of 3 mm within the labels are placed. The conversion of (x/25.4) is done because I needed to convert mm to inches.

Note that the pure chart size of x will be “figure.xsize – left margin – right margin” and the pure chart size of y will be “figure.ysize – bottom margin – top margin” in inches

Other sniplets (not sure about these ones, I just wanted to provide the other parameters)

pyplot.figure(figsize = figureSize, dpi = None)

and

pyplot.savefig("outputname.eps", dpi = 100)

回答 7

受以上萨米斯启发的答案:

margins = {  #     vvv margin in inches
    "left"   :     1.5 / figsize[0],
    "bottom" :     0.8 / figsize[1],
    "right"  : 1 - 0.3 / figsize[0],
    "top"    : 1 - 1   / figsize[1]
}
fig.subplots_adjust(**margins)

figsize是您在其中使用的元组 fig = pyplot.figure(figsize=...)

inspired by Sammys answer above:

margins = {  #     vvv margin in inches
    "left"   :     1.5 / figsize[0],
    "bottom" :     0.8 / figsize[1],
    "right"  : 1 - 0.3 / figsize[0],
    "top"    : 1 - 1   / figsize[1]
}
fig.subplots_adjust(**margins)

Where figsize is the tuple that you used in fig = pyplot.figure(figsize=...)


回答 8

对我来说,以上答案matplotlib.__version__ = 1.4.3在Win7上不起作用。因此,如果我们只对图像本身感兴趣(即,如果我们不需要注释,轴,刻度,标题,ylabel等),那么最好将numpy数组另存为image而不是savefig

from pylab import *

ax = subplot(111)
ax.imshow(some_image_numpyarray)
imsave('test.tif', some_image_numpyarray)

# or, if the image came from tiff or png etc
RGBbuffer = ax.get_images()[0].get_array()
imsave('test.tif', RGBbuffer)

另外,使用opencv绘图功能(cv2.line,cv2.polylines),我们可以直接在numpy数组上绘制一些绘图。http://docs.opencv.org/2.4/modules/core/doc/drawing_functions.html

For me, the answers above did not work with matplotlib.__version__ = 1.4.3 on Win7. So, if we are only interested in the image itself (i.e., if we don’t need annotations, axis, ticks, title, ylabel etc), then it’s better to simply save the numpy array as image instead of savefig.

from pylab import *

ax = subplot(111)
ax.imshow(some_image_numpyarray)
imsave('test.tif', some_image_numpyarray)

# or, if the image came from tiff or png etc
RGBbuffer = ax.get_images()[0].get_array()
imsave('test.tif', RGBbuffer)

Also, using opencv drawing functions (cv2.line, cv2.polylines), we can do some drawings directly on the numpy array. http://docs.opencv.org/2.4/modules/core/doc/drawing_functions.html


回答 9

对于最新的matplotlib版本,您可能需要尝试Constrained Layout

With recent matplotlib versions you might want to try Constrained Layout.


Matplotlib散点图在每个数据点具有不同的文本

问题:Matplotlib散点图在每个数据点具有不同的文本

我正在尝试绘制散点图,并用列表中的不同数字注释数据点。因此,例如,我想绘制yvs x并使用中的相应数字进行注释n

y = [2.56422, 3.77284, 3.52623, 3.51468, 3.02199]
z = [0.15, 0.3, 0.45, 0.6, 0.75]
n = [58, 651, 393, 203, 123]
ax = fig.add_subplot(111)
ax1.scatter(z, y, fmt='o')

有任何想法吗?

I am trying to make a scatter plot and annotate data points with different numbers from a list. So, for example, I want to plot y vs x and annotate with corresponding numbers from n.

y = [2.56422, 3.77284, 3.52623, 3.51468, 3.02199]
z = [0.15, 0.3, 0.45, 0.6, 0.75]
n = [58, 651, 393, 203, 123]
ax = fig.add_subplot(111)
ax1.scatter(z, y, fmt='o')

Any ideas?


回答 0

我不知道有任何采用数组或列表的绘图方法,但可以annotate()在对中的值进行迭代时使用n

y = [2.56422, 3.77284, 3.52623, 3.51468, 3.02199]
z = [0.15, 0.3, 0.45, 0.6, 0.75]
n = [58, 651, 393, 203, 123]

fig, ax = plt.subplots()
ax.scatter(z, y)

for i, txt in enumerate(n):
    ax.annotate(txt, (z[i], y[i]))

的格式设置选项很多annotate(),请参见matplotlib网站:

在此处输入图片说明

I’m not aware of any plotting method which takes arrays or lists but you could use annotate() while iterating over the values in n.

y = [2.56422, 3.77284, 3.52623, 3.51468, 3.02199]
z = [0.15, 0.3, 0.45, 0.6, 0.75]
n = [58, 651, 393, 203, 123]

fig, ax = plt.subplots()
ax.scatter(z, y)

for i, txt in enumerate(n):
    ax.annotate(txt, (z[i], y[i]))

There are a lot of formatting options for annotate(), see the matplotlib website:

enter image description here


回答 1

在版本低于matplotlib 2.0的版本中,ax.scatter绘制没有标记的文本不是必需的。在2.0版中,您需要ax.scatter为文本设置适当的范围和标记。

y = [2.56422, 3.77284, 3.52623, 3.51468, 3.02199]
z = [0.15, 0.3, 0.45, 0.6, 0.75]
n = [58, 651, 393, 203, 123]

fig, ax = plt.subplots()

for i, txt in enumerate(n):
    ax.annotate(txt, (z[i], y[i]))

在此链接中,您可以找到3d中的示例。

In version’s earlier than matplotlib 2.0, ax.scatter is not necessary to plot text without markers. In version 2.0 you’ll need ax.scatter to set the proper range and markers for text.

y = [2.56422, 3.77284, 3.52623, 3.51468, 3.02199]
z = [0.15, 0.3, 0.45, 0.6, 0.75]
n = [58, 651, 393, 203, 123]

fig, ax = plt.subplots()

for i, txt in enumerate(n):
    ax.annotate(txt, (z[i], y[i]))

And in this link you can find an example in 3d.


回答 2

如果有人试图将上述解决方案应用于.scatter()而不是.subplot(),

我尝试运行以下代码

y = [2.56422, 3.77284, 3.52623, 3.51468, 3.02199]
z = [0.15, 0.3, 0.45, 0.6, 0.75]
n = [58, 651, 393, 203, 123]

fig, ax = plt.scatter(z, y)

for i, txt in enumerate(n):
    ax.annotate(txt, (z[i], y[i]))

但是遇到错误,指出“无法解压缩不可迭代的PathCollection对象”,该错误专门指向代码行无花果,ax = plt.scatter(z,y)

我最终使用以下代码解决了该错误

plt.scatter(z, y)

for i, txt in enumerate(n):
    plt.annotate(txt, (z[i], y[i]))

我没想到我应该更清楚地知道.scatter()和.subplot()之间没有区别。

In case anyone is trying to apply the above solutions to a .scatter() instead of a .subplot(),

I tried running the following code

y = [2.56422, 3.77284, 3.52623, 3.51468, 3.02199]
z = [0.15, 0.3, 0.45, 0.6, 0.75]
n = [58, 651, 393, 203, 123]

fig, ax = plt.scatter(z, y)

for i, txt in enumerate(n):
    ax.annotate(txt, (z[i], y[i]))

But ran into errors stating “cannot unpack non-iterable PathCollection object”, with the error specifically pointing at codeline fig, ax = plt.scatter(z, y)

I eventually solved the error using the following code

plt.scatter(z, y)

for i, txt in enumerate(n):
    plt.annotate(txt, (z[i], y[i]))

I didn’t expect there to be a difference between .scatter() and .subplot() I should have known better.


回答 3

您也可以使用pyplot.text(请参阅此处)。

def plot_embeddings(M_reduced, word2Ind, words):
""" Plot in a scatterplot the embeddings of the words specified in the list "words".
    Include a label next to each point.
"""
for word in words:
    x, y = M_reduced[word2Ind[word]]
    plt.scatter(x, y, marker='x', color='red')
    plt.text(x+.03, y+.03, word, fontsize=9)
plt.show()

M_reduced_plot_test = np.array([[1, 1], [-1, -1], [1, -1], [-1, 1], [0, 0]])
word2Ind_plot_test = {'test1': 0, 'test2': 1, 'test3': 2, 'test4': 3, 'test5': 4}
words = ['test1', 'test2', 'test3', 'test4', 'test5']
plot_embeddings(M_reduced_plot_test, word2Ind_plot_test, words)

在此处输入图片说明

You may also use pyplot.text (see here).

def plot_embeddings(M_reduced, word2Ind, words):
    """ 
        Plot in a scatterplot the embeddings of the words specified in the list "words".
        Include a label next to each point.
    """
    for word in words:
        x, y = M_reduced[word2Ind[word]]
        plt.scatter(x, y, marker='x', color='red')
        plt.text(x+.03, y+.03, word, fontsize=9)
    plt.show()

M_reduced_plot_test = np.array([[1, 1], [-1, -1], [1, -1], [-1, 1], [0, 0]])
word2Ind_plot_test = {'test1': 0, 'test2': 1, 'test3': 2, 'test4': 3, 'test5': 4}
words = ['test1', 'test2', 'test3', 'test4', 'test5']
plot_embeddings(M_reduced_plot_test, word2Ind_plot_test, words)

enter image description here


回答 4

Python 3.6及更高版本:

coordinates = [('a',1,2), ('b',3,4), ('c',5,6)]
for x in coordinates: plt.annotate(x[0], (x[1], x[2]))

Python 3.6+:

coordinates = [('a',1,2), ('b',3,4), ('c',5,6)]
for x in coordinates: plt.annotate(x[0], (x[1], x[2]))

回答 5

作为一个使用列表理解和numpy的班轮:

[ax.annotate(x[0], (x[1], x[2])) for x in np.array([n,z,y]).T]

设置与Rutger的答案相同。

As a one liner using list comprehension and numpy:

[ax.annotate(x[0], (x[1], x[2])) for x in np.array([n,z,y]).T]

setup is ditto to Rutger’s answer.


回答 6

我想补充一点,您甚至可以使用箭头/文本框来标注标签。这是我的意思:

import random
import matplotlib.pyplot as plt


y = [2.56422, 3.77284, 3.52623, 3.51468, 3.02199]
z = [0.15, 0.3, 0.45, 0.6, 0.75]
n = [58, 651, 393, 203, 123]

fig, ax = plt.subplots()
ax.scatter(z, y)

ax.annotate(n[0], (z[0], y[0]), xytext=(z[0]+0.05, y[0]+0.3), 
    arrowprops=dict(facecolor='red', shrink=0.05))

ax.annotate(n[1], (z[1], y[1]), xytext=(z[1]-0.05, y[1]-0.3), 
    arrowprops = dict(  arrowstyle="->",
                        connectionstyle="angle3,angleA=0,angleB=-90"))

ax.annotate(n[2], (z[2], y[2]), xytext=(z[2]-0.05, y[2]-0.3), 
    arrowprops = dict(arrowstyle="wedge,tail_width=0.5", alpha=0.1))

ax.annotate(n[3], (z[3], y[3]), xytext=(z[3]+0.05, y[3]-0.2), 
    arrowprops = dict(arrowstyle="fancy"))

ax.annotate(n[4], (z[4], y[4]), xytext=(z[4]-0.1, y[4]-0.2),
    bbox=dict(boxstyle="round", alpha=0.1), 
    arrowprops = dict(arrowstyle="simple"))

plt.show()

将生成以下图形: 在此处输入图片说明

I would love to add that you can even use arrows /text boxes to annotate the labels. Here is what I mean:

import random
import matplotlib.pyplot as plt


y = [2.56422, 3.77284, 3.52623, 3.51468, 3.02199]
z = [0.15, 0.3, 0.45, 0.6, 0.75]
n = [58, 651, 393, 203, 123]

fig, ax = plt.subplots()
ax.scatter(z, y)

ax.annotate(n[0], (z[0], y[0]), xytext=(z[0]+0.05, y[0]+0.3), 
    arrowprops=dict(facecolor='red', shrink=0.05))

ax.annotate(n[1], (z[1], y[1]), xytext=(z[1]-0.05, y[1]-0.3), 
    arrowprops = dict(  arrowstyle="->",
                        connectionstyle="angle3,angleA=0,angleB=-90"))

ax.annotate(n[2], (z[2], y[2]), xytext=(z[2]-0.05, y[2]-0.3), 
    arrowprops = dict(arrowstyle="wedge,tail_width=0.5", alpha=0.1))

ax.annotate(n[3], (z[3], y[3]), xytext=(z[3]+0.05, y[3]-0.2), 
    arrowprops = dict(arrowstyle="fancy"))

ax.annotate(n[4], (z[4], y[4]), xytext=(z[4]-0.1, y[4]-0.2),
    bbox=dict(boxstyle="round", alpha=0.1), 
    arrowprops = dict(arrowstyle="simple"))

plt.show()

Which will generate the following graph: enter image description here


Matplotlib中的反向颜色图

问题:Matplotlib中的反向颜色图

我想知道如何简单地反转给定颜色图的颜色顺序,以便将其与plot_surface一起使用。

I would like to know how to simply reverse the color order of a given colormap in order to use it with plot_surface.


回答 0

标准色图也都具有相反的版本。它们具有相同的名称,并_r附加在末尾。(此处的文档。

The standard colormaps also all have reversed versions. They have the same names with _r tacked on to the end. (Documentation here.)


回答 1

在matplotlib中,颜色映射不是列表,但包含的颜色列表为colormap.colors。并且该模块matplotlib.colors提供了ListedColormap()根据列表生成颜色图的功能。因此,您可以通过以下方式反转任何颜色图

colormap_r = ListedColormap(colormap.colors[::-1])

In matplotlib a color map isn’t a list, but it contains the list of its colors as colormap.colors. And the module matplotlib.colors provides a function ListedColormap() to generate a color map from a list. So you can reverse any color map by doing

colormap_r = ListedColormap(colormap.colors[::-1])

回答 2

解决方案非常简单。假设您要使用“秋天”颜色图方案。标准版:

cmap = matplotlib.cm.autumn

要反转颜色图色谱,请使用get_cmap()函数,并将“ _r”附加到颜色图标题中,如下所示:

cmap_reversed = matplotlib.cm.get_cmap('autumn_r')

The solution is pretty straightforward. Suppose you want to use the “autumn” colormap scheme. The standard version:

cmap = matplotlib.cm.autumn

To reverse the colormap color spectrum, use get_cmap() function and append ‘_r’ to the colormap title like this:

cmap_reversed = matplotlib.cm.get_cmap('autumn_r')

回答 3

由于a LinearSegmentedColormaps基于红色,绿色和蓝色的词典,因此有必要将每个项目取反:

import matplotlib.pyplot as plt
import matplotlib as mpl
def reverse_colourmap(cmap, name = 'my_cmap_r'):
    """
    In: 
    cmap, name 
    Out:
    my_cmap_r

    Explanation:
    t[0] goes from 0 to 1
    row i:   x  y0  y1 -> t[0] t[1] t[2]
                   /
                  /
    row i+1: x  y0  y1 -> t[n] t[1] t[2]

    so the inverse should do the same:
    row i+1: x  y1  y0 -> 1-t[0] t[2] t[1]
                   /
                  /
    row i:   x  y1  y0 -> 1-t[n] t[2] t[1]
    """        
    reverse = []
    k = []   

    for key in cmap._segmentdata:    
        k.append(key)
        channel = cmap._segmentdata[key]
        data = []

        for t in channel:                    
            data.append((1-t[0],t[2],t[1]))            
        reverse.append(sorted(data))    

    LinearL = dict(zip(k,reverse))
    my_cmap_r = mpl.colors.LinearSegmentedColormap(name, LinearL) 
    return my_cmap_r

看到它的工作原理:

my_cmap        
<matplotlib.colors.LinearSegmentedColormap at 0xd5a0518>

my_cmap_r = reverse_colourmap(my_cmap)

fig = plt.figure(figsize=(8, 2))
ax1 = fig.add_axes([0.05, 0.80, 0.9, 0.15])
ax2 = fig.add_axes([0.05, 0.475, 0.9, 0.15])
norm = mpl.colors.Normalize(vmin=0, vmax=1)
cb1 = mpl.colorbar.ColorbarBase(ax1, cmap = my_cmap, norm=norm,orientation='horizontal')
cb2 = mpl.colorbar.ColorbarBase(ax2, cmap = my_cmap_r, norm=norm, orientation='horizontal')

在此处输入图片说明

编辑


我没有收到user3445587的评论。它在彩虹色图上工作良好:

cmap = mpl.cm.jet
cmap_r = reverse_colourmap(cmap)

fig = plt.figure(figsize=(8, 2))
ax1 = fig.add_axes([0.05, 0.80, 0.9, 0.15])
ax2 = fig.add_axes([0.05, 0.475, 0.9, 0.15])
norm = mpl.colors.Normalize(vmin=0, vmax=1)
cb1 = mpl.colorbar.ColorbarBase(ax1, cmap = cmap, norm=norm,orientation='horizontal')
cb2 = mpl.colorbar.ColorbarBase(ax2, cmap = cmap_r, norm=norm, orientation='horizontal')

在此处输入图片说明

但这对于自定义声明的颜色图特别有用,因为自定义声明的颜色图没有默认值_r。以下示例取自http://matplotlib.org/examples/pylab_examples/custom_cmap.html

cdict1 = {'red':   ((0.0, 0.0, 0.0),
                   (0.5, 0.0, 0.1),
                   (1.0, 1.0, 1.0)),

         'green': ((0.0, 0.0, 0.0),
                   (1.0, 0.0, 0.0)),

         'blue':  ((0.0, 0.0, 1.0),
                   (0.5, 0.1, 0.0),
                   (1.0, 0.0, 0.0))
         }

blue_red1 = mpl.colors.LinearSegmentedColormap('BlueRed1', cdict1)
blue_red1_r = reverse_colourmap(blue_red1)

fig = plt.figure(figsize=(8, 2))
ax1 = fig.add_axes([0.05, 0.80, 0.9, 0.15])
ax2 = fig.add_axes([0.05, 0.475, 0.9, 0.15])

norm = mpl.colors.Normalize(vmin=0, vmax=1)
cb1 = mpl.colorbar.ColorbarBase(ax1, cmap = blue_red1, norm=norm,orientation='horizontal')
cb2 = mpl.colorbar.ColorbarBase(ax2, cmap = blue_red1_r, norm=norm, orientation='horizontal')

在此处输入图片说明

As a LinearSegmentedColormaps is based on a dictionary of red, green and blue, it’s necessary to reverse each item:

import matplotlib.pyplot as plt
import matplotlib as mpl
def reverse_colourmap(cmap, name = 'my_cmap_r'):
    """
    In: 
    cmap, name 
    Out:
    my_cmap_r

    Explanation:
    t[0] goes from 0 to 1
    row i:   x  y0  y1 -> t[0] t[1] t[2]
                   /
                  /
    row i+1: x  y0  y1 -> t[n] t[1] t[2]

    so the inverse should do the same:
    row i+1: x  y1  y0 -> 1-t[0] t[2] t[1]
                   /
                  /
    row i:   x  y1  y0 -> 1-t[n] t[2] t[1]
    """        
    reverse = []
    k = []   

    for key in cmap._segmentdata:    
        k.append(key)
        channel = cmap._segmentdata[key]
        data = []

        for t in channel:                    
            data.append((1-t[0],t[2],t[1]))            
        reverse.append(sorted(data))    

    LinearL = dict(zip(k,reverse))
    my_cmap_r = mpl.colors.LinearSegmentedColormap(name, LinearL) 
    return my_cmap_r

See that it works:

my_cmap        
<matplotlib.colors.LinearSegmentedColormap at 0xd5a0518>

my_cmap_r = reverse_colourmap(my_cmap)

fig = plt.figure(figsize=(8, 2))
ax1 = fig.add_axes([0.05, 0.80, 0.9, 0.15])
ax2 = fig.add_axes([0.05, 0.475, 0.9, 0.15])
norm = mpl.colors.Normalize(vmin=0, vmax=1)
cb1 = mpl.colorbar.ColorbarBase(ax1, cmap = my_cmap, norm=norm,orientation='horizontal')
cb2 = mpl.colorbar.ColorbarBase(ax2, cmap = my_cmap_r, norm=norm, orientation='horizontal')

enter image description here

EDIT


I don’t get the comment of user3445587. It works fine on the rainbow colormap:

cmap = mpl.cm.jet
cmap_r = reverse_colourmap(cmap)

fig = plt.figure(figsize=(8, 2))
ax1 = fig.add_axes([0.05, 0.80, 0.9, 0.15])
ax2 = fig.add_axes([0.05, 0.475, 0.9, 0.15])
norm = mpl.colors.Normalize(vmin=0, vmax=1)
cb1 = mpl.colorbar.ColorbarBase(ax1, cmap = cmap, norm=norm,orientation='horizontal')
cb2 = mpl.colorbar.ColorbarBase(ax2, cmap = cmap_r, norm=norm, orientation='horizontal')

enter image description here

But it especially works nice for custom declared colormaps, as there is not a default _r for custom declared colormaps. Following example taken from http://matplotlib.org/examples/pylab_examples/custom_cmap.html:

cdict1 = {'red':   ((0.0, 0.0, 0.0),
                   (0.5, 0.0, 0.1),
                   (1.0, 1.0, 1.0)),

         'green': ((0.0, 0.0, 0.0),
                   (1.0, 0.0, 0.0)),

         'blue':  ((0.0, 0.0, 1.0),
                   (0.5, 0.1, 0.0),
                   (1.0, 0.0, 0.0))
         }

blue_red1 = mpl.colors.LinearSegmentedColormap('BlueRed1', cdict1)
blue_red1_r = reverse_colourmap(blue_red1)

fig = plt.figure(figsize=(8, 2))
ax1 = fig.add_axes([0.05, 0.80, 0.9, 0.15])
ax2 = fig.add_axes([0.05, 0.475, 0.9, 0.15])

norm = mpl.colors.Normalize(vmin=0, vmax=1)
cb1 = mpl.colorbar.ColorbarBase(ax1, cmap = blue_red1, norm=norm,orientation='horizontal')
cb2 = mpl.colorbar.ColorbarBase(ax2, cmap = blue_red1_r, norm=norm, orientation='horizontal')

enter image description here


回答 4

从Matplotlib 2.0开始,有reversed()一种用于ListedColormapLinearSegmentedColorMap对象的方法,因此您只需

cmap_reversed = cmap.reversed()

是文档。

As of Matplotlib 2.0, there is a reversed() method for ListedColormap and LinearSegmentedColorMap objects, so you can just do

cmap_reversed = cmap.reversed()

Here is the documentation.


回答 5

有两种类型的LinearSegmentedColormaps。在某些情况下,_segmentdata是明确给出的,例如,对于jet:

>>> cm.jet._segmentdata
{'blue': ((0.0, 0.5, 0.5), (0.11, 1, 1), (0.34, 1, 1), (0.65, 0, 0), (1, 0, 0)), 'red': ((0.0, 0, 0), (0.35, 0, 0), (0.66, 1, 1), (0.89, 1, 1), (1, 0.5, 0.5)), 'green': ((0.0, 0, 0), (0.125, 0, 0), (0.375, 1, 1), (0.64, 1, 1), (0.91, 0, 0), (1, 0, 0))}

对于Rainbow,_segmentdata给出如下:

>>> cm.rainbow._segmentdata
{'blue': <function <lambda> at 0x7fac32ac2b70>, 'red': <function <lambda> at 0x7fac32ac7840>, 'green': <function <lambda> at 0x7fac32ac2d08>}

我们可以在matplotlib的源代码中找到这些函数,这些函数以

_rainbow_data = {
        'red': gfunc[33],   # 33: lambda x: np.abs(2 * x - 0.5),
        'green': gfunc[13], # 13: lambda x: np.sin(x * np.pi),
        'blue': gfunc[10],  # 10: lambda x: np.cos(x * np.pi / 2)
}

您想要的一切都已经在matplotlib中完成,只需调用cm.revcmap,即可反转两种类型的segmentdata,因此

cm.revcmap(cm.rainbow._segmentdata)

应该做的工作-您可以简单地从中创建一个新的LinearSegmentData。在revcmap中,基于功能的SegmentData的逆转是通过

def _reverser(f):
    def freversed(x):
        return f(1 - x)
    return freversed

而其他列表照常颠倒

valnew = [(1.0 - x, y1, y0) for x, y0, y1 in reversed(val)] 

所以实际上,您想要的全部是

def reverse_colourmap(cmap, name = 'my_cmap_r'):
     return mpl.colors.LinearSegmentedColormap(name, cm.revcmap(cmap._segmentdata)) 

There are two types of LinearSegmentedColormaps. In some, the _segmentdata is given explicitly, e.g., for jet:

>>> cm.jet._segmentdata
{'blue': ((0.0, 0.5, 0.5), (0.11, 1, 1), (0.34, 1, 1), (0.65, 0, 0), (1, 0, 0)), 'red': ((0.0, 0, 0), (0.35, 0, 0), (0.66, 1, 1), (0.89, 1, 1), (1, 0.5, 0.5)), 'green': ((0.0, 0, 0), (0.125, 0, 0), (0.375, 1, 1), (0.64, 1, 1), (0.91, 0, 0), (1, 0, 0))}

For rainbow, _segmentdata is given as follows:

>>> cm.rainbow._segmentdata
{'blue': <function <lambda> at 0x7fac32ac2b70>, 'red': <function <lambda> at 0x7fac32ac7840>, 'green': <function <lambda> at 0x7fac32ac2d08>}

We can find the functions in the source of matplotlib, where they are given as

_rainbow_data = {
        'red': gfunc[33],   # 33: lambda x: np.abs(2 * x - 0.5),
        'green': gfunc[13], # 13: lambda x: np.sin(x * np.pi),
        'blue': gfunc[10],  # 10: lambda x: np.cos(x * np.pi / 2)
}

Everything you want is already done in matplotlib, just call cm.revcmap, which reverses both types of segmentdata, so

cm.revcmap(cm.rainbow._segmentdata)

should do the job – you can simply create a new LinearSegmentData from that. In revcmap, the reversal of function based SegmentData is done with

def _reverser(f):
    def freversed(x):
        return f(1 - x)
    return freversed

while the other lists are reversed as usual

valnew = [(1.0 - x, y1, y0) for x, y0, y1 in reversed(val)] 

So actually the whole thing you want, is

def reverse_colourmap(cmap, name = 'my_cmap_r'):
     return mpl.colors.LinearSegmentedColormap(name, cm.revcmap(cmap._segmentdata)) 

回答 6

还没有内置的方法可以反转任意颜色图,但是一种简单的解决方案是实际上不修改颜色条,而是创建一个反转的Normalize对象:

from matplotlib.colors import Normalize

class InvertedNormalize(Normalize):
    def __call__(self, *args, **kwargs):
        return 1 - super(InvertedNormalize, self).__call__(*args, **kwargs)

然后可以plot_surface通过执行以下操作将其与其他Matplotlib绘图功能一起使用

inverted_norm = InvertedNormalize(vmin=10, vmax=100)
ax.plot_surface(..., cmap=<your colormap>, norm=inverted_norm)

这将与任何Matplotlib颜色图一起使用。

There is no built-in way (yet) of reversing arbitrary colormaps, but one simple solution is to actually not modify the colorbar but to create an inverting Normalize object:

from matplotlib.colors import Normalize

class InvertedNormalize(Normalize):
    def __call__(self, *args, **kwargs):
        return 1 - super(InvertedNormalize, self).__call__(*args, **kwargs)

You can then use this with plot_surface and other Matplotlib plotting functions by doing e.g.

inverted_norm = InvertedNormalize(vmin=10, vmax=100)
ax.plot_surface(..., cmap=<your colormap>, norm=inverted_norm)

This will work with any Matplotlib colormap.


matplotlib图例标记仅一次

问题:matplotlib图例标记仅一次

我经常使用以下命令在matplotlib图上绘制点:

x = 10
y = 100
plot(x, y, "k*", label="Global Optimum")
legend()

但是,这会导致图例两次在图例中放置一颗星星,如下所示:

* * Global Optimum

当我真的希望它看起来像:

 *  Global Optimum

我该怎么做呢?

I often plot a point on a matplotlib plot with:

x = 10
y = 100
plot(x, y, "k*", label="Global Optimum")
legend()

However, this causes the legend to put a star in the legend twice, such that it looks like:

* * Global Optimum

when I really want it to look like:

 *  Global Optimum

How do I do this?


回答 0

这应该工作:

legend(numpoints=1)

顺便说一句,如果您添加行

legend.numpoints     : 1      # the number of points in the legend line

到您的matplotlibrc文件,那么这将是新的默认设置。

[另请参见散点图,具体取决于您的情节。]

API:链接到API文档

This should work:

legend(numpoints=1)

BTW, if you add the line

legend.numpoints     : 1      # the number of points in the legend line

to your matplotlibrc file, then this will be the new default.

[See also scatterpoints, depending on your plot.]

API: Link to API docs


回答 1

我喜欢在每个python脚本中动态更改matplotlib rc参数。为了实现这个目标,我只是在python文件的开头使用了类似的东西。

from pylab import *
rcParams['legend.numpoints'] = 1

这将适用于从我的python文件生成的所有图。

编辑:对于那些谁不喜欢导入pylab,长答案是

import matplotlib as mpl
mpl.rcParams['legend.numpoints'] = 1

I like to change my matplotlib rc parameters dynamically in every python script. To achieve this goal I simply use somthing like that at the beginning of my python files.

from pylab import *
rcParams['legend.numpoints'] = 1

This will apply to all plots generated from my python file.

EDIT: For those who do not like to import pylab, the long answer is

import matplotlib as mpl
mpl.rcParams['legend.numpoints'] = 1