我试图创建一个带有指数(?)Y轴的matplotlib图,就像我在下面嘲笑的假图一样。对于我的数据,我想在接近最大Y值时将值展开。我希望在Y接近零时压缩值。
所有正常的记录'示例恰恰相反:它们在离开零时压缩值。这是什么' log'当然。如何创建指数(?)缩放?
答案 0 :(得分:3)
我不认为它是直接可能的。但当然你总是可以尝试作弊。在我的例子中,我只是在标签上写下其他内容:
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.LinkedList;
import java.util.Queue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
Queue<String> queue = new LinkedList<>();
queue.add("I have something to say, it's better to burn out then fade away");
queue.add("Banana peels");
queue.add("Don't worry if plan A fails, there are 25 more letters in the alphabet");
queue.add("When the past comes knocking, don't answer. It has nothing new to tell you");
queue.add("I know the voices in my head aren't real..... but sometimes their ideas are just absolutely awesome!");
TickerTapPane pane = new TickerTapPane();
pane.setMessages(queue);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(pane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TickerTapPane extends JPanel {
private Queue<String> queue;
private String message;
private int xPos;
public TickerTapPane() {
Timer timer = new Timer(40, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (message == null) {
message = queue.remove();
xPos = getWidth();
}
xPos -= 4;
FontMetrics fm = getFontMetrics(getFont());
int stringWidth = fm.stringWidth(message);
if (xPos <= -stringWidth) {
queue.add(message);
xPos = getWidth();
message = queue.remove();
}
repaint();
}
});
timer.start();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (message != null) {
Graphics2D g2d = (Graphics2D) g.create();
FontMetrics fm = g2d.getFontMetrics();
int yPos = ((getHeight() - fm.getHeight()) / 2) + fm.getAscent();
g2d.drawString(message, xPos, yPos);
g2d.dispose();
}
}
protected void setMessages(Queue<String> queue) {
this.queue = queue;
}
}
}
结果如下:
答案 1 :(得分:1)
这不是完全一般的,因为定位器是硬编码的。但这对我有用。我不得不创建一个名为ExponentialScale的新比例,使用ma.power,基数为1.1。看似简单的事情太复杂了:
class ExponentialScale(mscale.ScaleBase):
name = 'expo'
base = 1.1
logbase = math.log(base)
def __init__(self, axis, **kwargs):
mscale.ScaleBase.__init__(self)
self.thresh = None #thresh
def get_transform(self):
return self.ExponentialTransform(self.thresh)
def set_default_locators_and_formatters(self, axis):
# I could not get LogLocator to do what I wanted. I don't understand
# the docs about "subs" and the source was not clear to me.
# So I just spell out the lines I want:
major = [1, 5, 10, 12, 14, 16, 18, 20, 25, 28, 30] + range(31,60)
axis.set_major_locator(ticker.FixedLocator(major))
class ExponentialTransform(mtransforms.Transform):
input_dims = 1
output_dims = 1
is_separable = True
def __init__(self, thresh):
mtransforms.Transform.__init__(self)
self.thresh = thresh
def transform_non_affine(self, a):
res = ma.power(ExponentialScale.base, a)
return res
def inverted(self):
return ExponentialScale.InvertedExponentialTransform(self.thresh)
class InvertedExponentialTransform(mtransforms.Transform):
input_dims = 1
output_dims = 1
is_separable = True
def __init__(self, thresh):
mtransforms.Transform.__init__(self)
self.thresh = thresh
def transform_non_affine(self, a):
denom = np.repeat(ExponentialScale.logbase, len(a))
return np.log(a) / denom
def inverted(self):
return ExponentialScale.ExponentialTransform(self.thresh)
答案 2 :(得分:1)
只需将其添加到代码中即可进行日志缩放:
plt.figure()
ax = plt.subplot(111)
ax.set_yscale('log')
但如果你想要一个指数级别,这个问题就可以解答: link to question
答案 3 :(得分:0)
我假设你的意思是X轴,因为在你的模拟图中,X轴是指数的,而不是Y轴。
您可以这样做:
...
ax = plt.subplot(111)
ax.plot(Xs,Ys,color='blue',linewidth=2)
....
xlabs = [pow(10,i) for i in range(0,6)]
ax.set_xticklabels(xlabs)
ax.set_xticks(xlabs)
我在这里做的是手动创建6个X的列表,其中每个X由10^i
表示,即10^1,10^2,...
。这将在[1, 10, 100, 1000, 10000, 100000]
处放置X刻度标记并正确标记它们。如果您需要更多标签,请更改6
。
答案 4 :(得分:0)
答案 5 :(得分:0)
从matplotlib 3.1起,您可以轻松地通过以下方式定义任何自定义比例
ax.set_yscale('function', functions=(forward, inverse))
另请参见https://matplotlib.org/3.1.1/gallery/scales/scales.html
在这种情况下,例如:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(1, 40, 100)
y = np.linspace(1, 4, 100)
fig, ax = plt.subplots()
ax.plot(x, y)
exp = lambda x: 10**(x)
log = lambda x: np.log(x)
# Set y scale to exponential
ax.set_yscale('function', functions=(exp, log))
ax.set(xlim=(1,40), ylim=(1,4))
ax.set_yticks([1, 3, 3.5, 3.75, 4.0])
plt.show()
答案 6 :(得分:0)
将此添加到您的代码中:
plt.yscale('symlog')
来源:https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.pyplot.yscale.html