PmagPy structure

The GUI programs

Some of the common data conversion and analysis functionality of PmagPy is exposed within the GUI programs as we saw yesterday. However, the capabilities of PmagPy extend well beyond what is in the GUIs and can access within the command line programs and as functions that can imported as Python modules.

The command line programs

As an example, let's consider a situation where we want to draw random samples from a specified Fisher distribution. This can be done with the command line program fishrot.py. We can learn a little bit about fishrot.py in the PmagPy Cookbook. The command line programs take flags. Type this command at the terminal to learn about them:

fishrot.py -h

For example, if we want to sample 10 directions from a Fisher distribution with a mean declination of 45, a mean inclination of 30 and a kappa of 20, we would use this command in terminal:

fishrot.py -k 20 -n 10 -D 45 -I 30

Let's look at the code of fishrot.py on Github: https://github.com/PmagPy/PmagPy/blob/master/programs/fishrot.py

We can see within the program that the program uses two functions within pmag.py (pmag.fshdev and pmag.dodirot). Let's look at the source of these functions which is taken from pmag.py into the code cell below:


In [1]:
def fshdev(k):
    """
    Generate a random draw from a Fisher distribution with mean declination 
    of 0 and inclination of 90 with a specified kappa.

    Parameters
    ----------
    k : kappa (precision parameter) of the distribution

    Returns
    ----------
    dec, inc : declination and inclination of random Fisher distribution draw
    """
    R1=random.random()
    R2=random.random()
    L=numpy.exp(-2*k)
    a=R1*(1-L)+L
    fac=numpy.sqrt((-numpy.log(a))/(2*k))
    inc=90.-2*numpy.arcsin(fac)*180./numpy.pi
    dec=2*numpy.pi*R2*180./numpy.pi
    return dec,inc

def dodirot(D,I,Dbar,Ibar):
    """
    Rotate a declination/inclination pair by the difference between dec=0 and
    inc = 90 and the provided desired mean direction

    Parameters
    ----------
    D : declination to be rotated
    I : inclination to be rotated
    Dbar : declination of desired mean
    Ibar : inclination of desired mean

    Returns
    ----------
    drot, irot : rotated declination and inclination
    """
    d,irot=dogeo(D,I,Dbar,90.-Ibar)
    drot=d-180.
    if drot<360.:drot=drot+360.
    if drot>360.:drot=drot-360.
    return drot,irot

Using functions in the notebook

To use functions in the notebook we can import PmagPy function modules as in the code cell below. These function modules are: pmag, a module with functions for analyzing paleomagnetic and rock magnetic data that are used within the command lines programs, the GUIs and within ipmag, a module with functions that combine and extend pmag functions and exposes pmagplotlib functions in order to generate output that works well within the Jupyter notebook environment.


In [12]:
import pmagpy.pmag as pmag
import pmagpy.ipmag as ipmag

import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

Putting a question mark after a function results in the docstring being displayed.


In [13]:
ipmag.fishrot?

In [14]:
ipmag.fishrot??

Putting two questions marks displays the docstring and the source code.


In [15]:
ipmag.fishrot??

Using ipmag.fishrot to simulate Fisher distributed directions

The docstring helps guide us to know what parameters to put into the function. Here let's take 10 samples from a distribution with mean of dec=45, inc= 30 and kappa precision parameter of 20. If simply call the function it will print to the console as in the code cell below. In the code cell below that, we assign the variable to be this this block of declination/inclination values which we call a di_block.


In [5]:
ipmag.fishrot(k=20, n=10, dec=45, inc=30)


Out[5]:
[[24.993171995769615, 31.20972525947937, 1.0],
 [58.359010376109779, 33.305462957470048, 1.0],
 [42.635619144688349, 10.627953058109977, 1.0],
 [81.261264135743204, 12.632770890638987, 1.0],
 [46.774276336575781, 53.121289098634008, 1.0],
 [55.992791121139703, 17.054058786100438, 1.0],
 [46.351927983816609, 15.151165169609847, 1.0],
 [72.809163208735129, 38.954052566652265, 1.0],
 [48.149035613761384, 18.295490639275904, 1.0],
 [61.323466349196678, -8.9409144357291179, 1.0]]

In [7]:
directions = ipmag.fishrot(k=20, n=10, dec=45, inc=30)
directions


Out[7]:
[[29.247677327866199, 8.2604819125653091, 1.0],
 [46.984358726836547, 13.990873265409752, 1.0],
 [54.582564158394575, 15.643973002119548, 1.0],
 [43.822712178795086, 32.567091737065141, 1.0],
 [41.143575692358127, 39.66918241986145, 1.0],
 [45.164218535973077, 14.282448889105222, 1.0],
 [29.096483806196943, 32.012026237483198, 1.0],
 [33.154733540204461, 23.808538728709841, 1.0],
 [61.434038213438043, 37.445075508403896, 1.0],
 [33.021019328679358, 20.764317497711787, 1.0]]

Plotting directions

