简体   繁体   中英

How do I set an exact float as the scaling factor for my y-axis limits on Matplotlib?

The number 1.67845714e-12 is an important result from my physics project. I want to plot graphs where the y-axis limit revolves around this result as a scaling factor.

In the following example:

import numpy as np
import matplotlib.pyplot as plt
plt.ion()
import random 

x = np.arange(0,100)
y = np.zeros(len(x))

for i in range(len(x)):
    y[i] = 1.67845714e-12*random.random() - (4.20e-14)*x[i]

plt.ylim(float(-3*1.67845714e-12), float(3*1.67845714e-12)) #The important line 
plt.plot(x,y)

The resulting plot has a y-axis going from -5*e-12 to 5*e-12 , instead of a y-axis going from -3*1.67845714e-12 to 3*1.67845714e-12

How can I get Matplotlib to display the step of 1.67845714e-12 on the top left corner of the graph with a scale of -3 to 3 displayed on the y axis like I intended? And if this is impossible because for example, the step is too long, can I give my step a nickname (such as "Result") to make this work?

I've tried using other commands like ax.set_yticks() , ax=plt.gta() or ax.set_ylim() but nothing I've searched seems to work.

I am trying to answer based on what I understood you wanted to do. As I see it, you want to have a y axis from -3*1.67845714e-12 up until 3*1.67845714e-12 but each step/tick would be of size 1.67845714e-12 .

Note I created a variable named scalingFactor to hold 1.67845714e-12 . I think this answers one of your questions. You can use it then instead of writing the whole number.

Ok, to generate the ticks so you can use numpy.arange(inf, sup, step) function. It returns evenly spaced values within a given interval [inf;sup) . So we are going to generate ticks from -3*scalingFactor up until 3*scalingFactor using a 1.67845714e-12 step. You may notice in the code that sup=4*scalingFactor . It is because numpy.arange() exclude the upper limit of the interval.

To get the whole number on the axis and not rounded, you can force it to have 8 decimal places using plt.gca().yaxis.set_major_formatter(mtick.FormatStrFormatter('%.8e')) . This function formats the labels for the ticks of the axis and it uses in this case this string format %.8e .

import numpy as np
import matplotlib.pyplot as plt
plt.ion()
import random 
import matplotlib.ticker as mtick

x = np.arange(0,100)
y = np.zeros(len(x))

scalingFactor = 1.67845714e-12

for i in range(len(x)):
    y[i] = scalingFactor*random.random() - (4.20e-14)*x[i]

inf = -3*scalingFactor
sup = 4*scalingFactor

plt.plot(x, y)
plt.ylim(inf, sup)
plt.yticks(np.arange(inf, sup, scalingFactor))
plt.subplots_adjust(left=0.24) # Squash the plot from the left so the ticks labels can be seen
plt.gca().yaxis.set_major_formatter(mtick.FormatStrFormatter('%.8e')) 
plt.show()

Outputs

输出

EDIT: Well, I was actually, in fact, struggling with what you wanted cause I've never needed to do that. However I came up with a very ad-hoc solution for your problem based on what you needed cause it seems all of your data would be in that range and you wanted a scaling factor of 1.67845714e-12 .

There are formatter classes that can format tick values and handle offset value (the scale value on top left corner). So we can create a ModScalarFormatter that inherits from ScalarFormatter and override some functions to set manually the offset and ticks we want without letting matplotlib computing it:

import numpy as np
import matplotlib.pyplot as plt
plt.ion()
import random 
import math
import matplotlib.ticker as mtick

class ModScalarFormatter(mtick.ScalarFormatter):
    def __init__(self, useOffset=None, useMathText=None, useLocale=None):
        mtick.ScalarFormatter.__init__(self, useOffset, useMathText, useLocale)
        # Create the ticks we want
        self.ticks = [i for i in range(-3, 4)]

    def _set_offset(self, text):
        self.offset = text # Set the offset text we want

    def get_offset(self, txt=''):
        return self.offset # Return the offset value

    def __call__(self, x, pos=None):
        # The __call__ returns the tick on position `pos` from the
        # ticks we specified
        return self.ticks[pos]

x = np.arange(0,100)
y = np.zeros(len(x))

scalingFactor = 1.67845714e-12

for i in range(len(x)):
    y[i] = scalingFactor*random.random() - (4.20e-14)*x[i]

inf = -3*scalingFactor
sup = 3*scalingFactor

plt.plot(x, y)
plt.yticks(np.linspace(inf, sup, 7))

# Create and use a Custom Scalar Formatter Class
sf = ModScalarFormatter(useOffset=1.67845714e-12)
plt.gca().yaxis.set_major_formatter(sf)

plt.ylim(inf, sup)

plt.show()

Outputs: 临时解决方案

NOTE : I am pretty sure there should be a more elegant way to achieve this, but this is my way of helping you with and ad-hoc solution for your specific problem.

Hope this helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM