Python 在matplotlib中手动绘制对数间隔的记号标记和标签

Python 在matplotlib中手动绘制对数间隔的记号标记和标签,python,matplotlib,Python,Matplotlib,我经常发现自己在绘制图时使用对数单位,例如,在对数据进行装箱或创建等高线图之前,先获取数据的np.log10(x)。问题是,当我想让绘图更形象化时,轴是以难看的对数单位表示的,刻度线是均匀分布的 如果我让matplotlib进行所有转换,即通过设置ax.set_xaxis('log'),那么我会得到非常好看的轴,但是我不能对我的数据进行转换,因为它已经以日志单位进行了装箱。我可以手动更改勾号标签,但这不会使勾号间距为对数。我想我也可以手动指定每个小记号的位置,这样它就有了日志间距,但这是实现这一

我经常发现自己在绘制图时使用对数单位,例如,在对数据进行装箱或创建等高线图之前,先获取数据的
np.log10(x)
。问题是,当我想让绘图更形象化时,轴是以难看的对数单位表示的,刻度线是均匀分布的

如果我让matplotlib进行所有转换,即通过设置
ax.set_xaxis('log')
,那么我会得到非常好看的轴,但是我不能对我的数据进行转换,因为它已经以日志单位进行了装箱。我可以手动更改勾号标签,但这不会使勾号间距为对数。我想我也可以手动指定每个小记号的位置,这样它就有了日志间距,但这是实现这一点的唯一方法吗?这有点乏味,所以如果有更好的方法就好了

具体来说,这里有一个情节:

我想把记号标签画成
10^x
10^y
(因此'1'是'10',2是'100'等等),我想把小记号画成
ax。set_xaxis('log')
会把它们画出来

编辑:为了更具体,假设绘图是从图像生成的,如下所示:

import matplotlib.pyplot as plt
import scipy.misc
img = scipy.misc.face()

x_range = [-5,3] # log10 units
y_range = [-55, -45] # log10 units

p = plt.imshow(img,extent=x_range+y_range)

plt.show()
我们要做的就是改变轴的外观,正如我所描述的

编辑2:好的,ImportanceOfBeingErnest的答案很聪明,但它比我想要的更具体一些。我有另一个例子,这次是装箱数据。也许他们的技术在这方面仍然有效,尽管我不清楚是否如此

import numpy as np
import pandas as pd
import datashader as ds
from matplotlib import pyplot as plt
import scipy.stats as sps

v1 = sps.lognorm(loc=0, scale=3, s=0.8)
v2 = sps.lognorm(loc=0, scale=1, s=0.8)
x = np.log10(v1.rvs(100000))
y = np.log10(v2.rvs(100000))
x_range=[np.min(x),np.max(x)]
y_range=[np.min(y),np.max(y)]

df = pd.DataFrame.from_dict({"x": x, "y": y})

#------ Aggregate the data ------
cvs = ds.Canvas(plot_width=30, plot_height=30, x_range=x_range, y_range=y_range)
agg = cvs.points(df, 'x', 'y')

# Create contour plot
fig = plt.figure()
ax = fig.add_subplot(111)
ax.contourf(agg, extent=x_range+y_range)
ax.set_xlabel("x")
ax.set_ylabel("y")

plt.show()

这篇文章大概给出了这个问题的一般答案:

但是,这里一个简单的选项可能是缩放轴的内容,然后将轴设置为对数比例

A.形象 您可以按对数比例打印图像,但要使所有像素以对数单位显示相同的大小。不幸的是,
imshow
不允许这样的图像(),但是人们可以为此使用
pcolormesh

import numpy as np
import matplotlib.pyplot as plt
import scipy.misc
img = scipy.misc.face()

extx = [-5,3]     # log10 units
exty = [-45, -55] # log10 units
x = np.logspace(extx[0],extx[-1],img.shape[1]+1)
y = np.logspace(exty[0],exty[-1],img.shape[0]+1)
X,Y = np.meshgrid(x,y)

c =  img.reshape((img.shape[0]*img.shape[1],img.shape[2]))/255.0
m = plt.pcolormesh(X,Y,X[:-1,:-1], color=c, linewidth=0)
m.set_array(None)

plt.gca().set_xscale("log")
plt.gca().set_yscale("log")

plt.show()

B.等高线 同样的概念也可用于等高线图

import numpy as np
from matplotlib import pyplot as plt

x = np.linspace(-1.1,1.9)
y = np.linspace(-1.4,1.55)
X,Y = np.meshgrid(x,y)
agg = np.exp(-(X**2+Y**2)*2)


fig, ax  = plt.subplots()

plt.gca().set_xscale("log")
plt.gca().set_yscale("log")


exp = lambda x: 10.**(np.array(x))

cf = ax.contourf(exp(X), exp(Y),agg, extent=exp([x.min(),x.max(),y.min(),y.max()]))

ax.set_xlabel("x")
ax.set_ylabel("y")

plt.show()

这一点相当不清楚。为什么首先要记录数据?省去这一点,然后使用ax.set_xaxis('log')就我所知,您可以得到所需的绘图。因为,例如,我已经使用其他工具以对数单位绘制了绘图。在这个特殊的例子中,我有一个基本上来自datashader的图像,我需要在matplotlib中很好地绘制轴。也许一个好办法是获取未记录的数据范围,并让matplotlib使用
set_xaxis('log')
绘制空轴,然后将图像添加到其中,或者做其他事情。您介意创建一个问题的解决方案吗?否则这都是猜测。好吧,我添加了一个嗯,好吧,这很酷,但比我想要的更具体一点。我添加了另一个示例,数据与numpy.histogram(即,您不能只为其提供日志箱边)之外的其他内容合并,然后绘制结果的等高线图。你建议的东西还能用吗?哈哈,当然,一旦我为你解决了这个问题,你会决定你还需要一些不同的东西。我希望能找到一个通用的解决方案,解决把轴换成漂亮的原木单位的问题,而不是对这种或那种类型的绘图进行微调。总之,我用轮廓的解决方案更新了答案。我很好奇接下来会发生什么实际上我忘了我已经回答了一个类似的问题。这可能是您对通用解决方案的理解(尽管实施起来也很麻烦);我更新了答案。