Now let's say we want to plot these directions. Let's use the ipmag.plot_di function to do so. We can learn about that function by putting questions marks after it. Shift+tab also displays such information about a function.


In [8]:
ipmag.plot_di()

Following the instructions in the documentation string, let's make a plot and plot the directions.


In [15]:
fignum = 1
plt.figure(num=fignum,figsize=(4,4),dpi=160)
ipmag.plot_net(fignum)
ipmag.plot_di(di_block=directions)


Calculating and plotting a Fisher mean

Let's get more directions and then take their mean. We can calculate the mean using the function ipmag.fisher_mean. That function returns a handy python data structure called a dictionary.


In [11]:
decs = [100,120,115]
incs = [24,26,10]
mean = ipmag.fisher_mean(dec=decs,inc=incs)
print(mean)


{'csd': 12.973034047271971, 'k': 38.984047002620635, 'n': 3, 'r': 2.9486969631483988, 'alpha95': 20.017203157751581, 'dec': 111.72444503792575, 'inc': 20.211930646305532}

In [18]:
lots_of_directions = ipmag.fishrot(k=50, n=100, dec=45, inc=30)
mean = ipmag.fisher_mean(di_block=lots_of_directions)
print(mean)


{'csd': 10.733005654690752, 'k': 56.954405295665438, 'n': 100, 'r': 98.261767470205953, 'alpha95': 1.8890635473495314, 'dec': 45.288894569478941, 'inc': 28.918129983160952}

In [19]:
ipmag.print_direction_mean(mean)


Dec: 45.3  Inc: 28.9
Number of directions in mean (n): 100
Angular radius of 95% confidence (a_95): 1.9
Precision parameter (k) estimate: 57.0

To access a single element in the dictionary, say the declination ('dec'), we would do it by putting the name of a dictionary and following it with the key related to the value we want to see. We will use this approach to extract and plot the mean dec, inc and $\alpha_{95}$ in the plot below.


In [20]:
mean['dec']


Out[20]:
45.288894569478941

Let's plot both the directions (using ipmag.plot_di) and the mean (using ipmag.plot_di_mean).


In [21]:
fignum = 1
plt.figure(num=fignum,figsize=(4,4),dpi=160)
ipmag.plot_net(fignum)
ipmag.plot_di(di_block=lots_of_directions)
ipmag.plot_di_mean(mean['dec'],mean['inc'],mean['alpha95'],color='r')
plt.show()


Calculating directions from the IGRF model using ipmag.igrf

Let's use another ipmag function to determine the field predicted by the IGRF model here in La Jolla over the past 100 hundred years.

*Before we do so, let's all open up ipmag.py in a text editor. Find the function ipmag.igrf* and report back what functions it uses (hint they are from the pmag.py module).

To determine the IGRF field at a bunch of different years we will first create a list of years using the numpy function np.linspace. We can then take these years along with the igrf function and the location of La Jolla to calculate the local direction through time using a for loop.


In [22]:
pmag.doigrf??

In [25]:
years = np.arange(1900,2020,1)

In [ ]:


In [26]:
years


Out[26]:
array([1900, 1901, 1902, 1903, 1904, 1905, 1906, 1907, 1908, 1909, 1910,
       1911, 1912, 1913, 1914, 1915, 1916, 1917, 1918, 1919, 1920, 1921,
       1922, 1923, 1924, 1925, 1926, 1927, 1928, 1929, 1930, 1931, 1932,
       1933, 1934, 1935, 1936, 1937, 1938, 1939, 1940, 1941, 1942, 1943,
       1944, 1945, 1946, 1947, 1948, 1949, 1950, 1951, 1952, 1953, 1954,
       1955, 1956, 1957, 1958, 1959, 1960, 1961, 1962, 1963, 1964, 1965,
       1966, 1967, 1968, 1969, 1970, 1971, 1972, 1973, 1974, 1975, 1976,
       1977, 1978, 1979, 1980, 1981, 1982, 1983, 1984, 1985, 1986, 1987,
       1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
       1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
       2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019])

In [36]:
field = ipmag.igrf([year,0,La_Jolla_lat,La_Jolla_lon])
field


Out[36]:
array([  1.14874557e+01,   5.79787820e+01,   4.61998094e+04])

In [32]:
local_field = []
local_field_intensity = []
La_Jolla_lat = 32.8328
La_Jolla_lon = -117.2713

for year in years:
    field = ipmag.igrf([year,0,La_Jolla_lat,La_Jolla_lon])
    local_field.append(field)
    local_field_intensity.append(field[2])

In [33]:
fignum = 1
plt.figure(num=fignum,figsize=(8,8),dpi=160)
ipmag.plot_net(fignum)
ipmag.plot_di(di_block=local_field,markersize=10,label='field since 1900 in La Jolla')
ipmag.plot_di(di_block=local_field[-2:],color='red',label='field today in La Jolla')
plt.legend()
plt.show()



In [34]:
plt.plot(years,local_field_intensity)


Out[34]:
[<matplotlib.lines.Line2D at 0x11407bc90>]

In [ ]: