标签归档:matplotlib

如何在Matplotlib中的子图中添加标题?

问题:如何在Matplotlib中的子图中添加标题?

我有一个包含许多子图的图。

fig = plt.figure(num=None, figsize=(26, 12), dpi=80, facecolor='w', edgecolor='k')
fig.canvas.set_window_title('Window Title')

# Returns the Axes instance
ax = fig.add_subplot(311) 
ax2 = fig.add_subplot(312) 
ax3 = fig.add_subplot(313) 

如何为子图添加标题?

fig.suptitle为所有图形添加标题,尽管ax.set_title()存在,但后者不向我的子图添加任何标题。

谢谢您的帮助。

编辑:纠正了有关的错字set_title()。谢谢罗格·卡西斯

I have one figure which contains many subplots.

fig = plt.figure(num=None, figsize=(26, 12), dpi=80, facecolor='w', edgecolor='k')
fig.canvas.set_window_title('Window Title')

# Returns the Axes instance
ax = fig.add_subplot(311) 
ax2 = fig.add_subplot(312) 
ax3 = fig.add_subplot(313) 

How do I add titles to the subplots?

fig.suptitle adds a title to all graphs and although ax.set_title() exists, the latter does not add any title to my subplots.

Thank you for your help.

Edit: Corrected typo about set_title(). Thanks Rutger Kassies


回答 0

ax.title.set_text('My Plot Title') 似乎也可以。

fig = plt.figure()
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222)
ax3 = fig.add_subplot(223)
ax4 = fig.add_subplot(224)
ax1.title.set_text('First Plot')
ax2.title.set_text('Second Plot')
ax3.title.set_text('Third Plot')
ax4.title.set_text('Fourth Plot')
plt.show()

ax.title.set_text('My Plot Title') seems to work too.

fig = plt.figure()
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222)
ax3 = fig.add_subplot(223)
ax4 = fig.add_subplot(224)
ax1.title.set_text('First Plot')
ax2.title.set_text('Second Plot')
ax3.title.set_text('Third Plot')
ax4.title.set_text('Fourth Plot')
plt.show()


回答 1

ax.set_title() 应该为单独的子图设置标题:

import matplotlib.pyplot as plt

if __name__ == "__main__":
    data = [1, 2, 3, 4, 5]

    fig = plt.figure()
    fig.suptitle("Title for whole figure", fontsize=16)
    ax = plt.subplot("211")
    ax.set_title("Title for first plot")
    ax.plot(data)

    ax = plt.subplot("212")
    ax.set_title("Title for second plot")
    ax.plot(data)

    plt.show()

您可以检查该代码是否适合您?也许以后会覆盖某些内容?

ax.set_title() should set the titles for separate subplots:

import matplotlib.pyplot as plt

if __name__ == "__main__":
    data = [1, 2, 3, 4, 5]

    fig = plt.figure()
    fig.suptitle("Title for whole figure", fontsize=16)
    ax = plt.subplot("211")
    ax.set_title("Title for first plot")
    ax.plot(data)

    ax = plt.subplot("212")
    ax.set_title("Title for second plot")
    ax.plot(data)

    plt.show()

Can you check if this code works for you? Maybe something overwrites them later?


回答 2

一个简短的答案假设 import matplotlib.pyplot as plt

plt.gca().set_title('title')

如:

plt.subplot(221)
plt.gca().set_title('title')
plt.subplot(222)
etc...

这样就不需要多余的变量。

A shorthand answer assuming import matplotlib.pyplot as plt:

plt.gca().set_title('title')

as in:

plt.subplot(221)
plt.gca().set_title('title')
plt.subplot(222)
etc...

Then there is no need for superfluous variables.


回答 3

如果要缩短它,可以编写:

import matplolib.pyplot as plt
for i in range(4):
    plt.subplot(2,2,i+1).set_title('Subplot n°{}' .format(i+1))
plt.show()

它可能不太清楚,但是您不需要更多的行或变量

If you want to make it shorter, you could write :

import matplolib.pyplot as plt
for i in range(4):
    plt.subplot(2,2,i+1).set_title('Subplot n°{}' .format(i+1))
plt.show()

It makes it maybe less clear but you don’t need more lines or variables


回答 4

如果您有多张图片,并且想要循环浏览它们,并与标题一起按1顺序显示-这就是您可以执行的操作。无需显式定义ax1,ax2等。

  1. 要注意的是,您可以像代码的第1行一样定义动态轴(ax),并且可以在循环中设置其标题。
  2. 2D阵列的行是轴(ax)的长度(len)
  3. 每行有2个项目,即列表中的列表(第2点)
  4. 一旦选择了正确的轴(ax)或子图,set_title可用于设置标题。
import matplotlib.pyplot as plt    
fig, ax = plt.subplots(2, 2, figsize=(6, 8))  
for i in range(len(ax)): 
    for j in range(len(ax[i])):
        ## ax[i,j].imshow(test_images_gr[0].reshape(28,28))
        ax[i,j].set_title('Title-' + str(i) + str(j))

In case you have multiple images and you want to loop though them and show them 1 by 1 along with titles – this is what you can do. No need to explicitly define ax1, ax2, etc.

  1. The catch is you can define dynamic axes(ax) as in Line 1 of code and you can set its title inside a loop.
  2. The rows of 2D array is length (len) of axis(ax)
  3. Each row has 2 items i.e. It is list within a list (Point No.2)
  4. set_title can be used to set title, once the proper axes(ax) or subplot is selected.
import matplotlib.pyplot as plt    
fig, ax = plt.subplots(2, 2, figsize=(6, 8))  
for i in range(len(ax)): 
    for j in range(len(ax[i])):
        ## ax[i,j].imshow(test_images_gr[0].reshape(28,28))
        ax[i,j].set_title('Title-' + str(i) + str(j))

回答 5

fig, (ax1, ax2, ax3, ax4) = plt.subplots(nrows=1, ncols=4,figsize=(11, 7))

grid = plt.GridSpec(2, 2, wspace=0.2, hspace=0.5)

ax1 = plt.subplot(grid[0, 0])
ax2 = plt.subplot(grid[0, 1:])
ax3 = plt.subplot(grid[1, :1])
ax4 = plt.subplot(grid[1, 1:])

ax1.title.set_text('First Plot')
ax2.title.set_text('Second Plot')
ax3.title.set_text('Third Plot')
ax4.title.set_text('Fourth Plot')

plt.show()

fig, (ax1, ax2, ax3, ax4) = plt.subplots(nrows=1, ncols=4,figsize=(11, 7))

grid = plt.GridSpec(2, 2, wspace=0.2, hspace=0.5)

ax1 = plt.subplot(grid[0, 0])
ax2 = plt.subplot(grid[0, 1:])
ax3 = plt.subplot(grid[1, :1])
ax4 = plt.subplot(grid[1, 1:])

ax1.title.set_text('First Plot')
ax2.title.set_text('Second Plot')
ax3.title.set_text('Third Plot')
ax4.title.set_text('Fourth Plot')

plt.show()


回答 6

我倾向于越来越使用的一种解决方案是:

import matplotlib.pyplot as plt

fig, axs = plt.subplots(2, 2)  # 1
for i, ax in enumerate(axs.ravel()): # 2
    ax.set_title("Plot #{}".format(i)) # 3
  1. 创建任意数量的轴
  2. axs.ravel()将您的2维对象转换为行主要样式的1维矢量
  3. 将标题分配给当前轴对象

A solution I tend to use more and more is this one:

import matplotlib.pyplot as plt

fig, axs = plt.subplots(2, 2)  # 1
for i, ax in enumerate(axs.ravel()): # 2
    ax.set_title("Plot #{}".format(i)) # 3
  1. Create your arbitrary number of axes
  2. axs.ravel() converts your 2-dim object to a 1-dim vector in row-major style
  3. assigns the title to the current axis-object

将matplotlib图例移到轴外使其被图框切断

问题:将matplotlib图例移到轴外使其被图框切断

我熟悉以下问题:

Matplotlib savefig在图外带有图例

如何将图例排除在情节之外

这些问题的答案似乎很奢侈,它能够摆弄轴的确切收缩,以使图例适合。

但是,缩小轴并不是一个理想的解决方案,因为它会使数据变小,从而实际上更难以解释。特别是当它复杂并且有很多事情要发生时…因此需要一个大的传说

文档中复杂图例的示例说明了此需求,因为其图中的图例实际上完全遮盖了多个数据点。

http://matplotlib.sourceforge.net/users/legend_guide.html#legend-of-complex-plots

我想做的是动态扩展图形框的大小,以适应扩展的图形图例。

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(-2*np.pi, 2*np.pi, 0.1)
fig = plt.figure(1)
ax = fig.add_subplot(111)
ax.plot(x, np.sin(x), label='Sine')
ax.plot(x, np.cos(x), label='Cosine')
ax.plot(x, np.arctan(x), label='Inverse tan')
lgd = ax.legend(loc=9, bbox_to_anchor=(0.5,0))
ax.grid('on')

请注意,最终标签“ Inverse tan”实际上是如何位于图形框之外的(看起来很不完整-而不是出版物质量!)

最后,有人告诉我这是R和LaTeX中的正常行为,所以我有些困惑,为什么在python中如此困难……是否有历史原因?Matlab在这件事上是否同样贫穷?

我在pastebin http://pastebin.com/grVjc007上有(仅略长)此代码的较长版本

I’m familiar with the following questions:

Matplotlib savefig with a legend outside the plot

How to put the legend out of the plot

It seems that the answers in these questions have the luxury of being able to fiddle with the exact shrinking of the axis so that the legend fits.

Shrinking the axes, however, is not an ideal solution because it makes the data smaller making it actually more difficult to interpret; particularly when its complex and there are lots of things going on … hence needing a large legend

The example of a complex legend in the documentation demonstrates the need for this because the legend in their plot actually completely obscures multiple data points.

http://matplotlib.sourceforge.net/users/legend_guide.html#legend-of-complex-plots

What I would like to be able to do is dynamically expand the size of the figure box to accommodate the expanding figure legend.

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(-2*np.pi, 2*np.pi, 0.1)
fig = plt.figure(1)
ax = fig.add_subplot(111)
ax.plot(x, np.sin(x), label='Sine')
ax.plot(x, np.cos(x), label='Cosine')
ax.plot(x, np.arctan(x), label='Inverse tan')
lgd = ax.legend(loc=9, bbox_to_anchor=(0.5,0))
ax.grid('on')

Notice how the final label ‘Inverse tan’ is actually outside the figure box (and looks badly cutoff – not publication quality!)

Finally, I’ve been told that this is normal behaviour in R and LaTeX, so I’m a little confused why this is so difficult in python… Is there a historical reason? Is Matlab equally poor on this matter?

I have the (only slightly) longer version of this code on pastebin http://pastebin.com/grVjc007


回答 0

抱歉,EMS,但实际上我刚刚从matplotlib邮件列表中得到了另一个答复(感谢Benjamin Root)。

我正在寻找的代码将savefig调用调整为:

fig.savefig('samplefigure', bbox_extra_artists=(lgd,), bbox_inches='tight')
#Note that the bbox_extra_artists must be an iterable

这显然类似于调用紧密布局,但是您允许savefig在计算中考虑额外的艺术家。实际上,这确实根据需要调整了图形框的大小。

import matplotlib.pyplot as plt
import numpy as np

plt.gcf().clear()
x = np.arange(-2*np.pi, 2*np.pi, 0.1)
fig = plt.figure(1)
ax = fig.add_subplot(111)
ax.plot(x, np.sin(x), label='Sine')
ax.plot(x, np.cos(x), label='Cosine')
ax.plot(x, np.arctan(x), label='Inverse tan')
handles, labels = ax.get_legend_handles_labels()
lgd = ax.legend(handles, labels, loc='upper center', bbox_to_anchor=(0.5,-0.1))
text = ax.text(-0.2,1.05, "Aribitrary text", transform=ax.transAxes)
ax.set_title("Trigonometry")
ax.grid('on')
fig.savefig('samplefigure', bbox_extra_artists=(lgd,text), bbox_inches='tight')

这将生成:

[edit]这个问题的目的是完全避免使用任意文本的任意坐标放置,这是解决这些问题的传统方法。尽管如此,最近许多编辑仍坚持将它们放入,通常以导致代码引发错误的方式进行。我现在已经解决了这些问题,并整理了任意文本,以说明如何在bbox_extra_artists算法中也考虑这些问题。

Sorry EMS, but I actually just got another response from the matplotlib mailling list (Thanks goes out to Benjamin Root).

The code I am looking for is adjusting the savefig call to:

fig.savefig('samplefigure', bbox_extra_artists=(lgd,), bbox_inches='tight')
#Note that the bbox_extra_artists must be an iterable

This is apparently similar to calling tight_layout, but instead you allow savefig to consider extra artists in the calculation. This did in fact resize the figure box as desired.

import matplotlib.pyplot as plt
import numpy as np

plt.gcf().clear()
x = np.arange(-2*np.pi, 2*np.pi, 0.1)
fig = plt.figure(1)
ax = fig.add_subplot(111)
ax.plot(x, np.sin(x), label='Sine')
ax.plot(x, np.cos(x), label='Cosine')
ax.plot(x, np.arctan(x), label='Inverse tan')
handles, labels = ax.get_legend_handles_labels()
lgd = ax.legend(handles, labels, loc='upper center', bbox_to_anchor=(0.5,-0.1))
text = ax.text(-0.2,1.05, "Aribitrary text", transform=ax.transAxes)
ax.set_title("Trigonometry")
ax.grid('on')
fig.savefig('samplefigure', bbox_extra_artists=(lgd,text), bbox_inches='tight')

This produces:

[edit] The intent of this question was to completely avoid the use of arbitrary coordinate placements of arbitrary text as was the traditional solution to these problems. Despite this, numerous edits recently have insisted on putting these in, often in ways that led to the code raising an error. I have now fixed the issues and tidied the arbitrary text to show how these are also considered within the bbox_extra_artists algorithm.


回答 1

补充:我发现应该立即解决问题的方法,但是下面的代码其余部分也提供了替代方法。

使用此subplots_adjust()函数可将子图的底部向上移动:

fig.subplots_adjust(bottom=0.2) # <-- Change the 0.02 to work for your plot.

然后bbox_to_anchor,在图例命令的图例部分中使用偏移量进行播放,以在所需的位置获得图例框。设置figsize和使用的某种组合subplots_adjust(bottom=...)应该可以为您产生质量图。

备选: 我只是更改了这一行:

fig = plt.figure(1)

至:

fig = plt.figure(num=1, figsize=(13, 13), dpi=80, facecolor='w', edgecolor='k')

并改变了

lgd = ax.legend(loc=9, bbox_to_anchor=(0.5,0))

lgd = ax.legend(loc=9, bbox_to_anchor=(0.5,-0.02))

并在我的屏幕(24英寸CRT显示器)上正常显示。

此处figsize=(M,N)将图形窗口设置为M英寸乘N英寸。只是玩这个,直到它看起来适合您。将其转换为更具可伸缩性的图像格式,并在必要时使用GIMP进行编辑,或者viewport在包括图形时仅使用LaTeX 选项进行裁剪。

Added: I found something that should do the trick right away, but the rest of the code below also offers an alternative.

Use the subplots_adjust() function to move the bottom of the subplot up:

fig.subplots_adjust(bottom=0.2) # <-- Change the 0.02 to work for your plot.

Then play with the offset in the legend bbox_to_anchor part of the legend command, to get the legend box where you want it. Some combination of setting the figsize and using the subplots_adjust(bottom=...) should produce a quality plot for you.

Alternative: I simply changed the line:

fig = plt.figure(1)

to:

fig = plt.figure(num=1, figsize=(13, 13), dpi=80, facecolor='w', edgecolor='k')

and changed

lgd = ax.legend(loc=9, bbox_to_anchor=(0.5,0))

to

lgd = ax.legend(loc=9, bbox_to_anchor=(0.5,-0.02))

and it shows up fine on my screen (a 24-inch CRT monitor).

Here figsize=(M,N) sets the figure window to be M inches by N inches. Just play with this until it looks right for you. Convert it to a more scalable image format and use GIMP to edit if necessary, or just crop with the LaTeX viewport option when including graphics.


回答 2

这是另一个非常手动的解决方案。您可以定义轴的大小,并相应地考虑填充(包括图例和刻度线)。希望它对某人有用。

示例(轴大小相同!):

码:

#==================================================
# Plot table

colmap = [(0,0,1) #blue
         ,(1,0,0) #red
         ,(0,1,0) #green
         ,(1,1,0) #yellow
         ,(1,0,1) #magenta
         ,(1,0.5,0.5) #pink
         ,(0.5,0.5,0.5) #gray
         ,(0.5,0,0) #brown
         ,(1,0.5,0) #orange
         ]


import matplotlib.pyplot as plt
import numpy as np

import collections
df = collections.OrderedDict()
df['labels']        = ['GWP100a\n[kgCO2eq]\n\nasedf\nasdf\nadfs','human\n[pts]','ressource\n[pts]'] 
df['all-petroleum long name'] = [3,5,2]
df['all-electric']  = [5.5, 1, 3]
df['HEV']           = [3.5, 2, 1]
df['PHEV']          = [3.5, 2, 1]

numLabels = len(df.values()[0])
numItems = len(df)-1
posX = np.arange(numLabels)+1
width = 1.0/(numItems+1)

fig = plt.figure(figsize=(2,2))
ax = fig.add_subplot(111)
for iiItem in range(1,numItems+1):
  ax.bar(posX+(iiItem-1)*width, df.values()[iiItem], width, color=colmap[iiItem-1], label=df.keys()[iiItem])
ax.set(xticks=posX+width*(0.5*numItems), xticklabels=df['labels'])

#--------------------------------------------------
# Change padding and margins, insert legend

fig.tight_layout() #tight margins
leg = ax.legend(loc='upper left', bbox_to_anchor=(1.02, 1), borderaxespad=0)
plt.draw() #to know size of legend

padLeft   = ax.get_position().x0 * fig.get_size_inches()[0]
padBottom = ax.get_position().y0 * fig.get_size_inches()[1]
padTop    = ( 1 - ax.get_position().y0 - ax.get_position().height ) * fig.get_size_inches()[1]
padRight  = ( 1 - ax.get_position().x0 - ax.get_position().width ) * fig.get_size_inches()[0]
dpi       = fig.get_dpi()
padLegend = ax.get_legend().get_frame().get_width() / dpi 

widthAx = 3 #inches
heightAx = 3 #inches
widthTot = widthAx+padLeft+padRight+padLegend
heightTot = heightAx+padTop+padBottom

# resize ipython window (optional)
posScreenX = 1366/2-10 #pixel
posScreenY = 0 #pixel
canvasPadding = 6 #pixel
canvasBottom = 40 #pixel
ipythonWindowSize = '{0}x{1}+{2}+{3}'.format(int(round(widthTot*dpi))+2*canvasPadding
                                            ,int(round(heightTot*dpi))+2*canvasPadding+canvasBottom
                                            ,posScreenX,posScreenY)
fig.canvas._tkcanvas.master.geometry(ipythonWindowSize) 
plt.draw() #to resize ipython window. Has to be done BEFORE figure resizing!

# set figure size and ax position
fig.set_size_inches(widthTot,heightTot)
ax.set_position([padLeft/widthTot, padBottom/heightTot, widthAx/widthTot, heightAx/heightTot])
plt.draw()
plt.show()
#--------------------------------------------------
#==================================================

Here is another, very manual solution. You can define the size of the axis and paddings are considered accordingly (including legend and tickmarks). Hope it is of use to somebody.

Example (axes size are the same!):

Code:

#==================================================
# Plot table

colmap = [(0,0,1) #blue
         ,(1,0,0) #red
         ,(0,1,0) #green
         ,(1,1,0) #yellow
         ,(1,0,1) #magenta
         ,(1,0.5,0.5) #pink
         ,(0.5,0.5,0.5) #gray
         ,(0.5,0,0) #brown
         ,(1,0.5,0) #orange
         ]


import matplotlib.pyplot as plt
import numpy as np

import collections
df = collections.OrderedDict()
df['labels']        = ['GWP100a\n[kgCO2eq]\n\nasedf\nasdf\nadfs','human\n[pts]','ressource\n[pts]'] 
df['all-petroleum long name'] = [3,5,2]
df['all-electric']  = [5.5, 1, 3]
df['HEV']           = [3.5, 2, 1]
df['PHEV']          = [3.5, 2, 1]

numLabels = len(df.values()[0])
numItems = len(df)-1
posX = np.arange(numLabels)+1
width = 1.0/(numItems+1)

fig = plt.figure(figsize=(2,2))
ax = fig.add_subplot(111)
for iiItem in range(1,numItems+1):
  ax.bar(posX+(iiItem-1)*width, df.values()[iiItem], width, color=colmap[iiItem-1], label=df.keys()[iiItem])
ax.set(xticks=posX+width*(0.5*numItems), xticklabels=df['labels'])

#--------------------------------------------------
# Change padding and margins, insert legend

fig.tight_layout() #tight margins
leg = ax.legend(loc='upper left', bbox_to_anchor=(1.02, 1), borderaxespad=0)
plt.draw() #to know size of legend

padLeft   = ax.get_position().x0 * fig.get_size_inches()[0]
padBottom = ax.get_position().y0 * fig.get_size_inches()[1]
padTop    = ( 1 - ax.get_position().y0 - ax.get_position().height ) * fig.get_size_inches()[1]
padRight  = ( 1 - ax.get_position().x0 - ax.get_position().width ) * fig.get_size_inches()[0]
dpi       = fig.get_dpi()
padLegend = ax.get_legend().get_frame().get_width() / dpi 

widthAx = 3 #inches
heightAx = 3 #inches
widthTot = widthAx+padLeft+padRight+padLegend
heightTot = heightAx+padTop+padBottom

# resize ipython window (optional)
posScreenX = 1366/2-10 #pixel
posScreenY = 0 #pixel
canvasPadding = 6 #pixel
canvasBottom = 40 #pixel
ipythonWindowSize = '{0}x{1}+{2}+{3}'.format(int(round(widthTot*dpi))+2*canvasPadding
                                            ,int(round(heightTot*dpi))+2*canvasPadding+canvasBottom
                                            ,posScreenX,posScreenY)
fig.canvas._tkcanvas.master.geometry(ipythonWindowSize) 
plt.draw() #to resize ipython window. Has to be done BEFORE figure resizing!

# set figure size and ax position
fig.set_size_inches(widthTot,heightTot)
ax.set_position([padLeft/widthTot, padBottom/heightTot, widthAx/widthTot, heightAx/heightTot])
plt.draw()
plt.show()
#--------------------------------------------------
#==================================================

如何使用Pyplot在所有子图上方设置单个主标题?

问题:如何使用Pyplot在所有子图上方设置单个主标题?

我正在使用pyplot。我有4个子图。如何在所有子图上方设置一个主标题?title()将其设置在最后一个子图上方。

I am using pyplot. I have 4 subplots. How to set a single, main title above all the subplots? title() sets it above the last subplot.


回答 0

使用pyplot.suptitleFigure.suptitle

import matplotlib.pyplot as plt
import numpy as np

fig=plt.figure()
data=np.arange(900).reshape((30,30))
for i in range(1,5):
    ax=fig.add_subplot(2,2,i)        
    ax.imshow(data)

fig.suptitle('Main title') # or plt.suptitle('Main title')
plt.show()

Use pyplot.suptitle or Figure.suptitle:

import matplotlib.pyplot as plt
import numpy as np

fig=plt.figure()
data=np.arange(900).reshape((30,30))
for i in range(1,5):
    ax=fig.add_subplot(2,2,i)        
    ax.imshow(data)

fig.suptitle('Main title') # or plt.suptitle('Main title')
plt.show()


回答 1

将其应用于自己的绘图时,我发现一些要点:

  • 我更喜欢使用一致性fig.suptitle(title)而不是plt.suptitle(title)
  • 使用fig.tight_layout()标题时,必须与fig.subplots_adjust(top=0.88)
  • 请参阅以下有关字体大小的答案

示例代码取自matplotlib文档中的subplots演示,并已通过主标题进行了调整。

import matplotlib.pyplot as plt
import numpy as np

# Simple data to display in various forms
x = np.linspace(0, 2 * np.pi, 400)
y = np.sin(x ** 2)

fig, axarr = plt.subplots(2, 2)
fig.suptitle("This Main Title is Nicely Formatted", fontsize=16)

axarr[0, 0].plot(x, y)
axarr[0, 0].set_title('Axis [0,0] Subtitle')
axarr[0, 1].scatter(x, y)
axarr[0, 1].set_title('Axis [0,1] Subtitle')
axarr[1, 0].plot(x, y ** 2)
axarr[1, 0].set_title('Axis [1,0] Subtitle')
axarr[1, 1].scatter(x, y ** 2)
axarr[1, 1].set_title('Axis [1,1] Subtitle')

# # Fine-tune figure; hide x ticks for top plots and y ticks for right plots
plt.setp([a.get_xticklabels() for a in axarr[0, :]], visible=False)
plt.setp([a.get_yticklabels() for a in axarr[:, 1]], visible=False)

# Tight layout often produces nice results
# but requires the title to be spaced accordingly
fig.tight_layout()
fig.subplots_adjust(top=0.88)

plt.show()

A few points I find useful when applying this to my own plots:

  • I prefer the consistency of using fig.suptitle(title) rather than plt.suptitle(title)
  • When using fig.tight_layout() the title must be shifted with fig.subplots_adjust(top=0.88)
  • See answer below about fontsizes

Example code taken from subplots demo in matplotlib docs and adjusted with a master title.

import matplotlib.pyplot as plt
import numpy as np

# Simple data to display in various forms
x = np.linspace(0, 2 * np.pi, 400)
y = np.sin(x ** 2)

fig, axarr = plt.subplots(2, 2)
fig.suptitle("This Main Title is Nicely Formatted", fontsize=16)

axarr[0, 0].plot(x, y)
axarr[0, 0].set_title('Axis [0,0] Subtitle')
axarr[0, 1].scatter(x, y)
axarr[0, 1].set_title('Axis [0,1] Subtitle')
axarr[1, 0].plot(x, y ** 2)
axarr[1, 0].set_title('Axis [1,0] Subtitle')
axarr[1, 1].scatter(x, y ** 2)
axarr[1, 1].set_title('Axis [1,1] Subtitle')

# # Fine-tune figure; hide x ticks for top plots and y ticks for right plots
plt.setp([a.get_xticklabels() for a in axarr[0, :]], visible=False)
plt.setp([a.get_yticklabels() for a in axarr[:, 1]], visible=False)

# Tight layout often produces nice results
# but requires the title to be spaced accordingly
fig.tight_layout()
fig.subplots_adjust(top=0.88)

plt.show()

回答 2

如果您的子图中也有标题,则可能需要调整主标题大小:

plt.suptitle("Main Title", size=16)

If your subplots also have titles, you may need to adjust the main title size:

plt.suptitle("Main Title", size=16)

修改刻度标签文本

问题:修改刻度标签文本

我想对图中的几个选定的刻度标签进行一些修改。

例如,如果我这样做:

label = axes.yaxis.get_major_ticks()[2].label
label.set_fontsize(size)
label.set_rotation('vertical')

字体大小和刻度标签的方向已更改。

但是,如果尝试:

label.set_text('Foo')

蜱标签修改。另外,如果我这样做:

print label.get_text()

什么都不会打印。

这里有些奇怪。当我尝试这个:

 from pylab import *
 axes = figure().add_subplot(111)
 t = arange(0.0, 2.0, 0.01)
 s = sin(2*pi*t)
 axes.plot(t, s)
 for ticklabel in axes.get_xticklabels():
     print ticklabel.get_text()

仅打印空字符串,但图中包含标记为“ 0.0”,“ 0.5”,“ 1.0”,“ 1.5”和“ 2.0”的刻度。

I want to make some modifications to a few selected tick labels in a plot.

For example, if I do:

label = axes.yaxis.get_major_ticks()[2].label
label.set_fontsize(size)
label.set_rotation('vertical')

the font size and the orientation of the tick label is changed.

However, if try:

label.set_text('Foo')

the tick label is not modified. Also if I do:

print label.get_text()

nothing is printed.

Here’s some more strangeness. When I tried this:

 from pylab import *
 axes = figure().add_subplot(111)
 t = arange(0.0, 2.0, 0.01)
 s = sin(2*pi*t)
 axes.plot(t, s)
 for ticklabel in axes.get_xticklabels():
     print ticklabel.get_text()

Only empty strings are printed, but the plot contains ticks labeled as ‘0.0’, ‘0.5’, ‘1.0’, ‘1.5’, and ‘2.0’.


回答 0

警告:除非ticklabel已设置为字符串(例如在boxplot中通常是这种情况),否则这不适用于任何比Matplotlib更新的版本1.1.0。如果您正在使用当前的github主机,则将无法使用。我不确定问题是什么…可能是意外更改,也可能不是。

通常,您会按照以下步骤进行操作:

import matplotlib.pyplot as plt

fig, ax = plt.subplots()

# We need to draw the canvas, otherwise the labels won't be positioned and 
# won't have values yet.
fig.canvas.draw()

labels = [item.get_text() for item in ax.get_xticklabels()]
labels[1] = 'Testing'

ax.set_xticklabels(labels)

plt.show()

要了解为什么需要跳过这么多的障碍,您需要更多地了解matplotlib的结构。

Matplotlib故意避免对刻度等进行“静态”定位,除非明确告知。假设您要与图进行交互,因此图的边界,刻度线,刻度标签等将动态变化。

因此,您不能只设置给定刻度标签的文本。默认情况下,每次绘制图形时,都会通过轴的“定位器”和“格式化程序”将其重置。

但是,如果将“定位器”和“格式器”设置为静态(分别为FixedLocatorFixedFormatter),则刻度线标签保持不变。

这是什么set_*ticklabelsax.*axis.set_ticklabels做。

希望这可以使我们更清楚地知道为什么更改单个刻度标签有些麻烦。

通常,您实际要做的只是注释特定位置。在这种情况下,请查看annotate

Caveat: Unless the ticklabels are already set to a string (as is usually the case in e.g. a boxplot), this will not work with any version of matplotlib newer than 1.1.0. If you’re working from the current github master, this won’t work. I’m not sure what the problem is yet… It may be an unintended change, or it may not be…

Normally, you’d do something along these lines:

import matplotlib.pyplot as plt

fig, ax = plt.subplots()

# We need to draw the canvas, otherwise the labels won't be positioned and 
# won't have values yet.
fig.canvas.draw()

labels = [item.get_text() for item in ax.get_xticklabels()]
labels[1] = 'Testing'

ax.set_xticklabels(labels)

plt.show()

To understand the reason why you need to jump through so many hoops, you need to understand a bit more about how matplotlib is structured.

Matplotlib deliberately avoids doing “static” positioning of ticks, etc, unless it’s explicitly told to. The assumption is that you’ll want to interact with the plot, and so the bounds of the plot, ticks, ticklabels, etc will be dynamically changing.

Therefore, you can’t just set the text of a given tick label. By default, it’s re-set by the axis’s Locator and Formatter every time the plot is drawn.

However, if the Locators and Formatters are set to be static (FixedLocator and FixedFormatter, respectively), then the tick labels stay the same.

This is what set_*ticklabels or ax.*axis.set_ticklabels does.

Hopefully that makes it slighly more clear as to why changing an individual tick label is a bit convoluted.

Often, what you actually want to do is just annotate a certain position. In that case, look into annotate, instead.


回答 1

pylabxticks也可以做到这一点

import matplotlib
import matplotlib.pyplot as plt
x = [0,1,2]
y = [90,40,65]
labels = ['high', 'low', 37337]
plt.plot(x,y, 'r')
plt.xticks(x, labels, rotation='vertical')
plt.show()

http://matplotlib.org/examples/ticks_and_spines/ticklabels_demo_rotation.html

One can also do this with pylab and xticks

import matplotlib
import matplotlib.pyplot as plt
x = [0,1,2]
y = [90,40,65]
labels = ['high', 'low', 37337]
plt.plot(x,y, 'r')
plt.xticks(x, labels, rotation='vertical')
plt.show()

http://matplotlib.org/examples/ticks_and_spines/ticklabels_demo_rotation.html


回答 2

在较新版本的中matplotlib,如果未为刻度标签设置一堆str值,则''默认情况下它们是刻度值(绘制绘图时,标签只是刻度值)。知道这一点,要获得所需的输出,将需要执行以下操作:

>>> from pylab import *
>>> axes = figure().add_subplot(111)
>>> a=axes.get_xticks().tolist()
>>> a[1]='change'
>>> axes.set_xticklabels(a)
[<matplotlib.text.Text object at 0x539aa50>, <matplotlib.text.Text object at 0x53a0c90>, 
<matplotlib.text.Text object at 0x53a73d0>, <matplotlib.text.Text object at 0x53a7a50>, 
<matplotlib.text.Text object at 0x53aa110>, <matplotlib.text.Text object at 0x53aa790>]
>>> plt.show()

结果:

现在,如果您进行检查_xticklabels,它们不再是一堆''

>>> [item.get_text() for item in axes.get_xticklabels()]
['0.0', 'change', '1.0', '1.5', '2.0']

它适用于从1.1.1rc1到当前版本的版本2.0

In newer versions of matplotlib, if you do not set the tick labels with a bunch of str values, they are '' by default (and when the plot is draw the labels are simply the ticks values). Knowing that, to get your desired output would require something like this:

>>> from pylab import *
>>> axes = figure().add_subplot(111)
>>> a=axes.get_xticks().tolist()
>>> a[1]='change'
>>> axes.set_xticklabels(a)
[<matplotlib.text.Text object at 0x539aa50>, <matplotlib.text.Text object at 0x53a0c90>, 
<matplotlib.text.Text object at 0x53a73d0>, <matplotlib.text.Text object at 0x53a7a50>, 
<matplotlib.text.Text object at 0x53aa110>, <matplotlib.text.Text object at 0x53aa790>]
>>> plt.show()

and the result:

and now if you check the _xticklabels, they are no longer a bunch of ''.

>>> [item.get_text() for item in axes.get_xticklabels()]
['0.0', 'change', '1.0', '1.5', '2.0']

It works in the versions from 1.1.1rc1 to the current version 2.0.


回答 3

自问这个问题已经有一段时间了。截至今天(matplotlib 2.2.2),经过一些阅读和试验,我认为最好/正确的方法如下:

Matplotlib有一个名为模块,ticker“中包含用于支持完全可配置的蜱定位和格式化”。要修改绘图中的特定刻度,以下对我有用:

import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import numpy as np 

def update_ticks(x, pos):
    if x == 0:
        return 'Mean'
    elif pos == 6:
        return 'pos is 6'
    else:
        return x

data = np.random.normal(0, 1, 1000)
fig, ax = plt.subplots()
ax.hist(data, bins=25, edgecolor='black')
ax.xaxis.set_major_formatter(mticker.FuncFormatter(update_ticks))
plt.show()

警告! x是刻度的值,并且pos是刻度在轴上的相对位置。请注意,建立索引时,其pos值以开头1,而不是0通常的值。


就我而言,我试图y-axis用百分比值格式化直方图的格式。mticker有另一个名为的类PercentFormatter,可以轻松地做到这一点,而无需像以前一样定义单独的函数:

import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import numpy as np 

data = np.random.normal(0, 1, 1000)
fig, ax = plt.subplots()
weights = np.ones_like(data) / len(data)
ax.hist(data, bins=25, weights=weights, edgecolor='black')
ax.yaxis.set_major_formatter(mticker.PercentFormatter(xmax=1.0, decimals=1))
plt.show()

在这种情况下 xmax,数据值对应于100%。百分比计算为x / xmax * 100,这就是我们固定的原因xmax=1.0。同样,decimals是要在该点之后放置的小数位数。

It’s been a while since this question was asked. As of today (matplotlib 2.2.2) and after some reading and trials, I think the best/proper way is the following:

Matplotlib has a module named ticker that “contains classes to support completely configurable tick locating and formatting”. To modify a specific tick from the plot, the following works for me:

import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import numpy as np 

def update_ticks(x, pos):
    if x == 0:
        return 'Mean'
    elif pos == 6:
        return 'pos is 6'
    else:
        return x

data = np.random.normal(0, 1, 1000)
fig, ax = plt.subplots()
ax.hist(data, bins=25, edgecolor='black')
ax.xaxis.set_major_formatter(mticker.FuncFormatter(update_ticks))
plt.show()

Caveat! x is the value of the tick and pos is its relative position in order in the axis. Notice that pos takes values starting in 1, not in 0 as usual when indexing.


In my case, I was trying to format the y-axis of a histogram with percentage values. mticker has another class named PercentFormatter that can do this easily without the need to define a separate function as before:

import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import numpy as np 

data = np.random.normal(0, 1, 1000)
fig, ax = plt.subplots()
weights = np.ones_like(data) / len(data)
ax.hist(data, bins=25, weights=weights, edgecolor='black')
ax.yaxis.set_major_formatter(mticker.PercentFormatter(xmax=1.0, decimals=1))
plt.show()

In this case xmax is the data value that corresponds to 100%. Percentages are computed as x / xmax * 100, that’s why we fix xmax=1.0. Also, decimals is the number of decimal places to place after the point.


回答 4

axes类具有set_yticklabels函数,可用于设置刻度标签,如下所示:

#ax is the axes instance
group_labels = ['control', 'cold treatment',
             'hot treatment', 'another treatment',
             'the last one']

ax.set_xticklabels(group_labels)

我仍在努力,为什么上面的示例不起作用。

The axes class has a set_yticklabels function which allows you to set the tick labels, like so:

#ax is the axes instance
group_labels = ['control', 'cold treatment',
             'hot treatment', 'another treatment',
             'the last one']

ax.set_xticklabels(group_labels)

I’m still working on why your example above didn’t work.


回答 5

这有效:

import matplotlib.pyplot as plt

fig, ax1 = plt.subplots(1,1)

x1 = [0,1,2,3]
squad = ['Fultz','Embiid','Dario','Simmons']

ax1.set_xticks(x1)
ax1.set_xticklabels(squad, minor=False, rotation=45)

This works:

import matplotlib.pyplot as plt

fig, ax1 = plt.subplots(1,1)

x1 = [0,1,2,3]
squad = ['Fultz','Embiid','Dario','Simmons']

ax1.set_xticks(x1)
ax1.set_xticklabels(squad, minor=False, rotation=45)


回答 6

这也适用于matplotlib 3:

x1 = [0,1,2,3]
squad = ['Fultz','Embiid','Dario','Simmons']

plt.xticks(x1, squad, rotation=45)

This also works in matplotlib 3:

x1 = [0,1,2,3]
squad = ['Fultz','Embiid','Dario','Simmons']

plt.xticks(x1, squad, rotation=45)

回答 7

如果您不使用figax并且想要修改所有标签(例如,用于规范化),则可以执行以下操作:

labels, locations = plt.yticks()
plt.yticks(labels, labels/max(labels))

If you do not work with fig and ax and you want to modify all labels (e.g. for normalization) you can do this:

labels, locations = plt.yticks()
plt.yticks(labels, labels/max(labels))


回答 8

试试这个 :

  fig,axis = plt.subplots(nrows=1,ncols=1,figsize=(13,6),sharex=True)
  axis.set_xticklabels(['0', 'testing', '10000', '20000', '30000'],fontsize=22)

Try this :

  fig,axis = plt.subplots(nrows=1,ncols=1,figsize=(13,6),sharex=True)
  axis.set_xticklabels(['0', 'testing', '10000', '20000', '30000'],fontsize=22)

回答 9

你可以做:

for k in ax.get_xmajorticklabels():
    if some-condition:
        k.set_color(any_colour_you_like)

draw()

you can do:

for k in ax.get_xmajorticklabels():
    if some-condition:
        k.set_color(any_colour_you_like)

draw()

如何为散点图放置单个标签

问题:如何为散点图放置单个标签

我正在尝试在matplotlib中进行散点图,但找不到找到将标记添加到点的方法。例如:

scatter1=plt.scatter(data1["x"], data1["y"], marker="o",
                     c="blue",
                     facecolors="white",
                     edgecolors="blue")

我希望“ y”中的点具有标签为“ point 1”,“ point 2”等。我无法弄清楚。

I am trying to do a scatter plot in matplotlib and I couldn’t find a way to add tags to the points. For example:

scatter1=plt.scatter(data1["x"], data1["y"], marker="o",
                     c="blue",
                     facecolors="white",
                     edgecolors="blue")

I want for the points in “y” to have labels as “point 1”, “point 2”, etc. I couldn’t figure it out.


回答 0

也许使用plt.annotate

import numpy as np
import matplotlib.pyplot as plt

N = 10
data = np.random.random((N, 4))
labels = ['point{0}'.format(i) for i in range(N)]

plt.subplots_adjust(bottom = 0.1)
plt.scatter(
    data[:, 0], data[:, 1], marker='o', c=data[:, 2], s=data[:, 3] * 1500,
    cmap=plt.get_cmap('Spectral'))

for label, x, y in zip(labels, data[:, 0], data[:, 1]):
    plt.annotate(
        label,
        xy=(x, y), xytext=(-20, 20),
        textcoords='offset points', ha='right', va='bottom',
        bbox=dict(boxstyle='round,pad=0.5', fc='yellow', alpha=0.5),
        arrowprops=dict(arrowstyle = '->', connectionstyle='arc3,rad=0'))

plt.show()

Perhaps use plt.annotate:

import numpy as np
import matplotlib.pyplot as plt

N = 10
data = np.random.random((N, 4))
labels = ['point{0}'.format(i) for i in range(N)]

plt.subplots_adjust(bottom = 0.1)
plt.scatter(
    data[:, 0], data[:, 1], marker='o', c=data[:, 2], s=data[:, 3] * 1500,
    cmap=plt.get_cmap('Spectral'))

for label, x, y in zip(labels, data[:, 0], data[:, 1]):
    plt.annotate(
        label,
        xy=(x, y), xytext=(-20, 20),
        textcoords='offset points', ha='right', va='bottom',
        bbox=dict(boxstyle='round,pad=0.5', fc='yellow', alpha=0.5),
        arrowprops=dict(arrowstyle = '->', connectionstyle='arc3,rad=0'))

plt.show()


使用熊猫绘制相关矩阵

问题:使用熊猫绘制相关矩阵

我有一个包含大量特征的数据集,因此分析相关矩阵变得非常困难。我想绘制一个相关矩阵,我们可以使用dataframe.corr()熊猫库中的函数获取相关矩阵。熊猫库是否提供任何内置函数来绘制此矩阵?

I have a data set with huge number of features, so analysing the correlation matrix has become very difficult. I want to plot a correlation matrix which we get using dataframe.corr() function from pandas library. Is there any built-in function provided by the pandas library to plot this matrix?


回答 0

您可以使用pyplot.matshow()matplotlib

import matplotlib.pyplot as plt

plt.matshow(dataframe.corr())
plt.show()

编辑:

在注释中,要求更改轴刻度标签。这是一个豪华的版本,它使用较大的图形尺寸绘制,具有与数据框匹配的轴标签,以及用于解释色阶的色条图例。

我将介绍如何调整标签的大小和旋转角度,并使用数字比例使颜色条和主图形的高度相同。

f = plt.figure(figsize=(19, 15))
plt.matshow(df.corr(), fignum=f.number)
plt.xticks(range(df.shape[1]), df.columns, fontsize=14, rotation=45)
plt.yticks(range(df.shape[1]), df.columns, fontsize=14)
cb = plt.colorbar()
cb.ax.tick_params(labelsize=14)
plt.title('Correlation Matrix', fontsize=16);

You can use pyplot.matshow() from matplotlib:

import matplotlib.pyplot as plt

plt.matshow(dataframe.corr())
plt.show()

Edit:

In the comments was a request for how to change the axis tick labels. Here’s a deluxe version that is drawn on a bigger figure size, has axis labels to match the dataframe, and a colorbar legend to interpret the color scale.

I’m including how to adjust the size and rotation of the labels, and I’m using a figure ratio that makes the colorbar and the main figure come out the same height.

f = plt.figure(figsize=(19, 15))
plt.matshow(df.corr(), fignum=f.number)
plt.xticks(range(df.shape[1]), df.columns, fontsize=14, rotation=45)
plt.yticks(range(df.shape[1]), df.columns, fontsize=14)
cb = plt.colorbar()
cb.ax.tick_params(labelsize=14)
plt.title('Correlation Matrix', fontsize=16);


回答 1

如果您的主要目标是可视化相关矩阵,而不是自己创建图表,则便捷的pandas 样式选项是可行的内置解决方案:

import pandas as pd
import numpy as np

rs = np.random.RandomState(0)
df = pd.DataFrame(rs.rand(10, 10))
corr = df.corr()
corr.style.background_gradient(cmap='coolwarm')
# 'RdBu_r' & 'BrBG' are other good diverging colormaps

请注意,这需要在支持渲染HTML的后端中,例如JupyterLab Notebook。(深色背景上的自动浅色文本来自现有PR,而不是最新发布的版本pandas0.23)。


造型

您可以轻松限制数字精度:

corr.style.background_gradient(cmap='coolwarm').set_precision(2)

或者,如果您更喜欢没有注释的矩阵,也可以完全删除数字:

corr.style.background_gradient(cmap='coolwarm').set_properties(**{'font-size': '0pt'})

样式文档还包括更高级样式的说明,例如如何更改鼠标指针悬停在其上方的单元格的显示。为了保存输出,您可以通过附加render()方法来返回HTML ,然后将其写入文件(或者只是截取屏幕快照,以减少非正式目的)。


时间比较

在我的测试中,速度是10×10矩阵的style.background_gradient()4倍,是plt.matshow()120x的120 倍sns.heatmap()。不幸的是,它的伸缩性不如plt.matshow():对于100×100的矩阵,两者花费的时间大约相同,而plt.matshow()对于1000×1000的矩阵,两者的速度要快10倍。


保存

有几种方法可以保存样式化数据框:

  • 通过追加render()方法返回HTML ,然后将输出写入文件。
  • .xslx通过附加该to_excel()方法以条件格式另存为文件。
  • 与imgkit结合以保存位图
  • 截屏(出于非正式目的)。

熊猫> = 0.24的更新

通过设置axis=None,现在可以基于整个矩阵而不是每列或每行计算颜色:

corr.style.background_gradient(cmap='coolwarm', axis=None)

If your main goal is to visualize the correlation matrix, rather than creating a plot per se, the convenient pandas styling options is a viable built-in solution:

import pandas as pd
import numpy as np

rs = np.random.RandomState(0)
df = pd.DataFrame(rs.rand(10, 10))
corr = df.corr()
corr.style.background_gradient(cmap='coolwarm')
# 'RdBu_r' & 'BrBG' are other good diverging colormaps

Note that this needs to be in a backend that supports rendering HTML, such as the JupyterLab Notebook. (The automatic light text on dark backgrounds is from an existing PR and not the latest released version, pandas 0.23).


Styling

You can easily limit the digit precision:

corr.style.background_gradient(cmap='coolwarm').set_precision(2)

Or get rid of the digits altogether if you prefer the matrix without annotations:

corr.style.background_gradient(cmap='coolwarm').set_properties(**{'font-size': '0pt'})

The styling documentation also includes instructions of more advanced styles, such as how to change the display of the cell the mouse pointer is hovering over. To save the output you could return the HTML by appending the render() method and then write it to a file (or just take a screenshot for less formal purposes).


Time comparison

In my testing, style.background_gradient() was 4x faster than plt.matshow() and 120x faster than sns.heatmap() with a 10×10 matrix. Unfortunately it doesn’t scale as well as plt.matshow(): the two take about the same time for a 100×100 matrix, and plt.matshow() is 10x faster for a 1000×1000 matrix.


Saving

There are a few possible ways to save the stylized dataframe:

  • Return the HTML by appending the render() method and then write the output to a file.
  • Save as an .xslx file with conditional formatting by appending the to_excel() method.
  • Combine with imgkit to save a bitmap
  • Take a screenshot (for less formal purposes).

Update for pandas >= 0.24

By setting axis=None, it is now possible to compute the colors based on the entire matrix rather than per column or per row:

corr.style.background_gradient(cmap='coolwarm', axis=None)


回答 2

试试这个函数,它也显示相关矩阵的变量名:

def plot_corr(df,size=10):
    '''Function plots a graphical correlation matrix for each pair of columns in the dataframe.

    Input:
        df: pandas DataFrame
        size: vertical and horizontal size of the plot'''

    corr = df.corr()
    fig, ax = plt.subplots(figsize=(size, size))
    ax.matshow(corr)
    plt.xticks(range(len(corr.columns)), corr.columns);
    plt.yticks(range(len(corr.columns)), corr.columns);

Try this function, which also displays variable names for the correlation matrix:

def plot_corr(df,size=10):
    '''Function plots a graphical correlation matrix for each pair of columns in the dataframe.

    Input:
        df: pandas DataFrame
        size: vertical and horizontal size of the plot'''

    corr = df.corr()
    fig, ax = plt.subplots(figsize=(size, size))
    ax.matshow(corr)
    plt.xticks(range(len(corr.columns)), corr.columns);
    plt.yticks(range(len(corr.columns)), corr.columns);

回答 3

Seaborn的热图版本:

import seaborn as sns
corr = dataframe.corr()
sns.heatmap(corr, 
            xticklabels=corr.columns.values,
            yticklabels=corr.columns.values)

Seaborn’s heatmap version:

import seaborn as sns
corr = dataframe.corr()
sns.heatmap(corr, 
            xticklabels=corr.columns.values,
            yticklabels=corr.columns.values)

回答 4

您可以通过绘制Seaborn的热图或熊猫的散点图来观察要素之间的关系。

散点矩阵:

pd.scatter_matrix(dataframe, alpha = 0.3, figsize = (14,8), diagonal = 'kde');

如果您还想可视化每个特征的偏斜度,请使用深浅的成对图。

sns.pairplot(dataframe)

SNS热图:

import seaborn as sns

f, ax = pl.subplots(figsize=(10, 8))
corr = dataframe.corr()
sns.heatmap(corr, mask=np.zeros_like(corr, dtype=np.bool), cmap=sns.diverging_palette(220, 10, as_cmap=True),
            square=True, ax=ax)

输出将是要素的关联图。即见下面的例子。

杂货和洗涤剂之间的相关性很高。类似地:

具有高相关性的产品:
  1. 杂货和洗涤剂。
具有中等相关性的产品:
  1. 牛奶和杂货
  2. 牛奶和洗涤剂_纸
低相关性产品:
  1. 牛奶和熟食
  2. 冷冻和新鲜。
  3. 冷冻和熟食。

从线对图:您可以从线对图或散布矩阵观察同一组关系。但是从这些我们可以说,数据是否是正态分布的。

注意:以上是从数据中提取的相同图形,用于绘制热图。

You can observe the relation between features either by drawing a heat map from seaborn or scatter matrix from pandas.

Scatter Matrix:

pd.scatter_matrix(dataframe, alpha = 0.3, figsize = (14,8), diagonal = 'kde');

If you want to visualize each feature’s skewness as well – use seaborn pairplots.

sns.pairplot(dataframe)

Sns Heatmap:

import seaborn as sns

f, ax = pl.subplots(figsize=(10, 8))
corr = dataframe.corr()
sns.heatmap(corr, mask=np.zeros_like(corr, dtype=np.bool), cmap=sns.diverging_palette(220, 10, as_cmap=True),
            square=True, ax=ax)

The output will be a correlation map of the features. i.e. see the below example.

The correlation between grocery and detergents is high. Similarly:

Pdoducts With High Correlation:
  1. Grocery and Detergents.
Products With Medium Correlation:
  1. Milk and Grocery
  2. Milk and Detergents_Paper
Products With Low Correlation:
  1. Milk and Deli
  2. Frozen and Fresh.
  3. Frozen and Deli.

From Pairplots: You can observe same set of relations from pairplots or scatter matrix. But from these we can say that whether the data is normally distributed or not.

Note: The above is same graph taken from the data, which is used to draw heatmap.


回答 5

您可以从matplotlib使用imshow()方法

import pandas as pd
import matplotlib.pyplot as plt
plt.style.use('ggplot')

plt.imshow(X.corr(), cmap=plt.cm.Reds, interpolation='nearest')
plt.colorbar()
tick_marks = [i for i in range(len(X.columns))]
plt.xticks(tick_marks, X.columns, rotation='vertical')
plt.yticks(tick_marks, X.columns)
plt.show()

You can use imshow() method from matplotlib

import pandas as pd
import matplotlib.pyplot as plt
plt.style.use('ggplot')

plt.imshow(X.corr(), cmap=plt.cm.Reds, interpolation='nearest')
plt.colorbar()
tick_marks = [i for i in range(len(X.columns))]
plt.xticks(tick_marks, X.columns, rotation='vertical')
plt.yticks(tick_marks, X.columns)
plt.show()

回答 6

如果您df使用的是数据框,则可以简单地使用:

import matplotlib.pyplot as plt
import seaborn as sns

plt.figure(figsize=(15, 10))
sns.heatmap(df.corr(), annot=True)

If you dataframe is df you can simply use:

import matplotlib.pyplot as plt
import seaborn as sns

plt.figure(figsize=(15, 10))
sns.heatmap(df.corr(), annot=True)

回答 7

statmodels图形还提供了一个很好的相关矩阵视图

import statsmodels.api as sm
import matplotlib.pyplot as plt

corr = dataframe.corr()
sm.graphics.plot_corr(corr, xnames=list(corr.columns))
plt.show()

statmodels graphics also gives a nice view of correlation matrix

import statsmodels.api as sm
import matplotlib.pyplot as plt

corr = dataframe.corr()
sm.graphics.plot_corr(corr, xnames=list(corr.columns))
plt.show()

回答 8

为了完整起见,如果有人正在使用Jupyter,则是2019年底我所知道的seaborn最简单的解决方案:

import seaborn as sns
sns.heatmap(dataframe.corr())

For completeness, the simplest solution i know with seaborn as of late 2019, if one is using Jupyter:

import seaborn as sns
sns.heatmap(dataframe.corr())

回答 9

与其他方法一起使用pairplot也会很好,它会给出所有情况的散点图,

import pandas as pd
import numpy as np
import seaborn as sns
rs = np.random.RandomState(0)
df = pd.DataFrame(rs.rand(10, 10))
sns.pairplot(df)

Along with other methods it is also good to have pairplot which will give scatter plot for all the cases-

import pandas as pd
import numpy as np
import seaborn as sns
rs = np.random.RandomState(0)
df = pd.DataFrame(rs.rand(10, 10))
sns.pairplot(df)

回答 10

形式相关矩阵,在我的情况下zdf是我需要执行相关矩阵的数据帧。

corrMatrix =zdf.corr()
corrMatrix.to_csv('sm_zscaled_correlation_matrix.csv');
html = corrMatrix.style.background_gradient(cmap='RdBu').set_precision(2).render()

# Writing the output to a html file.
with open('test.html', 'w') as f:
   print('<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-widthinitial-scale=1.0"><title>Document</title></head><style>table{word-break: break-all;}</style><body>' + html+'</body></html>', file=f)

然后我们可以截屏。或将html转换为图像文件。

Form correlation matrix, in my case zdf is the dataframe which i need perform correlation matrix.

corrMatrix =zdf.corr()
corrMatrix.to_csv('sm_zscaled_correlation_matrix.csv');
html = corrMatrix.style.background_gradient(cmap='RdBu').set_precision(2).render()

# Writing the output to a html file.
with open('test.html', 'w') as f:
   print('<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-widthinitial-scale=1.0"><title>Document</title></head><style>table{word-break: break-all;}</style><body>' + html+'</body></html>', file=f)

Then we can take screenshot. or convert html to an image file.


Matplotlibight_layout()未考虑人物字幕

问题:Matplotlibight_layout()未考虑人物字幕

如果我在matplotlib图上添加了字幕,则该字幕会被该字幕图的标题覆盖。有人知道如何轻松地解决这个问题吗?我尝试过该tight_layout()功能,但只会使情况变得更糟。

例:

import numpy as np
import matplotlib.pyplot as plt

f = np.random.random(100)
g = np.random.random(100)
fig = plt.figure()
fig.suptitle('Long Suptitle', fontsize=24)
plt.subplot(121)
plt.plot(f)
plt.title('Very Long Title 1', fontsize=20)
plt.subplot(122)
plt.plot(g)
plt.title('Very Long Title 2', fontsize=20)
plt.tight_layout()
plt.show()

If I add a subtitle to my matplotlib figure it gets overlaid by the subplot’s titles. Does anybody know how to easily take care of that? I tried the tight_layout() function, but it only makes things worse.

Example:

import numpy as np
import matplotlib.pyplot as plt

f = np.random.random(100)
g = np.random.random(100)
fig = plt.figure()
fig.suptitle('Long Suptitle', fontsize=24)
plt.subplot(121)
plt.plot(f)
plt.title('Very Long Title 1', fontsize=20)
plt.subplot(122)
plt.plot(g)
plt.title('Very Long Title 2', fontsize=20)
plt.tight_layout()
plt.show()

回答 0

您可以在tight_layout调用中调整子图的几何形状,如下所示:

fig.tight_layout(rect=[0, 0.03, 1, 0.95])

