我怎样才能用matplotlib以指数方式缩放Y轴

时间:2014-10-04 23:46:28

标签: python matplotlib

我试图创建一个带有指数(?)Y轴的matplotlib图,就像我在下面嘲笑的假图一样。对于我的数据,我想在接近最大Y值时将值展开。我希望在Y接近零时压缩值。

所有正常的记录'示例恰恰相反:它们在离开零时压缩值。这是什么' log'当然。如何创建指数(?)缩放?

graph

7 个答案:

答案 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;
        }

    }

}

结果如下: enter image description here

答案 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)

有关创建新轴刻度的Matplotlib文档可用here

exppential scale当前不包含在matplotlib中,但是 例如,您可以使用此example作为您自己实施的起点。

答案 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()

enter image description here

答案 6 :(得分:0)

将此添加到您的代码中:

plt.yscale('symlog')

来源:https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.pyplot.yscale.html