Getting started¶
This “Getting started” tutorial is a brief introduction to Pymicra. This is in no way supposed to be a complete representation of everything that can be done with Pymicra.
In this tutorial we use some example data and refer to some example python scripts that can be downloaded here. These data and scripts are from a measurement campaign in a very small island (about 20 meters across) in a large artificial lake. At the time of these measurements the island was almost completely immersed into about 5 cm of water. Please feel free to explore both the example data and the example programs, as well as modify the programs for your own learning process!
Notation¶
Pymicra uses a specific notation to name each one of its columns. This notation is extremely important, because it is by these labels that Pymicra knows which variable is in each column. You can check the default notation with
In [1]: %%capture
...: import pymicra as pm
...: print(pm.notation)
...:
The output is too long to be reproduced here, but on the left you’ll see the full name of the variables (which corresponds to a notation namespace/attribute) and on the right you’ll see the default notation for that variable.
We recommend to use the default notation for the sake of simplicity, however,
you can change Pymicra’s notation at any time by altering the attributes of
pm.notation. For example, by default the notation for the mean is
'%s_mean', and every variable follows this base notation:
In [2]: pm.notation.mean
NameErrorTraceback (most recent call last)
<ipython-input-2-f467b081da4a> in <module>()
----> 1 pm.notation.mean
NameError: name 'pm' is not defined
In [3]: pm.notation.mean_u
NameErrorTraceback (most recent call last)
<ipython-input-3-26c02fa0b0aa> in <module>()
----> 1 pm.notation.mean_u
NameError: name 'pm' is not defined
In [4]: pm.notation.mean_h2o_mass_concentration
NameErrorTraceback (most recent call last)
<ipython-input-4-0bc2297ca326> in <module>()
----> 1 pm.notation.mean_h2o_mass_concentration
NameError: name 'pm' is not defined
To change this, you have to change the mean notation and then re-build the
whole notation with the build method:
In [5]: pm.notation.mean = 'm_%s'
NameErrorTraceback (most recent call last)
<ipython-input-5-3b9a5520351c> in <module>()
----> 1 pm.notation.mean = 'm_%s'
NameError: name 'pm' is not defined
In [6]: pm.notation.build()
NameErrorTraceback (most recent call last)
<ipython-input-6-64160d8c1e70> in <module>()
----> 1 pm.notation.build()
NameError: name 'pm' is not defined
In [7]: pm.notation.mean_u
NameErrorTraceback (most recent call last)
<ipython-input-7-26c02fa0b0aa> in <module>()
----> 1 pm.notation.mean_u
NameError: name 'pm' is not defined
In [8]: pm.notation.mean_h2o_mass_concentration
NameErrorTraceback (most recent call last)
<ipython-input-8-0bc2297ca326> in <module>()
----> 1 pm.notation.mean_h2o_mass_concentration
NameError: name 'pm' is not defined
In [9]: pm.notation.h2o='v'
NameErrorTraceback (most recent call last)
<ipython-input-9-6c16ab414fc4> in <module>()
----> 1 pm.notation.h2o='v'
NameError: name 'pm' is not defined
In [10]: pm.notation.build()
NameErrorTraceback (most recent call last)
<ipython-input-10-64160d8c1e70> in <module>()
----> 1 pm.notation.build()
NameError: name 'pm' is not defined
In [11]: pm.notation.mean_h2o_mass_concentration
NameErrorTraceback (most recent call last)
<ipython-input-11-0bc2297ca326> in <module>()
----> 1 pm.notation.mean_h2o_mass_concentration
NameError: name 'pm' is not defined
If you just want to change the notation of one variable, but not the full notation, just don’t re-build. For example:
In [12]: pm.notation.mean_co2_mass_concentration = 'c_m'
NameErrorTraceback (most recent call last)
<ipython-input-12-c7dd423c4bb8> in <module>()
----> 1 pm.notation.mean_co2_mass_concentration = 'c_m'
NameError: name 'pm' is not defined
In [13]: pm.notation.mean_co2_mass_concentration
NameErrorTraceback (most recent call last)
<ipython-input-13-619ef1eb3e68> in <module>()
----> 1 pm.notation.mean_co2_mass_concentration
NameError: name 'pm' is not defined
In [14]: pm.notation.mean_h2o_mass_concentration
NameErrorTraceback (most recent call last)
<ipython-input-14-0bc2297ca326> in <module>()
----> 1 pm.notation.mean_h2o_mass_concentration
NameError: name 'pm' is not defined
It is important to note that this changes the notation used throughout every Pymicra function. If, however, you want to use a different notation in a specific part of the program (in one specific function for example) you can create a Notation object and pass it to the function, such as
In [15]: mynotation = pm.Notation()
In [16]: mynotation.co2='c'
In [17]: mynotation.build()
In [18]: fluxes = pm.eddyCovariance(data, units, notation=mynotation) # For example
In the example above the default Pymicra notation is left untouched, and a separate notation is defined which is then used in a Pymicra function separately.
Creating file configurations file¶
The easiest way to read data files is using a fileConfig object. This object holds
the configuration of the data files so you can just call this object when reading these files.
To make it easier, Pymicra prefers to read this configurations from a file. That way
you can write the configurations for some data files once, store it into a configuration file
and then use it from then on every time you want to read those data files. That is what
Pymicra calls a “file configuration file”, or “config file” for short. From that
file, Pymicra can create a pymicra.fileConfig object. Consider, for example, the config
file below
description='datalogger configuration file for a lake. Located at examples/lake.config'
variables={
0:'%Y-%m-%d',
1:'%H:%M:%S.%f',
2:'u',
3:'v',
4:'w',
5:'theta_v',
6:'mrho_h2o',
7:'mrho_co2',
8:'p',
9:'theta'}
units={
'u':'m/s',
'v':'m/s',
'w':'m/s',
'theta_v':'celsius',
'mrho_co2':'mmol/m**3',
'mrho_h2o':'mmol/m**3',
'p':'kPa',
'theta':'celsius'
}
columns_separator=','
frequency=20
header_lines=None
filename_format='%Y%m%d-%H%M.csv'
date_cols = [0, 1]
First of all, note that the .config file is written in Python syntax, so it
has to be able to actually be run on python. This has to be true for all
.config files.
Furthermore, the extension of the file does not matter. We adopt the
.config extension for clarity, but it could be anything else.
The previous config file describes the data files in the directory
../examples/ex_data/. Here’s an example of one such file for comparison:
2013-11-08,10:00:00.000000,2.375,-5.206,-0.103,27.06,1238.0,14.675,99.19,30.43,-0.303,-0.274,-0.269,-0.261
2013-11-08,10:00:00.050000,2.4930000000000003,-5.098,-0.018000000000000002,27.12,1196.0,14.409,99.199,30.43,-0.308,-0.275,-0.271,-0.263
2013-11-08,10:00:00.100000,2.263,-5.114,0.014,27.11,1220.0,14.636,99.102,30.43,-0.306,-0.277,-0.273,-0.263
2013-11-08,10:00:00.150000,2.21,-5.235,-0.012,27.11,1238.0,14.688,99.154,30.43,-0.308,-0.277,-0.273,-0.264
2013-11-08,10:00:00.200000,2.158,-5.174,-0.112,27.12,1174.0,14.476,99.154,30.44,-0.31,-0.277,-0.273,-0.264
2013-11-08,10:00:00.250000,2.334,-5.279,-0.092,27.1,1195.0,14.671,99.154,30.43,-0.308,-0.278,-0.273,-0.265
2013-11-08,10:00:00.300000,2.396,-5.2970000000000015,0.005,27.15,1198.0,14.669,99.154,30.43,-0.309,-0.279,-0.272,-0.264
2013-11-08,10:00:00.350000,2.494,-5.246,0.039,27.13,1197.0,14.722,99.154,30.44,-0.311,-0.279,-0.273,-0.264
2013-11-08,10:00:00.400000,2.263,-5.317,-0.079,27.12,1202.0,14.709,99.154,30.43,-0.311,-0.279,-0.275,-0.265
2013-11-08,10:00:00.450000,2.135,-5.176,-0.036000000000000004,27.08,1202.0,14.731,99.154,30.44,-0.314,-0.279,-0.275,-0.267
Note that not all columns of this file are described. Columns that are not
described are also read but are discarded by default. You can change that using
only_named_columns=False in the timeSeries function.
We obtain the config object with
In [19]: fconfig = pm.fileConfig('../examples/lake.config')
NameErrorTraceback (most recent call last)
<ipython-input-19-2002138cada7> in <module>()
----> 1 fconfig = pm.fileConfig('../examples/lake.config')
NameError: name 'pm' is not defined
In [20]: print(fconfig)
NameErrorTraceback (most recent call last)
<ipython-input-20-b8202bc48f0a> in <module>()
----> 1 print(fconfig)
NameError: name 'fconfig' is not defined
Each variable defined in this file works as a keyword, since it can also be
input manually when calling pymicra.fileConfig(). Thus, for more
information, you can also use help(pymicra.fileConfig). Now we explain the
keywords one by one. In the next section we will explain how to use this object
for reading a data file.
description¶
The description is optional. It’s a string that serves only to better identify the config file you’re dealing with. It might useful for storage purposes and useful when printing the config object.
variables¶
The most important keyword is variables. This is a python dictionary where
each key is a column and its corresponding value is the variable in that
column. Note that we are using here the default notation to indicate which
variable is in which column. If a different notation is to be used here, then
you will have to define a new notation in your program (refer back to
Notation for that).
Note
From this point on, for simplicity, we will assume that the default notation is used.
It is imperative that the columns be named accordingly. For example, measuring
H2O contents in mmol/m^3 is different from measuring it in g/m^3 or mg/g. The
first is a molar density (moles per volume), the second is a mass density (mass
per volume) and the third is a mass concentration (mass per mass). In the
default notation these are indicated by the names 'mrho_h2o', 'rho_h2o'
and 'conc_h2o', respectively, and Pymicra needs to know which one is which.
Columns that contain parts of the timestamp have to have their name matching Python’s date format string directive, which themselves are the 1989 version default C standard format dates, which is common in many platforms.
This is useful only in case you want to index your data by timestamp, which is a huge advantage in some cases (check out what Pandas can do with timestamp-indexed data) but Pymicra can also work well without this. If you don’t wish to work with timestamps and want to work only by line number in each file, you can ignore these columns and indicate that you don’t want to parse dates. In fact, parsing of dates makes Pymicra a lot slower. Reading a file parsing its dates is about 5.5 times slower than reading the same file without parsing any dates!
units¶
The units keyword is also very important. It tells Pymicra in which units
each variable is being measured. Units are handled by Pint, so for more
details on how to define the units please refer to their documentation. Suffices
to say here that the format of the units are pretty intuitive. Some quick remarks
are
- prefer to define units unambiguously (
'g/(m*(s**2))'is generally preferred to'g/m/s**2', although both will work).- to define that a unit is dimensionless,
'1'will not work. Define it as'dimensionless'or'g/g'and so on.- if one variable does not have a unit (such as a sensor flag), you don’t have to include that variable.
- the keys of
unitsshould exactly match the values ofvariables.
columns_separator¶
The columns_separator keyword is what it sounds: what separates one column
from the other. Generally it is one character, such as a comma. A special case
happens is if the columns are separated by whitespaces of varying length, or
tabs. In that case it should be "whitespace".
frequency¶
The frequency keyword is the frequency of the data collection in Hertz.
header_lines¶
The keyword header_lines tells us which of the first lines are part of
the file header. If there is no header then is should be None. If there
are header lines than it should be a list or int. For example, if the first two
lines of the file are part of a header, it should be [0, 1]. If it were the
4 first lines, [0, 1, 2, 3] (range(4) would also be acceptable).
Header lines are not used by Pymicra and are therefore skipped.
filename_format¶
The filename_format keyword tells Pymicra how the data files are named.
date_cols¶
The date_cols keyword is optional. It is a list of integers that indicates
which of the columns are a part of the timestamp. If it’s not provided, then
Pymicra will assume that columns whose names have the character “%” in them are
part of the date and will try to parse them. If the default notation is used,
this should always be true.
Reading data¶
To read a data file or a list of data files we use the function timeSeries along with
a config file. Let us use the config file defined in the previous subsection with one of the data
file it describes:
In [21]: fname = '../examples/ex_data/20131108-1000.csv'
In [22]: fconfig = pm.fileConfig('../examples/lake.config')
NameErrorTraceback (most recent call last)
<ipython-input-22-2002138cada7> in <module>()
----> 1 fconfig = pm.fileConfig('../examples/lake.config')
NameError: name 'pm' is not defined
In [23]: data, units = pm.timeSeries(fname, fconfig, parse_dates=True)
NameErrorTraceback (most recent call last)
<ipython-input-23-93e03627fecc> in <module>()
----> 1 data, units = pm.timeSeries(fname, fconfig, parse_dates=True)
NameError: name 'pm' is not defined
In [24]: print(data)
NameErrorTraceback (most recent call last)
<ipython-input-24-dbd883db58b7> in <module>()
----> 1 print(data)
NameError: name 'data' is not defined
Note that data is a pandas.DataFrame object which contains the whole
data available in the datafile with each column being a variable. Since we
indicated that we wanted to parse the dates with the option
parse_dates=True, each row has its respective timestamp. If, otherwise, we
were to ignore the dates, the result would be a integer-indexed dataset:
In [25]: data2, units = pm.timeSeries(fname, fconfig, parse_dates=False)
NameErrorTraceback (most recent call last)
<ipython-input-25-4c621b7fee67> in <module>()
----> 1 data2, units = pm.timeSeries(fname, fconfig, parse_dates=False)
NameError: name 'pm' is not defined
In [26]: print(data2)
NameErrorTraceback (most recent call last)
<ipython-input-26-2f17186c4c10> in <module>()
----> 1 print(data2)
NameError: name 'data2' is not defined
And, as mentioned, the latter way is a lot faster:
In [27]: %timeit pm.timeSeries(fname, fconfig, parse_dates=False)
....: %timeit pm.timeSeries(fname, fconfig, parse_dates=True)
....:
NameErrorTraceback (most recent call last)
<ipython-input-27-bc0c5d8a249c> in <module>()
----> 1 get_ipython().magic(u'timeit pm.timeSeries(fname, fconfig, parse_dates=False)')
/home/docs/checkouts/readthedocs.org/user_builds/pymicra/envs/v0.3.0/local/lib/python2.7/site-packages/IPython/core/interactiveshell.pyc in magic(self, arg_s)
2158 magic_name, _, magic_arg_s = arg_s.partition(' ')
2159 magic_name = magic_name.lstrip(prefilter.ESC_MAGIC)
-> 2160 return self.run_line_magic(magic_name, magic_arg_s)
2161
2162 #-------------------------------------------------------------------------
/home/docs/checkouts/readthedocs.org/user_builds/pymicra/envs/v0.3.0/local/lib/python2.7/site-packages/IPython/core/interactiveshell.pyc in run_line_magic(self, magic_name, line)
2079 kwargs['local_ns'] = sys._getframe(stack_depth).f_locals
2080 with self.builtin_trap:
-> 2081 result = fn(*args,**kwargs)
2082 return result
2083
<decorator-gen-59> in timeit(self, line, cell)
/home/docs/checkouts/readthedocs.org/user_builds/pymicra/envs/v0.3.0/local/lib/python2.7/site-packages/IPython/core/magic.pyc in <lambda>(f, *a, **k)
186 # but it's overkill for just that one bit of state.
187 def magic_deco(arg):
--> 188 call = lambda f, *a, **k: f(*a, **k)
189
190 if callable(arg):
/home/docs/checkouts/readthedocs.org/user_builds/pymicra/envs/v0.3.0/local/lib/python2.7/site-packages/IPython/core/magics/execution.pyc in timeit(self, line, cell)
1055 number = 1
1056 for _ in range(1, 10):
-> 1057 time_number = timer.timeit(number)
1058 worst_tuning = max(worst_tuning, time_number / number)
1059 if time_number >= 0.2:
/home/docs/checkouts/readthedocs.org/user_builds/pymicra/envs/v0.3.0/local/lib/python2.7/site-packages/IPython/core/magics/execution.pyc in timeit(self, number)
137 gc.disable()
138 try:
--> 139 timing = self.inner(it, self.timer)
140 finally:
141 if gcold:
<magic-timeit> in inner(_it, _timer)
NameError: global name 'pm' is not defined
NameErrorTraceback (most recent call last)
<ipython-input-28-a473648643e0> in <module>()
----> 1 get_ipython().magic(u'timeit pm.timeSeries(fname, fconfig, parse_dates=True)')
/home/docs/checkouts/readthedocs.org/user_builds/pymicra/envs/v0.3.0/local/lib/python2.7/site-packages/IPython/core/interactiveshell.pyc in magic(self, arg_s)
2158 magic_name, _, magic_arg_s = arg_s.partition(' ')
2159 magic_name = magic_name.lstrip(prefilter.ESC_MAGIC)
-> 2160 return self.run_line_magic(magic_name, magic_arg_s)
2161
2162 #-------------------------------------------------------------------------
/home/docs/checkouts/readthedocs.org/user_builds/pymicra/envs/v0.3.0/local/lib/python2.7/site-packages/IPython/core/interactiveshell.pyc in run_line_magic(self, magic_name, line)
2079 kwargs['local_ns'] = sys._getframe(stack_depth).f_locals
2080 with self.builtin_trap:
-> 2081 result = fn(*args,**kwargs)
2082 return result
2083
<decorator-gen-59> in timeit(self, line, cell)
/home/docs/checkouts/readthedocs.org/user_builds/pymicra/envs/v0.3.0/local/lib/python2.7/site-packages/IPython/core/magic.pyc in <lambda>(f, *a, **k)
186 # but it's overkill for just that one bit of state.
187 def magic_deco(arg):
--> 188 call = lambda f, *a, **k: f(*a, **k)
189
190 if callable(arg):
/home/docs/checkouts/readthedocs.org/user_builds/pymicra/envs/v0.3.0/local/lib/python2.7/site-packages/IPython/core/magics/execution.pyc in timeit(self, line, cell)
1055 number = 1
1056 for _ in range(1, 10):
-> 1057 time_number = timer.timeit(number)
1058 worst_tuning = max(worst_tuning, time_number / number)
1059 if time_number >= 0.2:
/home/docs/checkouts/readthedocs.org/user_builds/pymicra/envs/v0.3.0/local/lib/python2.7/site-packages/IPython/core/magics/execution.pyc in timeit(self, number)
137 gc.disable()
138 try:
--> 139 timing = self.inner(it, self.timer)
140 finally:
141 if gcold:
<magic-timeit> in inner(_it, _timer)
NameError: global name 'pm' is not defined
Viewing and manipulating data¶
To view and manipulate data, mostly you have to follow Pandas’s DataFrame rules. For that we suggest that the user visit a Pandas tutorial. However, I’ll explain some main ideas here for the sake of completeness and introduce some few ideas specific for Pymicra that don’t exist for general Pandas DataFrames.
Printing and plotting¶
First, for viewing raw data on screen there’s printing. Slicing and indexing are supported by Pandas, but without support for units:
In [29]: print(data['theta_v'])
NameErrorTraceback (most recent call last)
<ipython-input-29-e94992a74455> in <module>()
----> 1 print(data['theta_v'])
NameError: name 'data' is not defined
In [30]: print(data[['u', 'v', 'w']])
NameErrorTraceback (most recent call last)
<ipython-input-30-1c17a554e0d5> in <module>()
----> 1 print(data[['u', 'v', 'w']])
NameError: name 'data' is not defined
In [31]: print(data['20131108 10:15:00.000':'20131108 10:17:00.000'])
NameErrorTraceback (most recent call last)
<ipython-input-31-b15ec8bdb617> in <module>()
----> 1 print(data['20131108 10:15:00.000':'20131108 10:17:00.000'])
NameError: name 'data' is not defined
Note that Pandas “guesses” if the argument you pass ('theta_v' or
'2013-11-08 10:15:00' etc.) is a column indexer or a row indexer. To use
these unambiguously, use the .loc method as
In [32]: print(data.loc['2013-11-08 10:15:00':'2013-11-08 10:17:00', ['u','v','w']])
NameErrorTraceback (most recent call last)
<ipython-input-32-e4fccd621429> in <module>()
----> 1 print(data.loc['2013-11-08 10:15:00':'2013-11-08 10:17:00', ['u','v','w']])
NameError: name 'data' is not defined
This method is actually preferred and you can find more information on this topic here.
To view these data with units, you can use the .with_units() method.
The previous output would look like this using units:
In [33]: print(data.with_units(units)['theta_v'])
NameErrorTraceback (most recent call last)
<ipython-input-33-f205c87ca716> in <module>()
----> 1 print(data.with_units(units)['theta_v'])
NameError: name 'data' is not defined
In [34]: print(data.with_units(units)[['u', 'v', 'w']])
NameErrorTraceback (most recent call last)
<ipython-input-34-194962d4a60c> in <module>()
----> 1 print(data.with_units(units)[['u', 'v', 'w']])
NameError: name 'data' is not defined
In [35]: print(data.with_units(units)['2013-11-08 10:15:00'])
NameErrorTraceback (most recent call last)
<ipython-input-35-2ce7f3367470> in <module>()
----> 1 print(data.with_units(units)['2013-11-08 10:15:00'])
NameError: name 'data' is not defined
Warning
Note that, although this method returns a Pandas DataFrame, it is not meant for calculations. Currently the DataFrame it returns is meant for visualization purposes only!
We can also plot the data on screen so we can view it interactively. This can be done directly from the DataFrame with
In [36]: from matplotlib import pyplot as plt
In [37]: data[['u', 'v', 'w']].plot()
NameErrorTraceback (most recent call last)
<ipython-input-37-112e9fb6c73e> in <module>()
----> 1 data[['u', 'v', 'w']].plot()
NameError: name 'data' is not defined
In [38]: plt.show()
Using the plt.show() command, the plot above would plot interactively. If
we had used plt.savefig('figure.png') instead, it would have saved the
figure as png. For more on plotting, you can checkout Pandas’s visualization
guide and
find out ways to make this plot look nicer, how to render it with LaTeX and
some more tricks.
Pymicra also has an .xplot method, which brings a little more options to
Pandas’s .plot() method.
Todo
give xplot examples
Converting units¶
You can manually convert between units using the contents from Manipulating
and the Pint package. But Pymicra has a very useful method to do this called .convert_cols (more exist,
but let’s focus on this one).
Let’s, for example, convert some units:
In [39]: conversions = {'p':'pascal', 'mrho_h2o':'mole/m^3', 'theta_v':'kelvin'}
In [40]: print(data.convert_cols(conversions, units, inplace_units=False))
NameErrorTraceback (most recent call last)
<ipython-input-40-06dba93f4e84> in <module>()
----> 1 print(data.convert_cols(conversions, units, inplace_units=False))
NameError: name 'data' is not defined
Note that the units dictionary is updated automatically if the
inplace_units keyword is true. The default is false for safety reasons, but
passing this keyword as true is much simpler and compact:
In [41]: conversions = {'theta':'kelvin', 'theta_v':'kelvin'}
In [42]: data = data.convert_cols(conversions, units, inplace_units=True)
NameErrorTraceback (most recent call last)
<ipython-input-42-223bb8a15e35> in <module>()
----> 1 data = data.convert_cols(conversions, units, inplace_units=True)
NameError: name 'data' is not defined
In [43]: print(data.with_units(units))
NameErrorTraceback (most recent call last)
<ipython-input-43-8a66647eea32> in <module>()
----> 1 print(data.with_units(units))
NameError: name 'data' is not defined
Manipulating¶
Manipulating data is pretty intuitive with Pandas. For example
In [44]: data['rho_air'] = data['p']/(287.058*data['theta_v'])
NameErrorTraceback (most recent call last)
<ipython-input-44-2190c3db6903> in <module>()
----> 1 data['rho_air'] = data['p']/(287.058*data['theta_v'])
NameError: name 'data' is not defined
In [45]: print(data['rho_air'])
NameErrorTraceback (most recent call last)
<ipython-input-45-efd54506c8a9> in <module>()
----> 1 print(data['rho_air'])
NameError: name 'data' is not defined
If, however, you’re not familiar with Pandas and prefer to just stick with what
you know, you can get Numpy arrays from columns using the .values
attribute:
In [46]: P = data['p'].values
NameErrorTraceback (most recent call last)
<ipython-input-46-7834b8aa0781> in <module>()
----> 1 P = data['p'].values
NameError: name 'data' is not defined
In [47]: Tv = data['theta_v'].values
NameErrorTraceback (most recent call last)
<ipython-input-47-25320c940518> in <module>()
----> 1 Tv = data['theta_v'].values
NameError: name 'data' is not defined
In [48]: print(type(Tv))
NameErrorTraceback (most recent call last)
<ipython-input-48-d89e463e125b> in <module>()
----> 1 print(type(Tv))
NameError: name 'Tv' is not defined
In [49]: rho_air = P/(287.058*Tv)
NameErrorTraceback (most recent call last)
<ipython-input-49-818b77efd261> in <module>()
----> 1 rho_air = P/(287.058*Tv)
NameError: name 'P' is not defined
In [50]: print(rho_air)
NameErrorTraceback (most recent call last)
<ipython-input-50-c111f225b951> in <module>()
----> 1 print(rho_air)
NameError: name 'rho_air' is not defined
In [51]: print(type(rho_air))
NameErrorTraceback (most recent call last)
<ipython-input-51-a6bdff633dbb> in <module>()
----> 1 print(type(rho_air))
NameError: name 'rho_air' is not defined
Doing that you can step out of Pandas and do your own calculations using your own Python or Numpy code. This is pretty advantageous if you have a lot of routines that are already written in your own way.