如文档(https://matplotlib.org/users/tight_layout_guide.html)中所述:

tight_layout()仅考虑刻度标签,轴标签和标题。因此,其他艺术家可能会被裁剪,也可能会重叠。

You can adjust the subplot geometry in the very tight_layout call as follows:

fig.tight_layout(rect=[0, 0.03, 1, 0.95])

As it’s stated in the documentation (https://matplotlib.org/users/tight_layout_guide.html):

tight_layout() only considers ticklabels, axis labels, and titles. Thus, other artists may be clipped and also may overlap.


回答 1

您可以使用plt.subplots_adjust(top=0.85)以下方法手动调整间距:

import numpy as np
import matplotlib.pyplot as plt

f = np.random.random(100)
g = np.random.random(100)
fig = plt.figure()
fig.suptitle('Long Suptitle', fontsize=24)
plt.subplot(121)
plt.plot(f)
plt.title('Very Long Title 1', fontsize=20)
plt.subplot(122)
plt.plot(g)
plt.title('Very Long Title 2', fontsize=20)
plt.subplots_adjust(top=0.85)
plt.show()

You could manually adjust the spacing using plt.subplots_adjust(top=0.85):

import numpy as np
import matplotlib.pyplot as plt

f = np.random.random(100)
g = np.random.random(100)
fig = plt.figure()
fig.suptitle('Long Suptitle', fontsize=24)
plt.subplot(121)
plt.plot(f)
plt.title('Very Long Title 1', fontsize=20)
plt.subplot(122)
plt.plot(g)
plt.title('Very Long Title 2', fontsize=20)
plt.subplots_adjust(top=0.85)
plt.show()

回答 2

您可以很容易地在代码中更改的一件事就是fontsize您正在使用标题。但是,我将假设您不只是想这样做!

一些替代使用fig.subplots_adjust(top=0.85)

通常tight_layout(),在将所有内容放置在合适的位置方面做得很好,以免它们重叠。tight_layout()在这种情况下无济于事的原因是因为tight_layout()没有考虑到fig.suptitle()。GitHub上有一个未解决的问题:https : //github.com/matplotlib/matplotlib/issues/829 [由于需要完整的几何管理器,于2014年关闭-移至https://github.com/matplotlib/matplotlib / issues / 1109 ]。

如果您阅读该线程,则可以解决涉及的问题GridSpec。关键是在tight_layout使用rectkwarg 调用时,在图的顶部保留一些空间。对于您的问题,代码变为:

使用GridSpec

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

f = np.random.random(100)
g = np.random.random(100)

fig = plt.figure(1)
gs1 = gridspec.GridSpec(1, 2)
ax_list = [fig.add_subplot(ss) for ss in gs1]

ax_list[0].plot(f)
ax_list[0].set_title('Very Long Title 1', fontsize=20)

ax_list[1].plot(g)
ax_list[1].set_title('Very Long Title 2', fontsize=20)

fig.suptitle('Long Suptitle', fontsize=24)    

gs1.tight_layout(fig, rect=[0, 0.03, 1, 0.95])  

plt.show()

结果:

可能GridSpec对您来说有点过大,否则您的实际问题将涉及在更大的画布上进行更多的子图绘制或其他复杂情况。一个简单的技巧是仅使用annotate()并将其锁定'figure fraction'到来模仿suptitle。不过,一旦查看输出,您可能需要进行一些更精细的调整。请注意,这第二个解决方案并不能使用tight_layout()

更简单的解决方案(尽管可能需要微调)

fig = plt.figure(2)

ax1 = plt.subplot(121)
ax1.plot(f)
ax1.set_title('Very Long Title 1', fontsize=20)

ax2 = plt.subplot(122)
ax2.plot(g)
ax2.set_title('Very Long Title 2', fontsize=20)

# fig.suptitle('Long Suptitle', fontsize=24)
# Instead, do a hack by annotating the first axes with the desired 
# string and set the positioning to 'figure fraction'.
fig.get_axes()[0].annotate('Long Suptitle', (0.5, 0.95), 
                            xycoords='figure fraction', ha='center', 
                            fontsize=24
                            )
plt.show()

结果:

[使用Python2.7.3(64位)和matplotlib1.2.0]

One thing you could change in your code very easily is the fontsize you are using for the titles. However, I am going to assume that you don’t just want to do that!

Some alternatives to using fig.subplots_adjust(top=0.85):

Usually tight_layout() does a pretty good job at positioning everything in good locations so that they don’t overlap. The reason tight_layout() doesn’t help in this case is because tight_layout() does not take fig.suptitle() into account. There is an open issue about this on GitHub: https://github.com/matplotlib/matplotlib/issues/829 [closed in 2014 due to requiring a full geometry manager – shifted to https://github.com/matplotlib/matplotlib/issues/1109 ].

If you read the thread, there is a solution to your problem involving GridSpec. The key is to leave some space at the top of the figure when calling tight_layout, using the rect kwarg. For your problem, the code becomes:

Using GridSpec

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

f = np.random.random(100)
g = np.random.random(100)

fig = plt.figure(1)
gs1 = gridspec.GridSpec(1, 2)
ax_list = [fig.add_subplot(ss) for ss in gs1]

ax_list[0].plot(f)
ax_list[0].set_title('Very Long Title 1', fontsize=20)

ax_list[1].plot(g)
ax_list[1].set_title('Very Long Title 2', fontsize=20)

fig.suptitle('Long Suptitle', fontsize=24)    

gs1.tight_layout(fig, rect=[0, 0.03, 1, 0.95])  

plt.show()

The result:

Maybe GridSpec is a bit overkill for you, or your real problem will involve many more subplots on a much larger canvas, or other complications. A simple hack is to just use annotate() and lock the coordinates to the 'figure fraction' to imitate a suptitle. You may need to make some finer adjustments once you take a look at the output, though. Note that this second solution does not use tight_layout().

Simpler solution (though may need to be fine-tuned)

fig = plt.figure(2)

ax1 = plt.subplot(121)
ax1.plot(f)
ax1.set_title('Very Long Title 1', fontsize=20)

ax2 = plt.subplot(122)
ax2.plot(g)
ax2.set_title('Very Long Title 2', fontsize=20)

# fig.suptitle('Long Suptitle', fontsize=24)
# Instead, do a hack by annotating the first axes with the desired 
# string and set the positioning to 'figure fraction'.
fig.get_axes()[0].annotate('Long Suptitle', (0.5, 0.95), 
                            xycoords='figure fraction', ha='center', 
                            fontsize=24
                            )
plt.show()

The result:

[Using Python 2.7.3 (64-bit) and matplotlib 1.2.0]


回答 3

一种替代且易于使用的解决方案是在调用suptitle时使用y参数来调整图中字幕文本的坐标(请参阅docs):

import numpy as np
import matplotlib.pyplot as plt

f = np.random.random(100)
g = np.random.random(100)
fig = plt.figure()
fig.suptitle('Long Suptitle', y=1.05, fontsize=24)
plt.subplot(121)
plt.plot(f)
plt.title('Very Long Title 1', fontsize=20)
plt.subplot(122)
plt.plot(g)
plt.title('Very Long Title 2', fontsize=20)
plt.show()

An alternative and simple to use solution is to adjust the coordinates of the suptitle text in the figure using the y argument in the call of suptitle (see the docs):

import numpy as np
import matplotlib.pyplot as plt

f = np.random.random(100)
g = np.random.random(100)
fig = plt.figure()
fig.suptitle('Long Suptitle', y=1.05, fontsize=24)
plt.subplot(121)
plt.plot(f)
plt.title('Very Long Title 1', fontsize=20)
plt.subplot(122)
plt.plot(g)
plt.title('Very Long Title 2', fontsize=20)
plt.show()

回答 4

紧密的布局不适用于字幕,但constrained_layout可以。查看此问题使用matplotlib中的许多子图来提高子图大小/间距

我发现立即添加子图看起来更好,即

fig, axs = plt.subplots(rows, cols, constrained_layout=True)

# then iterating over the axes to fill in the plots

但是也可以在创建图形时添加它:

fig = plt.figure(constrained_layout=True)

ax1 = fig.add_subplot(cols, rows, 1)
# etc

注意:为了使子图更加紧密,我还使用了

fig.subplots_adjust(wspace=0.05)

和constrained_layout不适用于此:(

Tight layout doesn’t work with suptitle, but constrained_layout does. See this question Improve subplot size/spacing with many subplots in matplotlib

I found adding the subplots at once looked better, i.e.

fig, axs = plt.subplots(rows, cols, constrained_layout=True)

# then iterating over the axes to fill in the plots

But it can also be added at the point the figure is created:

fig = plt.figure(constrained_layout=True)

ax1 = fig.add_subplot(cols, rows, 1)
# etc

Note: To make my subplots closer together, I was also using

fig.subplots_adjust(wspace=0.05)

and constrained_layout doesn’t work with this :(


回答 5

我一直在努力与matplotlib修剪方法,所以我现在只是做了功能通过做这个bash调用ImageMagickmogrify命令,它运作良好,并得到所有多余的空白关图的边缘。这要求您正在使用UNIX / Linux,正在使用bashShell,并且已经ImageMagick安装。

拨打电话后,只需对此savefig()拨打电话即可。

def autocrop_img(filename):
    '''Call ImageMagick mogrify from bash to autocrop image'''
    import subprocess
    import os

    cwd, img_name = os.path.split(filename)

    bashcmd = 'mogrify -trim %s' % img_name
    process = subprocess.Popen(bashcmd.split(), stdout=subprocess.PIPE, cwd=cwd)

I have struggled with the matplotlib trimming methods, so I’ve now just made a function to do this via a bash call to ImageMagick‘s mogrify command, which works well and gets all extra white space off the figure’s edge. This requires that you are using UNIX/Linux, are using the bash shell, and have ImageMagick installed.

Just throw a call to this after your savefig() call.

def autocrop_img(filename):
    '''Call ImageMagick mogrify from bash to autocrop image'''
    import subprocess
    import os

    cwd, img_name = os.path.split(filename)

    bashcmd = 'mogrify -trim %s' % img_name
    process = subprocess.Popen(bashcmd.split(), stdout=subprocess.PIPE, cwd=cwd)

回答 6

正如其他人所提到的,默认情况下,紧凑的布局不考虑字幕。但是,我发现可以使用该bbox_extra_artists参数来传递字幕作为应该考虑的边界框:

st = fig.suptitle("My Super Title")
plt.savefig("figure.png", bbox_extra_artists=[st], bbox_inches='tight')

这迫使紧密的布局计算要考虑suptitle在内,并且看起来就像您期望的那样。

As mentioned by others, by default the tight layout does not take suptitle into account. However, I have found it is possible to use the bbox_extra_artists argument to pass in the suptitle as a bounding box that should be taken into account:

st = fig.suptitle("My Super Title")
plt.savefig("figure.png", bbox_extra_artists=[st], bbox_inches='tight')

This forces the tight layout calculation to take the suptitle into account, and it looks as you would expect.


回答 7

当我使用tight_layout非常大的网格图(超过200个子图)并在jupyter笔记本中进行渲染时,出现了类似的问题。我制定了一个快速解决方案,始终将您suptitle放在顶部子图上方一定距离处:

import matplotlib.pyplot as plt

n_rows = 50
n_col = 4
fig, axs = plt.subplots(n_rows, n_cols)

#make plots ...

# define y position of suptitle to be ~20% of a row above the top row
y_title_pos = axs[0][0].get_position().get_points()[1][1]+(1/n_rows)*0.2
fig.suptitle('My Sup Title', y=y_title_pos)

对于可变大小的子图,您仍然可以使用此方法获得最顶层子图的顶部,然后手动定义一个附加量以添加到字幕中。

I had a similar issue that cropped up when using tight_layout for a very large grid of plots (more than 200 subplots) and rendering in a jupyter notebook. I made a quick solution that always places your suptitle at a certain distance above your top subplot:

import matplotlib.pyplot as plt

n_rows = 50
n_col = 4
fig, axs = plt.subplots(n_rows, n_cols)

#make plots ...

# define y position of suptitle to be ~20% of a row above the top row
y_title_pos = axs[0][0].get_position().get_points()[1][1]+(1/n_rows)*0.2
fig.suptitle('My Sup Title', y=y_title_pos)

For variably-sized subplots, you can still use this method to get the top of the topmost subplot, then manually define an additional amount to add to the suptitle.


回答 8

唯一对我有用的是修改对suptitle的调用:

fig.suptitle("title", y=.995)

The only thing that worked for me was modifying the call to suptitle:

fig.suptitle("title", y=.995)

如何在Python中将RGB图像转换为灰度图像?

问题:如何在Python中将RGB图像转换为灰度图像?

我试图用来matplotlib读取RGB图像并将其转换为灰度。

在matlab中,我使用以下代码:

img = rgb2gray(imread('image.png'));

matplotlib教程中,他们没有介绍它。他们只是读了图像

import matplotlib.image as mpimg
img = mpimg.imread('image.png')

然后他们将数组切成薄片,但这与从我所了解的将RGB转换为灰度不同。

lum_img = img[:,:,0]

我发现很难相信numpy或matplotlib没有将rgb转换为灰色的内置函数。这不是图像处理中的常见操作吗?

我写了一个非常简单的函数,可以imread在5分钟内使用导入的图像。这是非常低效的,但这就是为什么我希望内置一个专业的实现。

Sebastian改进了我的功能,但我仍然希望找到内置的功能。

Matlab(NTSC / PAL)的实现:

import numpy as np

def rgb2gray(rgb):

    r, g, b = rgb[:,:,0], rgb[:,:,1], rgb[:,:,2]
    gray = 0.2989 * r + 0.5870 * g + 0.1140 * b

    return gray

I’m trying to use matplotlib to read in an RGB image and convert it to grayscale.

In matlab I use this:

img = rgb2gray(imread('image.png'));

In the matplotlib tutorial they don’t cover it. They just read in the image

import matplotlib.image as mpimg
img = mpimg.imread('image.png')

and then they slice the array, but that’s not the same thing as converting RGB to grayscale from what I understand.

lum_img = img[:,:,0]

I find it hard to believe that numpy or matplotlib doesn’t have a built-in function to convert from rgb to gray. Isn’t this a common operation in image processing?

I wrote a very simple function that works with the image imported using imread in 5 minutes. It’s horribly inefficient, but that’s why I was hoping for a professional implementation built-in.

Sebastian has improved my function, but I’m still hoping to find the built-in one.

matlab’s (NTSC/PAL) implementation:

import numpy as np

def rgb2gray(rgb):

    r, g, b = rgb[:,:,0], rgb[:,:,1], rgb[:,:,2]
    gray = 0.2989 * r + 0.5870 * g + 0.1140 * b

    return gray

回答 0

Pillow怎么做:

from PIL import Image
img = Image.open('image.png').convert('LA')
img.save('greyscale.png')

使用matplotlib和公式

Y' = 0.2989 R + 0.5870 G + 0.1140 B 

你可以做:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg

def rgb2gray(rgb):
    return np.dot(rgb[...,:3], [0.2989, 0.5870, 0.1140])

img = mpimg.imread('image.png')     
gray = rgb2gray(img)    
plt.imshow(gray, cmap=plt.get_cmap('gray'), vmin=0, vmax=1)
plt.show()

How about doing it with Pillow:

from PIL import Image
img = Image.open('image.png').convert('LA')
img.save('greyscale.png')

Using matplotlib and the formula

Y' = 0.2989 R + 0.5870 G + 0.1140 B 

you could do:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg

def rgb2gray(rgb):
    return np.dot(rgb[...,:3], [0.2989, 0.5870, 0.1140])

img = mpimg.imread('image.png')     
gray = rgb2gray(img)    
plt.imshow(gray, cmap=plt.get_cmap('gray'), vmin=0, vmax=1)
plt.show()

回答 1

您还可以使用scikit-image,它提供了一些功能来转换图像ndarray,例如rgb2gray

from skimage import color
from skimage import io

img = color.rgb2gray(io.imread('image.png'))

注意:此转换中使用的重量已针对当代CRT荧光粉进行了校准:Y = 0.2125 R + 0.7154 G + 0.0721 B

或者,您可以通过以下方式读取灰度图像:

from skimage import io
img = io.imread('image.png', as_gray=True)

You can also use scikit-image, which provides some functions to convert an image in ndarray, like rgb2gray.

from skimage import color
from skimage import io

img = color.rgb2gray(io.imread('image.png'))

Notes: The weights used in this conversion are calibrated for contemporary CRT phosphors: Y = 0.2125 R + 0.7154 G + 0.0721 B

Alternatively, you can read image in grayscale by:

from skimage import io
img = io.imread('image.png', as_gray=True)

回答 2

在Ubuntu 16.04 LTS(配备SSD的Xeon E5 2670)上使用Python 3.5运行1000个RGBA PNG图像(224 x 256像素)时,对其中三种建议的方法进行了速度测试。

平均运行时间

pil : 1.037秒

scipy: 1.040秒

sk : 2.120秒

PIL和SciPy给出了相同的numpy数组(范围从0到255)。SkImage给出从0到1的数组。此外,颜色的转换略有不同,请参阅CUB-200数据集的示例

SkImage:

PIL :

SciPy :

Original:

Diff :

  1. 性能

    run_times = dict(sk=list(), pil=list(), scipy=list())
    for t in range(100):
        start_time = time.time()
        for i in range(1000):
            z = random.choice(filenames_png)
            img = skimage.color.rgb2gray(skimage.io.imread(z))
        run_times['sk'].append(time.time() - start_time)

    start_time = time.time()
    for i in range(1000):
        z = random.choice(filenames_png)
        img = np.array(Image.open(z).convert('L'))
    run_times['pil'].append(time.time() - start_time)
    
    start_time = time.time()
    for i in range(1000):
        z = random.choice(filenames_png)
        img = scipy.ndimage.imread(z, mode='L')
    run_times['scipy'].append(time.time() - start_time)
    

    for k, v in run_times.items(): print('{:5}: {:0.3f} seconds'.format(k, sum(v) / len(v)))

  2. 输出量
    z = 'Cardinal_0007_3025810472.jpg'
    img1 = skimage.color.rgb2gray(skimage.io.imread(z)) * 255
    IPython.display.display(PIL.Image.fromarray(img1).convert('RGB'))
    img2 = np.array(Image.open(z).convert('L'))
    IPython.display.display(PIL.Image.fromarray(img2))
    img3 = scipy.ndimage.imread(z, mode='L')
    IPython.display.display(PIL.Image.fromarray(img3))
  3. 比较方式
    img_diff = np.ndarray(shape=img1.shape, dtype='float32')
    img_diff.fill(128)
    img_diff += (img1 - img3)
    img_diff -= img_diff.min()
    img_diff *= (255/img_diff.max())
    IPython.display.display(PIL.Image.fromarray(img_diff).convert('RGB'))
  4. 进口货
    import skimage.color
    import skimage.io
    import random
    import time
    from PIL import Image
    import numpy as np
    import scipy.ndimage
    import IPython.display
  5. 版本号
    skimage.version
    0.13.0
    scipy.version
    0.19.1
    np.version
    1.13.1

Three of the suggested methods were tested for speed with 1000 RGBA PNG images (224 x 256 pixels) running with Python 3.5 on Ubuntu 16.04 LTS (Xeon E5 2670 with SSD).

Average run times

pil : 1.037 seconds

scipy: 1.040 seconds

sk : 2.120 seconds

PIL and SciPy gave identical numpy arrays (ranging from 0 to 255). SkImage gives arrays from 0 to 1. In addition the colors are converted slightly different, see the example from the CUB-200 dataset.

SkImage:

PIL :

SciPy :

Original:

Diff :

Code

  1. Performance

    run_times = dict(sk=list(), pil=list(), scipy=list())
    for t in range(100):
        start_time = time.time()
        for i in range(1000):
            z = random.choice(filenames_png)
            img = skimage.color.rgb2gray(skimage.io.imread(z))
        run_times['sk'].append(time.time() - start_time)
    
    
    start_time = time.time()
    for i in range(1000):
        z = random.choice(filenames_png)
        img = np.array(Image.open(z).convert('L'))
    run_times['pil'].append(time.time() - start_time)
    
    start_time = time.time()
    for i in range(1000):
        z = random.choice(filenames_png)
        img = scipy.ndimage.imread(z, mode='L')
    run_times['scipy'].append(time.time() - start_time)
    

    for k, v in run_times.items(): print('{:5}: {:0.3f} seconds'.format(k, sum(v) / len(v)))

  2. Output
    z = 'Cardinal_0007_3025810472.jpg'
    img1 = skimage.color.rgb2gray(skimage.io.imread(z)) * 255
    IPython.display.display(PIL.Image.fromarray(img1).convert('RGB'))
    img2 = np.array(Image.open(z).convert('L'))
    IPython.display.display(PIL.Image.fromarray(img2))
    img3 = scipy.ndimage.imread(z, mode='L')
    IPython.display.display(PIL.Image.fromarray(img3))
    
  3. Comparison
    img_diff = np.ndarray(shape=img1.shape, dtype='float32')
    img_diff.fill(128)
    img_diff += (img1 - img3)
    img_diff -= img_diff.min()
    img_diff *= (255/img_diff.max())
    IPython.display.display(PIL.Image.fromarray(img_diff).convert('RGB'))
    
  4. Imports
    import skimage.color
    import skimage.io
    import random
    import time
    from PIL import Image
    import numpy as np
    import scipy.ndimage
    import IPython.display
    
  5. Versions
    skimage.version
    0.13.0
    scipy.version
    0.19.1
    np.version
    1.13.1
    

回答 3

您始终可以从一开始就使用imreadOpenCV 从灰度读取图像文件:

img = cv2.imread('messi5.jpg', 0)

此外,如果要将图像读取为RGB,请进行一些处理,然后转换为可以cvtcolor在OpenCV中使用的灰度:

gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

You can always read the image file as grayscale right from the beginning using imread from OpenCV:

img = cv2.imread('messi5.jpg', 0)

Furthermore, in case you want to read the image as RGB, do some processing and then convert to Gray Scale you could use cvtcolor from OpenCV:

gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

回答 4

最快和最新的方法是使用Pillow,通过pip install Pillow

代码如下:

from PIL import Image
img = Image.open('input_file.jpg').convert('L')
img.save('output_file.jpg')

The fastest and current way is to use Pillow, installed via pip install Pillow.

The code is then:

from PIL import Image
img = Image.open('input_file.jpg').convert('L')
img.save('output_file.jpg')

回答 5

该教程之所以作弊是因为它是以RGB编码的灰度图像开始的,因此他们只是将单个颜色通道切片并将其视为灰度。您需要执行的基本步骤是,将RGB颜色空间转换为使用近似luma / chroma模型(例如YUV / YIQ或HSL / HSV)进行编码的颜色空间,然后将类似luma的通道切成薄片并将其用作您的灰度图像。 matplotlib似乎没有提供转换为YUV / YIQ的机制,但是它确实允许您转换为HSV。

尝试使用,matplotlib.colors.rgb_to_hsv(img)然后从阵列中为灰度切片最后一个值(V)。它与亮度值并不完全相同,但这意味着您可以在其中完成所有操作matplotlib

背景:

或者,您可以使用PIL或内置colorsys.rgb_to_yiq()函数转换为具有真实亮度值的色彩空间。您也可以全力以赴,推出自己的仅亮度转换器,尽管这可能会过分杀了。

The tutorial is cheating because it is starting with a greyscale image encoded in RGB, so they are just slicing a single color channel and treating it as greyscale. The basic steps you need to do are to transform from the RGB colorspace to a colorspace that encodes with something approximating the luma/chroma model, such as YUV/YIQ or HSL/HSV, then slice off the luma-like channel and use that as your greyscale image. matplotlib does not appear to provide a mechanism to convert to YUV/YIQ, but it does let you convert to HSV.

Try using matplotlib.colors.rgb_to_hsv(img) then slicing the last value (V) from the array for your grayscale. It’s not quite the same as a luma value, but it means you can do it all in matplotlib.

Background:

Alternatively, you could use PIL or the builtin colorsys.rgb_to_yiq() to convert to a colorspace with a true luma value. You could also go all in and roll your own luma-only converter, though that’s probably overkill.


回答 6

使用这个公式

Y' = 0.299 R + 0.587 G + 0.114 B 

我们可以做的

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

pic = imageio.imread('(image)')
gray = lambda rgb : np.dot(rgb[... , :3] , [0.299 , 0.587, 0.114]) 
gray = gray(pic)  
plt.imshow(gray, cmap = plt.get_cmap(name = 'gray'))

但是,那 GIMP将颜色转换为灰度图像软件有三种算法可以完成任务。

Using this formula

Y' = 0.299 R + 0.587 G + 0.114 B 

We can do

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

pic = imageio.imread('(image)')
gray = lambda rgb : np.dot(rgb[... , :3] , [0.299 , 0.587, 0.114]) 
gray = gray(pic)  
plt.imshow(gray, cmap = plt.get_cmap(name = 'gray'))

However, the GIMP converting color to grayscale image software has three algorithms to do the task.


回答 7

如果您已经在使用NumPy / SciPy,则也可以使用

scipy.ndimage.imread(file_name, mode='L')

If you’re using NumPy/SciPy already you may as well use:

scipy.ndimage.imread(file_name, mode='L')


回答 8

你可以做:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg

def rgb_to_gray(img):
        grayImage = np.zeros(img.shape)
        R = np.array(img[:, :, 0])
        G = np.array(img[:, :, 1])
        B = np.array(img[:, :, 2])

        R = (R *.299)
        G = (G *.587)
        B = (B *.114)

        Avg = (R+G+B)
        grayImage = img

        for i in range(3):
           grayImage[:,:,i] = Avg

        return grayImage       

image = mpimg.imread("your_image.png")   
grayImage = rgb_to_gray(image)  
plt.imshow(grayImage)
plt.show()

you could do:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg

def rgb_to_gray(img):
        grayImage = np.zeros(img.shape)
        R = np.array(img[:, :, 0])
        G = np.array(img[:, :, 1])
        B = np.array(img[:, :, 2])

        R = (R *.299)
        G = (G *.587)
        B = (B *.114)

        Avg = (R+G+B)
        grayImage = img

        for i in range(3):
           grayImage[:,:,i] = Avg

        return grayImage       

image = mpimg.imread("your_image.png")   
grayImage = rgb_to_gray(image)  
plt.imshow(grayImage)
plt.show()

回答 9

使用img.Convert(),支持“ L”,“ RGB”和“ CMYK”。模式

import numpy as np
from PIL import Image

img = Image.open("IMG/center_2018_02_03_00_34_32_784.jpg")
img.convert('L')

print np.array(img)

输出:

[[135 123 134 ...,  30   3  14]
 [137 130 137 ...,   9  20  13]
 [170 177 183 ...,  14  10 250]
 ..., 
 [112  99  91 ...,  90  88  80]
 [ 95 103 111 ..., 102  85 103]
 [112  96  86 ..., 182 148 114]]

Use img.Convert(), supports “L”, “RGB” and “CMYK.” mode

import numpy as np
from PIL import Image

img = Image.open("IMG/center_2018_02_03_00_34_32_784.jpg")
img.convert('L')

print np.array(img)

Output:

[[135 123 134 ...,  30   3  14]
 [137 130 137 ...,   9  20  13]
 [170 177 183 ...,  14  10 250]
 ..., 
 [112  99  91 ...,  90  88  80]
 [ 95 103 111 ..., 102  85 103]
 [112  96  86 ..., 182 148 114]]

回答 10

我通过Google遇到了这个问题,寻找一种将已加载的图像转换为灰度的方法。

这是使用SciPy的一种方法:

import scipy.misc
import scipy.ndimage

# Load an example image
# Use scipy.ndimage.imread(file_name, mode='L') if you have your own
img = scipy.misc.face()

# Convert the image
R = img[:, :, 0]
G = img[:, :, 1]
B = img[:, :, 2]
img_gray = R * 299. / 1000 + G * 587. / 1000 + B * 114. / 1000

# Show the image
scipy.misc.imshow(img_gray)

I came to this question via Google, searching for a way to convert an already loaded image to grayscale.

Here is a way to do it with SciPy:

import scipy.misc
import scipy.ndimage

# Load an example image
# Use scipy.ndimage.imread(file_name, mode='L') if you have your own
img = scipy.misc.face()

# Convert the image
R = img[:, :, 0]
G = img[:, :, 1]
B = img[:, :, 2]
img_gray = R * 299. / 1000 + G * 587. / 1000 + B * 114. / 1000

# Show the image
scipy.misc.imshow(img_gray)

回答 11

image=myCamera.getImage().crop(xx,xx,xx,xx).scale(xx,xx).greyscale()

您可以greyscale()直接用于转换。

image=myCamera.getImage().crop(xx,xx,xx,xx).scale(xx,xx).greyscale()

You can use greyscale() directly for the transformation.


Seaborn地块未显示

问题:Seaborn地块未显示

我确定我忘记了一些非常简单的内容,但是我无法获得某些与Seaborn合作的计划。

如果我做:

import seaborn as sns

然后,我照常使用matplotlib创建的任何图都将获得Seaborn样式(背景为灰色网格)。

但是,如果我尝试执行以下示例之一,例如:

In [1]: import seaborn as sns

In [2]: sns.set()

In [3]: df = sns.load_dataset('iris')

In [4]: sns.pairplot(df, hue='species', size=2.5)
Out[4]: <seaborn.axisgrid.PairGrid at 0x3e59150>

pairplot函数返回一个PairGrid对象,但该图未显示。

我有些困惑,因为matplotlib似乎可以正常运行,并且Seaborn样式已应用于其他matplotlib图,但是Seaborn函数似乎没有任何作用。有人知道可能是什么问题吗?

I’m sure I’m forgetting something very simple, but I cannot get certain plots to work with Seaborn.

If I do:

import seaborn as sns

Then any plots that I create as usual with matplotlib get the Seaborn styling (with the grey grid in the background).

However, if I try to do one of the examples, such as:

In [1]: import seaborn as sns

In [2]: sns.set()

In [3]: df = sns.load_dataset('iris')

In [4]: sns.pairplot(df, hue='species', size=2.5)
Out[4]: <seaborn.axisgrid.PairGrid at 0x3e59150>

The pairplot function returns a PairGrid object, but the plot doesn’t show up.

I’m a little confused because matplotlib seems to be functioning properly, and the Seaborn styles are applied to other matplotlib plots, but the Seaborn functions don’t seem to do anything. Does anybody have any idea what might be the problem?


回答 0

使用seaborn创建的图需要像普通的matplotlib图一样显示。可以使用

plt.show()

来自matplotlib的功能。

最初,我发布了使用seaborn(sns.plt.show())中已导入的matplotlib对象的解决方案,但是这被认为是不好的做法。因此,只需直接导入matplotlib.pyplot模块并使用

import matplotlib.pyplot as plt
plt.show()

如果使用IPython笔记本,则可以调用内联后端以消除在每次绘制后调用show的必要性。各自的魔力是

%matplotlib inline

Plots created using seaborn need to be displayed like ordinary matplotlib plots. This can be done using the

plt.show()

function from matplotlib.

Originally I posted the solution to use the already imported matplotlib object from seaborn (sns.plt.show()) however this is considered to be a bad practice. Therefore, simply directly import the matplotlib.pyplot module and show your plots with

import matplotlib.pyplot as plt
plt.show()

If the IPython notebook is used the inline backend can be invoked to remove the necessity of calling show after each plot. The respective magic is

%matplotlib inline

回答 1

我经常问这个问题,而且总是花些时间才能找到要搜索的内容:

import seaborn as sns
import matplotlib.pyplot as plt

plt.show()  # <--- This is what you are looking for

请注意:在Python 2中,您也可以使用sns.plt.show(),但在Python 3中则不能。

完整的例子

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""Visualize C_0.99 for all languages except the 10 with most characters."""

import seaborn as sns
import matplotlib.pyplot as plt

l = [41, 44, 46, 46, 47, 47, 48, 48, 49, 51, 52, 53, 53, 53, 53, 55, 55, 55,
     55, 56, 56, 56, 56, 56, 56, 57, 57, 57, 57, 57, 57, 57, 57, 58, 58, 58,
     58, 59, 59, 59, 59, 59, 59, 59, 59, 60, 60, 60, 60, 60, 60, 60, 60, 61,
     61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 62, 62, 62, 62, 62, 62, 62, 62,
     62, 63, 63, 63, 63, 63, 63, 63, 63, 63, 64, 64, 64, 64, 64, 64, 64, 65,
     65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 66, 66, 66, 66, 66, 66, 66,
     67, 67, 67, 67, 67, 67, 67, 67, 68, 68, 68, 68, 68, 69, 69, 69, 70, 70,
     70, 70, 71, 71, 71, 71, 71, 72, 72, 72, 72, 73, 73, 73, 73, 73, 73, 73,
     74, 74, 74, 74, 74, 75, 75, 75, 76, 77, 77, 78, 78, 79, 79, 79, 79, 80,
     80, 80, 80, 81, 81, 81, 81, 83, 84, 84, 85, 86, 86, 86, 86, 87, 87, 87,
     87, 87, 88, 90, 90, 90, 90, 90, 90, 91, 91, 91, 91, 91, 91, 91, 91, 92,
     92, 93, 93, 93, 94, 95, 95, 96, 98, 98, 99, 100, 102, 104, 105, 107, 108,
     109, 110, 110, 113, 113, 115, 116, 118, 119, 121]

sns.distplot(l, kde=True, rug=False)

plt.show()

I come to this question quite regularly and it always takes me a while to find what I search:

import seaborn as sns
import matplotlib.pyplot as plt

plt.show()  # <--- This is what you are looking for

Please note: In Python 2, you can also use sns.plt.show(), but not in Python 3.

Complete Example

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""Visualize C_0.99 for all languages except the 10 with most characters."""

import seaborn as sns
import matplotlib.pyplot as plt

l = [41, 44, 46, 46, 47, 47, 48, 48, 49, 51, 52, 53, 53, 53, 53, 55, 55, 55,
     55, 56, 56, 56, 56, 56, 56, 57, 57, 57, 57, 57, 57, 57, 57, 58, 58, 58,
     58, 59, 59, 59, 59, 59, 59, 59, 59, 60, 60, 60, 60, 60, 60, 60, 60, 61,
     61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 62, 62, 62, 62, 62, 62, 62, 62,
     62, 63, 63, 63, 63, 63, 63, 63, 63, 63, 64, 64, 64, 64, 64, 64, 64, 65,
     65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 66, 66, 66, 66, 66, 66, 66,
     67, 67, 67, 67, 67, 67, 67, 67, 68, 68, 68, 68, 68, 69, 69, 69, 70, 70,
     70, 70, 71, 71, 71, 71, 71, 72, 72, 72, 72, 73, 73, 73, 73, 73, 73, 73,
     74, 74, 74, 74, 74, 75, 75, 75, 76, 77, 77, 78, 78, 79, 79, 79, 79, 80,
     80, 80, 80, 81, 81, 81, 81, 83, 84, 84, 85, 86, 86, 86, 86, 87, 87, 87,
     87, 87, 88, 90, 90, 90, 90, 90, 90, 91, 91, 91, 91, 91, 91, 91, 91, 92,
     92, 93, 93, 93, 94, 95, 95, 96, 98, 98, 99, 100, 102, 104, 105, 107, 108,
     109, 110, 110, 113, 113, 115, 116, 118, 119, 121]

sns.distplot(l, kde=True, rug=False)

plt.show()

Gives


回答 2

为了避免混淆(评论中似乎有一些)。假设您使用Jupyter:

%matplotlib inline>显示的曲线INSIDE笔记本

sns.plt.show()> 在笔记本的外侧显示图

%matplotlib inline从某种意义上讲,即使绘图被调用,绘图也会显示笔记本中,它将覆盖sns.plt.show()sns.plt.show()

是的,很容易将行包含到您的配置中:

在IPython Notebook中内联自动运行%matplotlib

但是在实际代码中将其与导入保持在一起似乎是一个更好的约定。

To avoid confusion (as there seems to be some in the comments). Assuming you are on Jupyter:

%matplotlib inline > displays the plots INSIDE the notebook

sns.plt.show() > displays the plots OUTSIDE of the notebook

%matplotlib inline will OVERRIDE sns.plt.show() in the sense that plots will be shown IN the notebook even when sns.plt.show() is called.

And yes, it is easy to include the line in to your config:

Automatically run %matplotlib inline in IPython Notebook

But it seems a better convention to keep it together with imports in the actual code.


回答 3

这对我有用

import matplotlib.pyplot as plt
import seaborn as sns
.
.
.
plt.show(sns)

This worked for me

import matplotlib.pyplot as plt
import seaborn as sns
.
.
.
plt.show(sns)

回答 4

我的建议是给

plt.figure()并给出一些sns图。例如

sns.distplot(data)

尽管看起来它不会显示任何图,但是当您最大化图形时,您将能够看到该图。

My advice is just to give a

plt.figure() and give some sns plot. For example

sns.distplot(data).

Though it will look it doesnt show any plot, When you maximise the figure, you will be able to see the plot.


回答 5

如果您在IPython控制台(不能使用%matplotlib inline)而不是Jupyter笔记本中进行绘制,并且不想plt.show()重复运行,则可以使用以下命令启动IPython控制台ipython --pylab

$ ipython --pylab     
Python 3.6.6 |Anaconda custom (64-bit)| (default, Jun 28 2018, 17:14:51) 
Type 'copyright', 'credits' or 'license' for more information
IPython 7.0.1 -- An enhanced Interactive Python. Type '?' for help.
Using matplotlib backend: Qt5Agg

In [1]: import seaborn as sns

In [2]: tips = sns.load_dataset("tips")

In [3]: sns.relplot(x="total_bill", y="tip", data=tips) # you can see the plot now

If you plot in IPython console (where you can’t use %matplotlib inline) instead of Jupyter notebook, and don’t want to run plt.show() repeatedly, you can start IPython console with ipython --pylab:

$ ipython --pylab     
Python 3.6.6 |Anaconda custom (64-bit)| (default, Jun 28 2018, 17:14:51) 
Type 'copyright', 'credits' or 'license' for more information
IPython 7.0.1 -- An enhanced Interactive Python. Type '?' for help.
Using matplotlib backend: Qt5Agg

In [1]: import seaborn as sns

In [2]: tips = sns.load_dataset("tips")

In [3]: sns.relplot(x="total_bill", y="tip", data=tips) # you can see the plot now

回答 6

从您的代码片段的风格可以看出,我想您使用的是IPython而不是Jupyter Notebook。

在GitHub上的此期中,IPython的一名成员在2016年明确指出,图表的显示仅在“仅在Jupyter内核中有效”时才起作用。因此, %matplotlib inline将无法正常工作。

我只是遇到了同样的问题,建议您使用Jupyter Notebook进行可视化。

To tell from the style of your code snippet, I suppose you were using IPython rather than Jupyter Notebook.

In this issue on GitHub, it was made clear by a member of IPython in 2016 that the display of charts would only work when “only work when it’s a Jupyter kernel”. Thus, the %matplotlib inline would not work.

I was just having the same issue and suggest you use Jupyter Notebook for the visualization.


如何在单个图形中为不同的图获得不同的彩色线条?

问题:如何在单个图形中为不同的图获得不同的彩色线条?

matplotlib用来创建情节。我必须用不同的颜色来标识每个图,这些颜色应该由Python自动生成。

能否请您给我一种在同一图形中为不同图放置不同颜色的方法?

I am using matplotlib to create the plots. I have to identify each plot with a different color which should be automatically generated by Python.

Can you please give me a method to put different colors for different plots in the same figure?


回答 0

Matplotlib默认情况下会执行此操作。

例如:

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(10)

plt.plot(x, x)
plt.plot(x, 2 * x)
plt.plot(x, 3 * x)
plt.plot(x, 4 * x)
plt.show()

而且,您可能已经知道,可以轻松添加图例:

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(10)

plt.plot(x, x)
plt.plot(x, 2 * x)
plt.plot(x, 3 * x)
plt.plot(x, 4 * x)

plt.legend(['y = x', 'y = 2x', 'y = 3x', 'y = 4x'], loc='upper left')

plt.show()

如果要控制将循环显示的颜色:

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(10)

plt.gca().set_color_cycle(['red', 'green', 'blue', 'yellow'])

plt.plot(x, x)
plt.plot(x, 2 * x)
plt.plot(x, 3 * x)
plt.plot(x, 4 * x)

plt.legend(['y = x', 'y = 2x', 'y = 3x', 'y = 4x'], loc='upper left')

plt.show()

如果您不熟悉matplotlib,那么本教程是一个不错的起点

编辑:

首先,如果要在一个图形上绘制很多东西(> 5),则可以:

  1. 将它们放在不同的图上(考虑在一个图形上使用几个子图),或者
  2. 使用颜色以外的其他东西(即标记样式或线条粗细)来区分它们。

否则,您将面临一个非常混乱的情节!对要阅读您正在做的事情的人要好,不要试图将15种不同的东西塞成一个数字!

除此之外,许多人都存在不同程度的色盲现象,对于更多人来说,很难分辨出许多细微不同的颜色,这超出了您的想象。

话虽如此,如果您真的想在一条轴上放置20条线并使用20种相对不同的颜色,则可以采用以下一种方法:

import matplotlib.pyplot as plt
import numpy as np

num_plots = 20

# Have a look at the colormaps here and decide which one you'd like:
# http://matplotlib.org/1.2.1/examples/pylab_examples/show_colormaps.html
colormap = plt.cm.gist_ncar
plt.gca().set_prop_cycle(plt.cycler('color', plt.cm.jet(np.linspace(0, 1, num_plots))))

# Plot several different functions...
x = np.arange(10)
labels = []
for i in range(1, num_plots + 1):
    plt.plot(x, i * x + 5 * i)
    labels.append(r'$y = %ix + %i$' % (i, 5*i))

# I'm basically just demonstrating several different legend options here...
plt.legend(labels, ncol=4, loc='upper center', 
           bbox_to_anchor=[0.5, 1.1], 
           columnspacing=1.0, labelspacing=0.0,
           handletextpad=0.0, handlelength=1.5,
           fancybox=True, shadow=True)

plt.show()

Matplotlib does this by default.

E.g.:

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(10)

plt.plot(x, x)
plt.plot(x, 2 * x)
plt.plot(x, 3 * x)
plt.plot(x, 4 * x)
plt.show()

And, as you may already know, you can easily add a legend:

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(10)

plt.plot(x, x)
plt.plot(x, 2 * x)
plt.plot(x, 3 * x)
plt.plot(x, 4 * x)

plt.legend(['y = x', 'y = 2x', 'y = 3x', 'y = 4x'], loc='upper left')

plt.show()

If you want to control the colors that will be cycled through:

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(10)

plt.gca().set_color_cycle(['red', 'green', 'blue', 'yellow'])

plt.plot(x, x)
plt.plot(x, 2 * x)
plt.plot(x, 3 * x)
plt.plot(x, 4 * x)

plt.legend(['y = x', 'y = 2x', 'y = 3x', 'y = 4x'], loc='upper left')

plt.show()

If you’re unfamiliar with matplotlib, the tutorial is a good place to start.

Edit:

First off, if you have a lot (>5) of things you want to plot on one figure, either:

  1. Put them on different plots (consider using a few subplots on one figure), or
  2. Use something other than color (i.e. marker styles or line thickness) to distinguish between them.

Otherwise, you’re going to wind up with a very messy plot! Be nice to who ever is going to read whatever you’re doing and don’t try to cram 15 different things onto one figure!!

Beyond that, many people are colorblind to varying degrees, and distinguishing between numerous subtly different colors is difficult for more people than you may realize.

That having been said, if you really want to put 20 lines on one axis with 20 relatively distinct colors, here’s one way to do it:

import matplotlib.pyplot as plt
import numpy as np

num_plots = 20

# Have a look at the colormaps here and decide which one you'd like:
# http://matplotlib.org/1.2.1/examples/pylab_examples/show_colormaps.html
colormap = plt.cm.gist_ncar
plt.gca().set_prop_cycle(plt.cycler('color', plt.cm.jet(np.linspace(0, 1, num_plots))))

# Plot several different functions...
x = np.arange(10)
labels = []
for i in range(1, num_plots + 1):
    plt.plot(x, i * x + 5 * i)
    labels.append(r'$y = %ix + %i$' % (i, 5*i))

# I'm basically just demonstrating several different legend options here...
plt.legend(labels, ncol=4, loc='upper center', 
           bbox_to_anchor=[0.5, 1.1], 
           columnspacing=1.0, labelspacing=0.0,
           handletextpad=0.0, handlelength=1.5,
           fancybox=True, shadow=True)

plt.show()


回答 1

稍后设置

如果您不知道要绘制的图的数量,则可以在绘制颜色后直接使用来更改颜色,从而直接从图中检索编号.lines,我可以使用以下解决方案:

一些随机数据

import matplotlib.pyplot as plt
import numpy as np

fig1 = plt.figure()
ax1 = fig1.add_subplot(111)


for i in range(1,15):
    ax1.plot(np.array([1,5])*i,label=i)

您需要的一段代码:

colormap = plt.cm.gist_ncar #nipy_spectral, Set1,Paired   
colors = [colormap(i) for i in np.linspace(0, 1,len(ax1.lines))]
for i,j in enumerate(ax1.lines):
    j.set_color(colors[i])
  

ax1.legend(loc=2)

结果如下:

Setting them later

If you don’t know the number of the plots you are going to plot you can change the colours once you have plotted them retrieving the number directly from the plot using .lines, I use this solution:

Some random data

import matplotlib.pyplot as plt
import numpy as np

fig1 = plt.figure()
ax1 = fig1.add_subplot(111)


for i in range(1,15):
    ax1.plot(np.array([1,5])*i,label=i)

The piece of code that you need:

colormap = plt.cm.gist_ncar #nipy_spectral, Set1,Paired   
colors = [colormap(i) for i in np.linspace(0, 1,len(ax1.lines))]
for i,j in enumerate(ax1.lines):
    j.set_color(colors[i])
  

ax1.legend(loc=2)

The result is the following:


回答 2

TL; DR不,它不能自动完成。是的,有可能。

import matplotlib.pyplot as plt
my_colors = plt.rcParams['axes.prop_cycle']() # <<< note that we CALL the prop_cycle
fig, axes = plt.subplots(2,3)
for ax in axes.flatten(): ax.plot((0,1), (0,1), **next(my_colors))

图(axes)中的每个图(figure)都有自己的颜色周期-如果您不为每个图强制使用不同的颜色,则所有图共享相同的颜色顺序,但是,如果我们稍微扩展一下“自动”的含义, 可以办到。


OP写道

[…]我必须用[Matplotlib]自动生成的不同颜色标识每个图。

但是… Matplotlib会为每条不同的曲线自动生成不同的颜色

In [10]: import numpy as np
    ...: import matplotlib.pyplot as plt

In [11]: plt.plot((0,1), (0,1), (1,2), (1,0));
Out[11]:

那么为什么要OP请求呢?如果我们继续阅读,我们有

能否请您给我一种在同一图形中为不同图放置不同颜色的方法?

这是有道理的,因为每个图(axes按Matplotlib的说法,每个图)都有自己的color_cycle(或更确切地说,在2018年,它是prop_cycle),并且每个图(axes)以相同的顺序重用相同的颜色。

In [12]: fig, axes = plt.subplots(2,3)

In [13]: for ax in axes.flatten():
    ...:     ax.plot((0,1), (0,1))

如果这是原始问题的意思,则一种可能性是为每个图明确命名不同的颜色。

如果绘图(经常发生)是在循环中生成的,我们必须有一个附加的循环变量来覆盖Matplotlib 自动选择的颜色。

In [14]: fig, axes = plt.subplots(2,3)

In [15]: for ax, short_color_name in zip(axes.flatten(), 'brgkyc'):
    ...:     ax.plot((0,1), (0,1), short_color_name)

另一种可能性是实例化循环器对象

from cycler import cycler
my_cycler = cycler('color', ['k', 'r']) * cycler('linewidth', [1., 1.5, 2.])
actual_cycler = my_cycler()

fig, axes = plt.subplots(2,3)
for ax in axes.flat:
    ax.plot((0,1), (0,1), **next(actual_cycler))

请注意,type(my_cycler)cycler.Cycler不过type(actual_cycler)itertools.cycle

TL;DR No, it can’t be done automatically. Yes, it is possible.

import matplotlib.pyplot as plt
my_colors = plt.rcParams['axes.prop_cycle']() # <<< note that we CALL the prop_cycle
fig, axes = plt.subplots(2,3)
for ax in axes.flatten(): ax.plot((0,1), (0,1), **next(my_colors))

Each plot (axes) in a figure (figure) has its own cycle of colors — if you don’t force a different color for each plot, all the plots share the same order of colors but, if we stretch a bit what “automatically” means, it can be done.


The OP wrote

[…] I have to identify each plot with a different color which should be automatically generated by [Matplotlib].

But… Matplotlib automatically generates different colors for each different curve

In [10]: import numpy as np
    ...: import matplotlib.pyplot as plt

In [11]: plt.plot((0,1), (0,1), (1,2), (1,0));
Out[11]:

So why the OP request? If we continue to read, we have

Can you please give me a method to put different colors for different plots in the same figure?

and it make sense, because each plot (each axes in Matplotlib’s parlance) has its own color_cycle (or rather, in 2018, its prop_cycle) and each plot (axes) reuses the same colors in the same order.

In [12]: fig, axes = plt.subplots(2,3)

In [13]: for ax in axes.flatten():
    ...:     ax.plot((0,1), (0,1))

If this is the meaning of the original question, one possibility is to explicitly name a different color for each plot.

If the plots (as it often happens) are generated in a loop we must have an additional loop variable to override the color automatically chosen by Matplotlib.

In [14]: fig, axes = plt.subplots(2,3)

In [15]: for ax, short_color_name in zip(axes.flatten(), 'brgkyc'):
    ...:     ax.plot((0,1), (0,1), short_color_name)

Another possibility is to instantiate a cycler object

from cycler import cycler
my_cycler = cycler('color', ['k', 'r']) * cycler('linewidth', [1., 1.5, 2.])
actual_cycler = my_cycler()

fig, axes = plt.subplots(2,3)
for ax in axes.flat:
    ax.plot((0,1), (0,1), **next(actual_cycler))

Note that type(my_cycler) is cycler.Cycler but type(actual_cycler) is itertools.cycle.


回答 3

我想对上一篇文章中给出的最后一个循环答案进行一些细微的改进(该文章是正确的,应该仍然可以接受)。标记最后一个示例时所做的隐式假设是,plt.label(LIST)将标记号X放入LIST与第X次相对应的行中plot。我以前在使用这种方法时遇到了问题。根据matplotlibs文档(http://matplotlib.org/users/legend_guide.html#adjusting-the-order-legend-item)构建图例并自定义标签的建议方法是使标签充满热情以及您认为它们所做的确切绘图:

...
# Plot several different functions...
labels = []
plotHandles = []
for i in range(1, num_plots + 1):
    x, = plt.plot(some x vector, some y vector) #need the ',' per ** below
    plotHandles.append(x)
    labels.append(some label)
plt.legend(plotHandles, labels, 'upper left',ncol=1)

**:Matplotlib图例不起作用

I would like to offer a minor improvement on the last loop answer given in the previous post (that post is correct and should still be accepted). The implicit assumption made when labeling the last example is that plt.label(LIST) puts label number X in LIST with the line corresponding to the Xth time plot was called. I have run into problems with this approach before. The recommended way to build legends and customize their labels per matplotlibs documentation ( http://matplotlib.org/users/legend_guide.html#adjusting-the-order-of-legend-item) is to have a warm feeling that the labels go along with the exact plots you think they do:

...
# Plot several different functions...
labels = []
plotHandles = []
for i in range(1, num_plots + 1):
    x, = plt.plot(some x vector, some y vector) #need the ',' per ** below
    plotHandles.append(x)
    labels.append(some label)
plt.legend(plotHandles, labels, 'upper left',ncol=1)

**: Matplotlib Legends not working