在matplotlib中绘制对数2刻度的正方形坐标轴图表

36

我想用matplotlib制作一个正方形轴散点图。通常使用set_scale("log")很好用,但它限制了我只能使用对数10。我希望在对数2下绘制图表。我在这里看到了解决方案:如何生成指数比例的坐标轴?

但它非常复杂,并且如果数组中有0值,则无法使用该方法。我希望像其他numpy函数一样简单地忽略这些值。

例如:

log2scatter(data1, data2)

data1和data2中包含0的图表应该在x和y轴上采用对数刻度,并使用对数间隔刻度。 就像log10一样,只不过是log2...

谢谢。


日志仅对正参数定义。这适用于任何基数,即自然对数、以10为底的对数、以2为底的对数等。因此,除非对这些零值进行处理,否则您无法在对数刻度上绘制具有零的内容。 - ev-br
使用那个问题的答案,但首先过滤掉y值为0及其对应的x值(这也是numpy忽略它们的方式)。 - mathematical.coffee
有什么优雅的方法可以在numpy中完成这个任务?过滤会使代码变得复杂,因为现在我必须有一个未经过滤的数组副本和一个已经过滤的副本... - user248237
2个回答

65
Matplotlib >= 3.3:
指定 base=2:
import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.set_xscale('log', base=2)
ax.set_yscale('log', base=2)

ax.plot(range(1024))
plt.show()

Matplotlib < 3.3:
为x轴和y轴指定basex=2和/或basey=2
import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.set_xscale('log', basex=2)
ax.set_yscale('log', basey=2)

ax.plot(range(1024))
plt.show()

enter image description here

对于零交叉行为,你所指的是“对称对数”图(也称为“symlog”)。不管怎么说,数据并没有被过滤掉,只是在接近0的地方是线性图,在其他地方是对数图。改变的是刻度,而不是数据。
通常你只需要使用ax.set_xscale('symlog', basex=2),但是目前在symlog图中使用非10为底的对数似乎有些问题。 编辑: 哈!这个bug似乎是由一个经典错误引起的:使用可变的默认参数。 我已经提交了一个bug报告,但是如果你想修复它,你需要在lib/matplotlib/ticker.py文件中的大约1376行附近,在SymmetricalLogLocator类的__init__方法中进行一个小的编辑。
而不是
def __init__(self, transform, subs=[1.0]):
    self._transform = transform
    self._subs = subs
    ...

改成类似的东西:
def __init__(self, transform, subs=None):
    self._transform = transform
    if subs is None:
        self._subs = [1.0]
    else:
        self._subs = subs
    ....

经过这个改变,它的表现符合预期...
import matplotlib.pyplot as plt
import numpy as np

fig, ax = plt.subplots()
ax.set_xscale('symlog', basex=2)
ax.set_yscale('symlog', basey=2)

x = np.arange(-1024, 1024)
ax.plot(x, x)

plt.show()

enter image description here


使用 base=2 参数(即使没有该参数),我得到了非常奇怪的默认 x 和 y 轴限制。它不会将其设置为任一维度中的最小值。它选择非常奇怪的限制,隐藏了大部分数据。除手动设置 x/y 轴限制外,如何修复这个问题? - user248237
1
不应该在matplotlib中覆盖/黑客类来制作一个以log2为基础的散点图...这太悲哀和令人沮丧了。:( - user248237
symlog 部分存在一个错误。你所提到的限制只是对于对数坐标轴而言,限制行为的一种方式。它们会“捕捉”到最接近基数的幂次方。如果你想要限制严格地结束于数据的最小值和最大值,则需要指定 ax.axis('tight') - Joe Kington
14
matplotlib >= 3.3中,使用base=2代替basex=2basey=2 - rvf

16

如果您使用的是plt.xscale,仍需要指定basex而不是base:

plt.figure()
plt.plot(x, y)
plt.xscale('log', basex=2)
plt.show()

1
就像这个评论所建议的那样。这取决于matplotlib的版本。现在,上面的代码将产生TypeError: LogScale.__init__() got an unexpected keyword argument 'basex' - Hacker
5
plt.xscale('log', base=2) 对我有效。 - Mike B

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接