matplotlib问题绘制记录的数据并设置其x/y边界

9 python numpy matplotlib

我在matplotlib中使用如下的日志图,大致如下.

plt.scatter(x, y)

# use log scales
plt.gca().set_xscale('log')
plt.gca().set_yscale('log')

# set x,y limits
plt.xlim([-1, 3])
plt.ylim([-1, 3])
Run Code Online (Sandbox Code Playgroud)

第一个问题是没有x,y限制,matplotlib设置比例使得大多数数据不可见 - 由于某种原因,它不使用沿x和y维度的最小值和最大值,因此默认图是非常误导.

当我使用plt.xlim,plt.ylim手动设置限制时,我将其解释为以log10为单位的-1到3(即1/10到3000),我得到一个类似附图的图. 在此输入图像描述

这里的轴标签没有意​​义:它从10 ^ 1到10 ^ 3.这里发生了什么?

我在下面包含了一个更详细的示例,它显示了数据的所有这些问题:

import matplotlib
import matplotlib.pyplot as plt
from numpy import *

x = array([58, 0, 20, 2, 2, 0, 12, 17, 16, 6, 257, 0, 0, 0, 0, 1, 0, 13, 25, 9, 13, 94, 0, 0, 2, 42, 83, 0, 0, 157, 27, 1, 80, 0, 0, 0, 0, 2, 0, 41, 0, 4, 0, 10, 1, 4, 63, 6, 0, 31, 3, 5, 0, 61, 2, 0, 0, 0, 17, 52, 46, 15, 67, 20, 0, 0, 20, 39, 0, 31, 0, 0, 0, 0, 116, 0, 0, 0, 11, 39, 0, 17, 0, 59, 1, 0, 0, 2, 7, 0, 66, 14, 1, 19, 0, 101, 104, 228, 0, 31])

y = array([60, 0, 9, 1, 3, 0, 13, 9, 11, 7, 177, 0, 0, 0, 0, 1, 0, 12, 31, 10, 14, 80, 0, 0, 2, 30, 70, 0, 0, 202, 26, 1, 96, 0, 0, 0, 0, 1, 0, 43, 0, 6, 0, 9, 1, 3, 32, 6, 0, 20, 1, 2, 0, 52, 1, 0, 0, 0, 26, 37, 44, 13, 74, 15, 0, 0, 24, 36, 0, 22, 0, 0, 0, 0, 75, 0, 0, 0, 9, 40, 0, 14, 0, 51, 2, 0, 0, 1, 9, 0, 59, 9, 0, 23, 0, 80, 81, 158, 0, 27])

c = 0.01

plt.figure(figsize=(5,3))
s = plt.subplot(1, 3, 1)
plt.scatter(x + c, y + c)
plt.title('Unlogged')
s = plt.subplot(1, 3, 2)
plt.scatter(x + c, y + c)
plt.gca().set_xscale('log', basex=2)
plt.gca().set_yscale('log', basey=2)
plt.title('Logged')
s = plt.subplot(1, 3, 3)
plt.scatter(x + c, y + c)
plt.gca().set_xscale('log', basex=2)
plt.gca().set_yscale('log', basey=2)
plt.xlim([-2, 20])
plt.ylim([-2, 20])
plt.title('Logged with wrong xlim/ylim')
plt.savefig('test.png')
Run Code Online (Sandbox Code Playgroud)

这产生了以下情节:

在此输入图像描述

在左起第一个子图中,我们有原始未记录的数据.第二,我们记录了默认视图的值.第三,我们记录了指定x/y lims的值.我的问题是:

  1. 为什么散点图的默认x/y边界错误?手册说它应该使用数据中的最小值和最大值,但这显然不是这里的情况.它选择隐藏绝大多数数据的值.

  2. 为什么当我自己设置边界时,在左边的第三个散点图中,它会反转标签的顺序?在2 ^ 5之前显示2 ^ 8?这很令人困惑.

  3. 最后,我怎样才能得到它,以便在默认情况下使用子图时这些图不会像那样被压扁?我希望这些散点图是方形的.

编辑:感谢Joe和Honk的回复.如果我尝试将这样的子图调整为正方形:

plt.figure(figsize=(5,3), dpi=10)
s = plt.subplot(1, 2, 1, adjustable='box', aspect='equal')
plt.scatter(x + c, y + c)
plt.title('Unlogged')
s = plt.subplot(1, 2, 2, adjustable='box', aspect='equal')
plt.scatter(x + c, y + c)
plt.gca().set_xscale('log', basex=2)
plt.gca().set_yscale('log', basey=2)
plt.title('Logged')
Run Code Online (Sandbox Code Playgroud)

我得到以下结果:

在此输入图像描述

我怎样才能让每个情节都是方形的并且彼此对齐?它应该只是一个正方形的网格,所有大小相等......

编辑2:

为了回馈一些东西,下面是如何使用这些log 2图并使轴以非指数表示法出现:

import matplotlib

from matplotlib.ticker import FuncFormatter

def log_2_product(x, pos):
    return "%.2f" %(x)

c = 0.01
plt.figure(figsize=(10,5), dpi=100)
s1 = plt.subplot(1, 2, 1, adjustable='box', aspect='equal')
plt.scatter(x + c, y + c)
plt.title('Unlogged')
plotting.axes_square(s1)
s2 = plt.subplot(1, 2, 2, adjustable='box', aspect='equal')
min_x, max_x = min(x + c), max(x + c)
min_y, max_y = min(y + c), max(y + c)
plotting.axes_square(s2)
plt.xlim([min_x, max_x])
plt.ylim([min_y, max_y])
plt.gca().set_xscale('log', basex=2)
plt.gca().set_yscale('log', basey=2)
plt.scatter(x + c, y + c)
formatter = FuncFormatter(log_2_product)
s2.xaxis.set_major_formatter(formatter)
s2.yaxis.set_major_formatter(formatter)

plt.title('Logged')
plt.savefig('test.png')
Run Code Online (Sandbox Code Playgroud)

谢谢你的帮助.

Joe*_*ton 12

@honk已经回答了你的主要问题,但至于其他人(以及你原来的问题),请阅读一些教程或看一些例子.:)

你变得非常困惑,因为你还没有查看你正在使用的函数的文档.

为什么散点图的默认x/y边界错误?手册说它应该使用数据中的最小值和最大值,但这显然不是这里的情况.它选择隐藏绝大多数数据的值.

它肯定不会在文档中说明.

默认情况下,matplotlib将"舍入"到最接近的"偶数"数字以用于绘图限制.在对数图的情况下,这是基数的最近幂.

如果您希望它严格捕捉到数据的最小值和最大值,请指定:

ax.axis('tight')
Run Code Online (Sandbox Code Playgroud)

或者等价的

plt.axis('tight')
Run Code Online (Sandbox Code Playgroud)

为什么当我自己设置边界时,在左边的第三个散点图中,它会反转标签的顺序?在2 ^ 5之前显示2 ^ 8?这很令人困惑.

不是.它在2 ^ 5之前显示2 ^ -8.你只有太多的标签被压扁了.指数中的减号被重叠的文字隐藏了.尝试调整绘图或调用的大小plt.tight_layout()(或更改字体大小或dpi.更改dpi是在保存的图像上使所有字体变大或变小的快速方法.)

最后,我怎样才能得到它,以便在默认情况下使用子图时这些图不会像那样被压扁?我希望这些散点图是方形的.

有几种方法可以做到这一点,取决于你所说的"方形".(即你想要图的宽高比变化还是限制?)

我猜你的意思是这两个,在这种情况下,你传递adjustable='box'aspect='equal'plt.subplot.(您也可以稍后以多种不同方式设置它,(plt.axis('equal')等))

作为以上所有的一个例子:

import matplotlib.pyplot as plt
import numpy as np

x = np.array([58, 0, 20, 2, 2, 0, 12, 17, 16, 6, 257, 0, 0, 0, 0, 1, 0, 13, 25,
              9, 13, 94, 0, 0, 2, 42, 83, 0, 0, 157, 27, 1, 80, 0, 0, 0, 0, 2, 
              0, 41, 0, 4, 0, 10, 1, 4, 63, 6, 0, 31, 3, 5, 0, 61, 2, 0, 0, 0, 
              17, 52, 46, 15, 67, 20, 0, 0, 20, 39, 0, 31, 0, 0, 0, 0, 116, 0, 
              0, 0, 11, 39, 0, 17, 0, 59, 1, 0, 0, 2, 7, 0, 66, 14, 1, 19, 0, 
              101, 104, 228, 0, 31])

y = np.array([60, 0, 9, 1, 3, 0, 13, 9, 11, 7, 177, 0, 0, 0, 0, 1, 0, 12, 31, 
              10, 14, 80, 0, 0, 2, 30, 70, 0, 0, 202, 26, 1, 96, 0, 0, 0, 0, 1,
              0, 43, 0, 6, 0, 9, 1, 3, 32, 6, 0, 20, 1, 2, 0, 52, 1, 0, 0, 0, 
              26, 37, 44, 13, 74, 15, 0, 0, 24, 36, 0, 22, 0, 0, 0, 0, 75, 0, 
              0, 0, 9, 40, 0, 14, 0, 51, 2, 0, 0, 1, 9, 0, 59, 9, 0, 23, 0, 80,
              81, 158, 0, 27])
c = 0.01

# Let's make the figure a bit bigger so the text doesn't run into itself...
# (5x3 is rather small at 100dpi. Adjust the dpi if you really want a 5x3 plot)
fig, axes = plt.subplots(ncols=3, figsize=(10, 6), 
                         subplot_kw=dict(aspect=1, adjustable='box'))

# Don't use scatter for this. Use plot. Scatter is if you want to vary things 
# like color or size by a third or fourth variable.
for ax in axes:
    ax.plot(x + c, y + c, 'bo')

for ax in axes[1:]:
    ax.set_xscale('log', basex=2)
    ax.set_yscale('log', basey=2)

axes[0].set_title('Unlogged')
axes[1].set_title('Logged')

axes[2].axis([2**-2, 2**20, 2**-2, 2**20])
axes[2].set_title('Logged with wrong xlim/ylim')

plt.tight_layout()
plt.show()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

如果您希望绘图轮廓大小和形状完全相同,那么最简单的方法是将图形大小更改为适当的比例然后使用adjustable='datalim'.

如果要完全推广,只需手动添加子轴而不是使用子图.

但是,如果您不介意调整图形大小和/或使用subplots_adjust,那么很容易做到并且仍然使用子图.

基本上,你会做类似的事情

# For 3 columns and one row, we'd want a 3 to 1 ratio...
fig, axes = plt.subplots(ncols=3, figsize=(9,3), 
                         subplot_kw=dict(adjustable='datalim', aspect='equal')

# By default, the width available to make subplots in is 5% smaller than the 
# height to make them in. This is easily changable...
# ("right" is a percentage of the total width. It will be 0.95 regardless.)
plt.subplots_adjust(right=0.95)
Run Code Online (Sandbox Code Playgroud)

然后继续像以前一样.

完整的例子:

import matplotlib.pyplot as plt
import numpy as np

x = np.array([58, 0, 20, 2, 2, 0, 12, 17, 16, 6, 257, 0, 0, 0, 0, 1, 0, 13, 25,
              9, 13, 94, 0, 0, 2, 42, 83, 0, 0, 157, 27, 1, 80, 0, 0, 0, 0, 2, 
              0, 41, 0, 4, 0, 10, 1, 4, 63, 6, 0, 31, 3, 5, 0, 61, 2, 0, 0, 0, 
              17, 52, 46, 15, 67, 20, 0, 0, 20, 39, 0, 31, 0, 0, 0, 0, 116, 0, 
              0, 0, 11, 39, 0, 17, 0, 59, 1, 0, 0, 2, 7, 0, 66, 14, 1, 19, 0, 
              101, 104, 228, 0, 31])

y = np.array([60, 0, 9, 1, 3, 0, 13, 9, 11, 7, 177, 0, 0, 0, 0, 1, 0, 12, 31, 
              10, 14, 80, 0, 0, 2, 30, 70, 0, 0, 202, 26, 1, 96, 0, 0, 0, 0, 1,
              0, 43, 0, 6, 0, 9, 1, 3, 32, 6, 0, 20, 1, 2, 0, 52, 1, 0, 0, 0, 
              26, 37, 44, 13, 74, 15, 0, 0, 24, 36, 0, 22, 0, 0, 0, 0, 75, 0, 
              0, 0, 9, 40, 0, 14, 0, 51, 2, 0, 0, 1, 9, 0, 59, 9, 0, 23, 0, 80,
              81, 158, 0, 27])
c = 0.01

fig, axes = plt.subplots(ncols=3, figsize=(9, 3),
                         subplot_kw=dict(adjustable='datalim', aspect='equal'))
plt.subplots_adjust(right=0.95)

for ax in axes:
    ax.plot(x + c, y + c, 'bo')

for ax in axes[1:]:
    ax.set_xscale('log', basex=2)
    ax.set_yscale('log', basey=2)

axes[0].set_title('Unlogged')
axes[1].set_title('Logged')

axes[2].axis([2**-2, 2**20, 2**-2, 2**20])
axes[2].set_title('Logged with wrong xlim/ylim')

plt.tight_layout()
plt.show()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述