TimGJ
TimGJ

Reputation: 1654

Setting axis values in numpy/matplotlib.plot

I am in the process of learning numpy. I wish to plot a graph of Planck's law for different temperatures and so have two np.arrays, T and l for temperature and wavelength respectively.

import scipy.constants as sc
import numpy as np
import matplotlib.pyplot as plt

lhinm = 10000                         # Highest wavelength in nm
T = np.linspace(200, 1000, 10)        # Temperature in K
l = np.linspace(0, lhinm*1E-9, 101)   # Wavelength in m
labels = np.linspace(0, lhinm, 6)     # Axis labels giving l in nm

B = (2*sc.h*sc.c**2/l[:, np.newaxis]**5)/(np.exp((sc.h*sc.c)/(T*l[:, np.newaxis]*sc.Boltzmann))-1)

for ticks in [True, False]:
    plt.plot(B)
    plt.xlabel("Wavelength (nm)")
    if ticks:
        plt.xticks(l, labels)
        plt.title("With xticks()")
        plt.savefig("withticks.png")
    else:
        plt.title("Without xticks()")
        plt.savefig("withoutticks.png")
    plt.show()

I would like to label the x-axis with the wavelength in nm. If I don't call plt.xitcks() the labels on the x-axis would appear to be the index in to the array B (which holds the caculated values).

Without ticks

I've seen answer 7559542, but when I call plt.xticks() all the values are scrunched up on the left of the axis, rather than being evenly spread along it.

With ticks

So what's the best way to define my own set of values (in this case a subset of the values in l) and place them on the axis?

Upvotes: 2

Views: 8565

Answers (3)

tmdavison
tmdavison

Reputation: 69213

You can supply the x values to plt.plot, and let matplotlib take care of setting the tick labels.

In your case, you could plot plt.plot(l, B), but then you still have the ticks in m, not nm.

You could therefore convert your l array to nm before plotting (or during plotting). Here's a working example:

import scipy.constants as sc
import numpy as np
import matplotlib.pyplot as plt

lhinm = 10000                         # Highest wavelength in nm
T = np.linspace(200, 1000, 10)        # Temperature in K
l = np.linspace(0, lhinm*1E-9, 101)   # Wavelength in m
l_nm = l*1e9                          # Wavelength in nm
labels = np.linspace(0, lhinm, 6)     # Axis labels giving l in nm

B = (2*sc.h*sc.c**2/l[:, np.newaxis]**5)/(np.exp((sc.h*sc.c)/(T*l[:, np.newaxis]*sc.Boltzmann))-1)

plt.plot(l_nm, B)
# Alternativly:
# plt.plot(l*1e9, B)
plt.xlabel("Wavelength (nm)")
plt.title("With xticks()")
plt.savefig("withticks.png")
plt.show()

enter image description here

Upvotes: 3

David Z
David Z

Reputation: 131730

The problem is that you're not giving your wavelength values to plt.plot(), so Matplotlib puts the index into the array on the horizontal axis as a default. Quick solution:

plt.plot(l, B)

Without explicitly setting tick labels, that gives you this:

plot with proper values on x axis

Of course, the values on the horizontal axis in this plot are actually in meters, not nanometers (despite the labeling), because the values you passed as the first argument to plot() (namely the array l) are in meters. That's where xticks() comes in. The two-argument version xticks(locations, labels) places the labels at the corresponding locations on the x axis. For example, xticks([1], 'one') would put a label "one" at the location x=1, if that location is in the plot.

However, it doesn't change the range displayed on the axis. In your original example, your call to xticks() placed a bunch of labels at coordinates like 10-9, but it didn't change the axis range, which was still 0 to 100. No wonder all the labels were squished over to the left.

What you need to do is call xticks() with the points at which you want to place the labels, and the desired text of the labels. The way you were doing it, xticks(l, labels), would work except that l has length 101 and labels only has length 6, so it only uses the first 6 elements of l. To fix that, you can do something like

plt.xticks(labels * 1e-9, labels)

where the multiplication by 1e-9 converts from nanometers (what you want displayed) to meters (which are the coordinates Matplotlib actually uses in the plot).

fixed plot with proper labels

Upvotes: 3

Repiklis
Repiklis

Reputation: 399

You need to use same size lists at the xtick. Try setting the axis values separately from the plot value as below.

import scipy.constants as sc
import numpy as np
import matplotlib.pyplot as plt

lhinm = 10000                         # Highest wavelength in nm
T = np.linspace(200, 1000, 10)        # Temperature in K
l = np.linspace(0, lhinm*1E-9, 101)   # Wavelength in m
ll = np.linspace(0, lhinm*1E-9, 6)    # Axis values
labels = np.linspace(0, lhinm, 6)     # Axis labels giving l in nm

B = (2*sc.h*sc.c**2/l[:, np.newaxis]**5)/(np.exp((sc.h*sc.c)/(T*l[:, np.newaxis]*sc.Boltzmann))-1)

for ticks in [True, False]:
    plt.plot(B)
    plt.xlabel("Wavelength (nm)")
    if ticks:
        plt.xticks(ll, labels)
        plt.title("With xticks()")
        plt.savefig("withticks.png")
    else:
        plt.title("Without xticks()")
        plt.savefig("withoutticks.png")
    plt.show()

Upvotes: 0

Related Questions