In [ ]:



# Handling Data over time¶

There's a widespread trend in solar physics at the moment for correlation over actual science, so being able to handle data over time spans is a skill we all need to have. Python has ample support for this so lets have a look at what we can use.

## Learning Objectives

• Understand and use SunPy lightcurve.
• Create a pandas dataframe.
• Utilise the datetime package
• Use the pandas dataframe to plot the data within it.

## SunPy Lightcurve¶

SunPy provides a lightcurve object to handle this type of time series data. The module has a number of instruments associated with it, including:

• GOES XRS LightCurve
• SDO EVE LightCurve for level 0CS data
• Proba-2 LYRA LightCurve
• NOAA Solar Cycle monthly indices.
• RHESSI X-ray Summary LightCurve.

We're going to examine the lightcurves created by a solar flare on June 7th 2011.

Lets begin with the import statements:

In [2]:
from __future__ import print_function, division
import numpy as np
import sunpy
from sunpy import lightcurve as lc
import matplotlib.pyplot as plt
%matplotlib inline

import warnings
warnings.filterwarnings('ignore')


Now lets create some lightcurves

In [4]:
goes_lightcurve =  lc.GOESLightCurve.create('2011-06-07 06:00', '2011-06-07 08:00')
hsi_lightcurve = lc.RHESSISummaryLightCurve.create('2011-06-07 06:00', '2011-06-07 08:00')


In terms of LYRA, the server only allows you to download an entire day of data at a time. We can match this to the rest of the data by using the truncate function.

In [5]:
lyra_lightcurve_fullday = lc.LYRALightCurve.create('2011-06-07')
lyra_lightcurve = lyra_lightcurve_fullday.truncate('2011-06-07 06:00', '2011-06-07 08:00')


Part of the advantage of using these inbuilt functions we can get a quicklook at our data using short commands:

In [6]:
fig = goes_lightcurve.peek()
fig = lyra_lightcurve.peek()


### Accessing and using the data¶

More custom plots can be made easily by accessing the data in the lightcurve functionality. Both the time information and the data are contained within the lightcurve.data code, which is a pandas dataframe. We can see what data is contained in the dataframe by finding which keys it contains and also asking what's in the meta data:

In [7]:
print(lyra_lightcurve.data.keys())

Index([u'CHANNEL1', u'CHANNEL2', u'CHANNEL3', u'CHANNEL4'], dtype='object')

In [8]:
print(lyra_lightcurve.meta)

OrderedDict([('SIMPLE', True), ('BITPIX', 8), ('NAXIS', 0), ('EXTEND', True), ('ORIGIN', 'ROB'), ('TELESCOP', 'PROBA2'), ('INSTRUME', 'LYRA'), ('OBJECT', 'EUV solar irrad'), ('OBS_MODE', 'standard'), ('DATE', '2015-12-16'), ('DATE-OBS', '2011-06-07T00:00:00.010000'), ('DATE-END', '2011-06-07T23:59:59.988995'), ('DATASRC', 'Redu'), ('LEVEL', '2'), ('ALGOR_V', 'EDG=2.1  BSDG=1.0'), ('FILENAME', 'lyra_20110607-000000_lev2_std.fits')])


Notice that the meta data information is stored in something called OrderedDict

## On Dictionaries

We can create keyword-data pairs to form a dictionary (shock horror) of values. In this case we have defined some strings and number to represent temperatures across europe
temps = {'Brussles': 9, 'London': 3, 'Barcelona': 13, 'Rome': 16}
temps['Rome']
16

We can also find out what keywords are associated with a given dictionary, In this case:
temps.keys()
dict_keys(['London', 'Barcelona', 'Rome', 'Brussles'])


We can use these keys to plot specific parameters from the lightcurve, Aluminium is 'CHANNEL3' and Zirconium is 'CHANNEL4'. These measurements are taken on a instuments which detect events at different energy levels.

In [9]:
plt.figure(1, figsize=(10,5))
plt.plot(lyra_lightcurve.data.index, lyra_lightcurve.data['CHANNEL3'], color='b')
plt.plot(lyra_lightcurve.data.index, lyra_lightcurve.data['CHANNEL4'], color='r')
plt.ylabel('Flux (Wm^2)')
plt.show()


### Analysing Lightcurve data¶

We can asses the degree to which the lyra curves correlate with each other:

In [10]:
cross_correlation = np.correlate(lyra_lightcurve.data['CHANNEL3'],
lyra_lightcurve.data['CHANNEL4'])
print(cross_correlation)

[ 1.01648024]


## Pandas¶

In its own words Pandas is a Python package providing fast, flexible, and expressive data structures designed to make working with “relational” or “labeled” data both easy and intuitive. Pandas has two forms of structures, 1D series and 2D dataframe. It also has its own functions associated with it.

It is also amazing.

Lightcurve uses these in built Pandas functions, so we can find out things like the maximum of curves:

In [11]:
# max time argument taken from long and short GOES channels
# max_time argument taken from channel 3 & 4 LYRA channels
max_t_goes_long = goes_lightcurve.data['xrsb'].idxmax()
max_t_goes_short = goes_lightcurve.data['xrsa'].idxmax()

max_t_lyra_al = lyra_lightcurve.data['CHANNEL3'].idxmax()
max_t_lyra_zr = lyra_lightcurve.data['CHANNEL4'].idxmax()

print('GOES max values', max_t_goes_long, max_t_goes_short)
print('LYRA max values', max_t_lyra_al, max_t_lyra_zr)

GOES max values 2011-06-07 06:41:24.118999 2011-06-07 06:39:00.761999
LYRA max values 2011-06-07 06:44:47.915000 2011-06-07 06:44:44.464880


So lets plot them on the graph

In [15]:
# create figure with raw curves
# max lines
plt.figure(1, figsize=(10,5))
plt.plot(lyra_lightcurve.data.index, lyra_lightcurve.data['CHANNEL3'], color='b', linestyle='--')
plt.plot(lyra_lightcurve.data.index, lyra_lightcurve.data['CHANNEL4'], color='r', linestyle=':')
plt.ylabel('Flux (Wm^2)')

# max lines
plt.axvline(max_t_lyra_al, color='b', linestyle='--', linewidth=2)
plt.axvline(max_t_lyra_zr, color='r', linestyle='--')
plt.axvline(max_t_goes_long, color='g', linestyle='--', linewidth=2)
plt.show()


Now we have seen a little of what Pandas can do, lets read in some of our own data. In this case we are going to use data from Bennett et al. 2015, ApJ, a truly ground breaking work. Now the data we are reading in here is a structured Array.

In [16]:
data_ms = np.genfromtxt('data/macrospicules.csv', skip_header=1, dtype=None, delimiter=',')


Now, the above line imports information on some solar features over a sample time period. Specifically we have, maximum length, lifetime and time at which they occured. Now if we type data[0] what will happen?

In [17]:
data_ms[0]

Out[17]:
(27.022617088020528, 13.6, '2010-06-01T13:00:14.120000')

This is the first row of the array, containing the first element of our three properties. This particular example is a stuctured array, so the columns and rows can have properties and assign properties to the header. We can ask what the title of these columns is by using a dtype command:

In [19]:
data_ms.dtype.names

Out[19]:
('f0', 'f1', 'f2')

Unhelpful, so lets give them something more recognisable. We can use the docs to look up syntax and change the names of the column lables.

So the docs are [here](http://docs.scipy.org/doc/numpy-1.10.0/reference/generated/numpy.genfromtxt.html). Find the syntax to change to names to better to represent maximum length, lifetime and point in time which they occured.
In [20]:
data_ms.dtype.names = ('max_len', 'ltime', 'sample_time')
data_ms['max_len']

Out[20]:
array([ 27.02261709,  36.20809658,  62.93289752,  38.97054949,
53.58942032,  30.6401107 ,  34.62323773,  25.76578452,
42.55229885,  43.78096232,  32.07478058,  46.32895236,
41.81948071,  36.15639728,  27.76449747,  28.36338204,
46.24264885,  31.66963787,  37.98509124,  41.10763789,
36.31153664,  63.94515322,  33.20603032,  45.12547627,
45.59984305,  44.13747471,  39.05135355,  42.70997285,
22.00943851,  45.70103315,  40.61460622,  53.58952877,
33.55068528,  34.12704163,  28.84501455,  33.50857898,
33.04991294,  43.14772776,  64.7263967 ,  58.4113328 ,
26.51897508,  38.16891551,  53.91004427,  38.66085552,
27.32363074,  34.82350067,  49.29044968,  44.55780869,
30.01404343,  33.79223954,  37.02116485,  28.72061961,
29.21863497,  55.72629452,  54.57759503,  45.33884703,
50.69244379,  33.25632341,  37.73000783,  26.92855622,
52.49096835,  63.49966052,  36.13680388,  61.63887853,
44.4662083 ,  29.52452638,  43.23969955,  41.65026311,
52.16598344,  42.67412936,  41.81910611,  34.49493977,
35.78882006,  45.59188682,  39.26216985,  35.10139159,
38.14667516,  46.09430341,  50.44398261,  46.41930315,
43.99951416,  31.10082419,  45.43674785,  38.78414481,
36.03072435,  39.52956702,  28.94948495,  36.16831602,
54.90157329,  49.35714339,  45.9207131 ,  36.33602522,
47.81325513,  30.02565172,  22.4376017 ,  25.77671126,
22.09750136,  51.10043568,  52.13571082,  35.70298287,
34.73403574,  40.74477779,  38.34861845,  22.82335936,
27.30678373,  27.42834706,  23.27232254,  29.83005671,
36.08121426,  50.04105014,  33.14161453,  29.2621644 ,
26.55148777,  36.15467202,  26.06766701,  27.37302807,
30.56321175,  26.83143584,  37.11331356,  30.79380358,
32.89179738,  28.89730285,  33.0527976 ,  25.57069612,
44.20414097,  28.68038005,  25.11419547,  23.78793994,
26.60399083,  36.72695416,  44.35566025,  41.37507269,
31.08485597,  39.71759583,  47.36372856,  42.72431429,
30.49807689,  37.4604915 ,  39.65240926,  37.26885237,
41.50380626,  29.8313709 ,  43.02721083,  33.23966863,
28.73848974,  41.28193776,  44.80971415,  50.10792885,
37.79992144,  54.59165111,  31.60523881,  36.31252683,
44.25298922,  51.02121661,  34.20351256,  39.24552078,
43.71189706,  36.40843056,  34.02240796,  39.27977921,
54.66979248,  65.7384905 ,  53.01413049,  34.17031127,
47.00239714,  17.32168005,  44.68585728,  29.44389171,
40.80497941,  34.6572607 ,  42.62526043,  37.36422913,
31.17786476,  28.12867393,  30.40163346,  30.51526168,
35.9876376 ,  23.08802156,  40.76121653,  21.0614616 ,
37.30928468,  33.74493288,  23.37625041,  23.26285756,
21.90478831,  31.46692441,  24.02288547,  32.79270784,
30.07317007,  29.7039241 ,  34.13671581,  50.58575418,
34.97447555,  24.51408577,  48.26530071,  41.1800655 ,
38.59687577,  28.32914516,  26.86404795,  29.09491492,
22.1925731 ,  26.6573342 ,  34.45652454,  29.52441516,
26.05330498,  16.91583914,  24.09964195,  27.83367552,
21.83934023,  24.08621306,  21.4539239 ,  50.23369701,
22.20207407,  24.5242085 ,  28.29914756,  25.40145715,
35.59277051,  32.59279863,  31.24484412,  46.45496714,
25.81684312,  23.82663323,  25.75515713,  27.49177445,
38.48352531,  29.50744816,  54.12496571,  40.63961711,
37.23678458,  34.68878712,  31.37594022,  26.97844296,
38.23975554,  38.90287314,  24.01076136,  37.26779816,
35.0705135 ,  29.1850186 ,  40.49388844,  33.4466624 ,
28.94498308,  22.75986112,  32.27371125,  27.51808194,
45.9195814 ,  37.40509992,  36.5449928 ,  44.1242809 ,
41.54289686,  40.40254961,  33.47264368,  34.01641674,
37.52700525,  44.02589254,  40.08500945,  29.29270305,
41.57391536,  44.2470371 ,  55.54916983])

### DataFrame¶

Now a pandas DataFrame takes two arguments as a minimum, index and data. In this case the index will be our time within the sample and the maximum length and lifetime will be our data. So lets import pandas and use the dataframe:

Pandas reads a dictionary when we want to input multiple data columns. Therefore we need to make a dictionary of our data and read that into a pandas data frame. First we need to import pandas.

## Dictionaries

So we covered dictionaries earlier. We can create keyword data pairs to form a dictionary (shock horror) of values. In this case
temps = {'Brussles': 9, 'London': 3, 'Barcelona': 13, 'Rome': 16}
temps['Rome']
16

We can also find out what keywords are associated with a given dictionary, In this case:
temps.keys()
dict_keys(['London', 'Barcelona', 'Rome', 'Brussles'])


First, let's import Pandas:

In [22]:
import pandas as pd

d = {'max_len':data_ms['max_len'], 'ltime':data_ms['ltime']}

df = pd.DataFrame(data=d, index=data_ms['sample_time'])

df.index

Out[22]:
Index([u'2010-06-01T13:00:14.120000', u'2010-06-01T12:58:02.120000',
u'2010-06-15T12:55:02.110000', u'2010-07-07T12:23:50.110000',
u'2010-07-07T13:28:50.120000', u'2010-07-15T12:12:02.130000',
u'2010-07-15T12:19:02.110000', u'2010-07-24T12:09:50.120000',
u'2010-08-01T13:27:14.120000', u'2010-08-07T12:37:44.120000',
...
u'2014-11-01T12:29:31.130000', u'2014-11-15T13:28:19.140000',
u'2014-12-01T13:05:55.120000', u'2014-12-01T13:46:55.140000',
u'2014-12-07T12:20:55.140000', u'2014-12-07T13:11:07.120000',
u'2014-12-15T12:07:19.130000', u'2014-12-15T12:41:19.130000',
u'2014-12-15T13:13:19.130000', u'2014-12-24T13:14:55.120000'],
dtype='object', length=259)

## Datetime Objects¶

Notice that the time for the sample is in a strange format. It is a string containing the date in YYYY-MM-DD and time in HH-MM-SS-mmmmmm. These datetime objects have their own set of methods associated with them. Python appreciates that theses are built this way and can use them for the indexing easily.

We can use this module to create date objects (representing just year, month, day). We can also get information about universal time, such as the time and date today.

NOTE: Datetime objects are NOT strings. They are objects which print out as strings.

In [24]:
import datetime
print(datetime.datetime.now())
print(datetime.datetime.utcnow())

lunchtime = datetime.time(12,30)
the_date = datetime.date(2005, 7, 13)
dinner = datetime.datetime.combine(the_date, lunchtime)
print('When is coffee? {}'.format(datetime.datetime.now()))

#dt_obj = datetime.datetime.strptime()

2016-01-15 10:46:44.996775
2016-01-15 10:46:44.996924
When is coffee? 2016-01-15 10:46:44.997269


Looking back at when we discussed the first element of data, and the format of the time index was awkward to use so lets do something about that.

In [25]:
df.index[0]

Out[25]:
'2010-06-01T13:00:14.120000'

This is a string and python will just treat it as such. We need to use datetime to pick this string appart and change it into an oject we can use.

To the Docs!

So we use the formatting commands to match up with the string we have.

In [28]:
dt_obj = datetime.datetime.strptime(df.index[0], '%Y-%m-%dT%H:%M:%S.%f')
print(dt_obj)
print(type(dt_obj))

2010-06-01 13:00:14.120000
<type 'datetime.datetime'>


Now the next logical step would be to make a for loop and iterate over the index and reassign it. HOWEVER there is almost always a better way. And Pandas has a to_dateime() method that we can feed the index:

In [35]:
df.index = pd.to_datetime(df.index)
df

Out[35]:
ltime max_len
2010-06-01 13:00:14.120 13.600000 27.022617
2010-06-01 12:58:02.120 8.400000 36.208097
2010-06-15 12:55:02.110 24.199833 62.932898
2010-07-07 12:23:50.110 22.999667 38.970549
2010-07-07 13:28:50.120 21.799833 53.589420
2010-07-15 12:12:02.130 17.400167 30.640111
2010-07-15 12:19:02.110 12.800000 34.623238
2010-07-24 12:09:50.120 14.200000 25.765785
2010-08-01 13:27:14.120 24.400000 42.552299
2010-08-07 12:37:44.120 15.400000 43.780962
2010-08-15 13:10:32.120 15.199833 32.074781
2010-08-24 12:51:44.120 18.599833 46.328952
2010-08-24 13:22:20.120 15.200000 41.819481
2010-09-01 12:43:44.120 18.800167 36.156397
2010-09-15 12:21:20.120 17.200000 27.764497
2010-09-15 12:26:08.120 20.200000 28.363382
2010-09-15 12:33:44.120 18.800167 46.242649
2010-09-15 13:06:32.130 18.999833 31.669638
2010-09-24 12:36:56.120 18.400000 37.985091
2010-10-15 12:32:08.120 17.799833 41.107638
2010-10-24 12:37:08.130 20.399500 36.311537
2010-11-01 12:43:08.130 26.599833 63.945153
2010-11-01 12:55:20.130 15.999833 33.206030
2010-11-07 12:25:20.120 20.000000 45.125476
2010-11-07 13:18:08.120 12.000000 45.599843
2010-11-15 12:10:08.130 15.000000 44.137475
2010-11-15 12:14:44.140 15.199833 39.051354
2010-12-01 13:45:20.140 22.400000 42.709973
2010-12-07 12:09:08.120 12.800000 22.009439
2010-12-15 12:17:08.130 25.400000 45.701033
... ... ...
2014-08-01 12:55:31.130 15.399833 34.688787
2014-08-07 12:13:31.130 18.800167 31.375940
2014-08-15 12:09:31.120 16.600000 26.978443
2014-08-15 12:39:07.120 22.000000 38.239756
2014-08-15 13:28:55.120 21.400000 38.902873
2014-08-24 12:36:43.130 17.600333 24.010761
2014-08-24 13:04:55.130 25.800000 37.267798
2014-08-24 13:31:19.120 16.200167 35.070513
2014-09-01 12:31:07.130 15.200167 29.185019
2014-09-01 12:49:31.130 35.600333 40.493888
2014-09-07 13:13:43.120 14.600000 33.446662
2014-09-07 13:26:55.120 13.200000 28.944983
2014-09-07 13:48:19.130 18.799833 22.759861
2014-09-15 12:44:43.120 15.000333 32.273711
2014-09-15 13:24:55.140 18.400000 27.518082
2014-09-24 12:48:19.130 19.200000 45.919581
2014-10-01 12:41:07.130 21.000000 37.405100
2014-10-01 12:58:19.120 13.200000 36.544993
2014-10-07 12:39:55.130 21.800000 44.124281
2014-10-24 12:10:43.130 18.399833 41.542897
2014-11-01 12:29:31.130 21.600000 40.402550
2014-11-15 13:28:19.140 10.799833 33.472644
2014-12-01 13:05:55.120 14.400000 34.016417
2014-12-01 13:46:55.140 15.400000 37.527005
2014-12-07 12:20:55.140 19.399667 44.025893
2014-12-07 13:11:07.120 13.200000 40.085009
2014-12-15 12:07:19.130 13.400000 29.292703
2014-12-15 12:41:19.130 13.200000 41.573915
2014-12-15 13:13:19.130 17.800167 44.247037
2014-12-24 13:14:55.120 16.999667 55.549170

259 rows × 2 columns

Much easier. Note that the format of table has now changed and are pandas specific datetime objects, and looks like this:

In [36]:
print(df.index[0])

2010-06-01 13:00:14.120000


This means we can bin data according to time

In [41]:
len_bins = pd.groupby(df['max_len'], by=[df.index.year, df.index.month])
print(len(len_bins))

54


Here we have used the groupby command to take the 'max_len' column, called as a dictionary key, and create bins for our data to sit in according to year and then month.

The object l_bins has mean, max, std etc. attributes in the same way as the numpy arrays we handled the other day.

In [46]:
len_means = len_bins.mean()
print(len_means)
len_std = len_bins.std()
print(len_std)

2010  6     42.054537
7     36.717821
8     41.311295
9     34.696942
10    38.709587
11    45.177555
12    40.924916
2011  1     41.170836
2     38.385196
3     37.007258
4     45.966302
5     39.049844
7     45.736577
8     42.089144
9     37.181781
10    45.276066
11    39.070391
12    34.882456
2012  1     50.059810
2     32.477849
3     39.154133
4     32.305885
5     31.951032
6     30.973616
7     28.897303
8     30.068358
9     36.644022
10    39.539804
11    36.201343
12    35.001790
2013  1     45.718231
2     33.958883
3     44.252989
4     41.490083
5     38.047579
6     53.229354
7     44.728946
8     33.382734
9     37.055785
10    31.258302
11    28.063602
12    32.474516
2014  1     42.680747
2     26.620170
3     25.922509
4     31.924611
5     27.203932
6     30.948541
7     38.049466
8     33.752406
9     32.567724
10    39.904318
11    36.937597
12    40.789644
Name: max_len, dtype: float64
2010  6     18.655367
7     10.618364
8      5.440305
9      6.979722
10     3.391356
11    10.337633
12    11.664923
2011  1     13.310975
2     10.294977
3      9.966492
4      9.281308
5     12.832214
7     12.569426
8      6.505276
9      2.942115
10     5.148206
11     5.866478
12     5.405979
2012  1      4.531475
2     10.022291
3     12.585824
4      8.614694
5      8.301316
6      4.185172
7           NaN
8      7.679454
9      6.678510
10     6.273834
11     5.908986
12     7.305525
2013  1      6.730764
2      3.328555
3           NaN
4      8.630605
5      5.048431
6     13.288040
7      9.625425
8     10.699844
9      5.729928
10     3.339021
11     7.889644
12     7.797334
2014  1      5.005861
2      3.093437
3      5.225323
4     15.910663
5      5.172536
6      8.333880
7     10.603654
8      5.246553
9      7.447101
10     3.560158
11     4.900183
12     7.838396
Name: max_len, dtype: float64


Lets not forget that l_bins is a list of bins so when we print out l_mean we get:

In [ ]:



Now we have all this data we can build a lovely bargraph with error bars and wonderful things like that.

Remember, these pandas objects have functions associated with them, and one of them is a plot command.

In [59]:
fig, ax = plt.subplots(1, figsize=(15,5))
len_means.plot(kind='bar', ax=ax, yerr=len_std)
fig.autofmt_xdate()
plt.show()


Note that the date on the x-axis is a little messed up we can fix with fig.autofmt_xdate()

## How do the lifetimes change?

Now that we have the plot for the maximum length, now make a bar graph of the lifetimes of the features.
In [ ]:



## Exoplanet Data

Now, to all the astronomers out there, let us process some real data. We have some txt files containing the lightcurve from a recent paper. Can you process the data and show us the planet? HINT: You'll need to treat this data slightly differently. The date here is in Julian Day so you will need to use [these](http://docs.astropy.org/en/v1.1.1/api/astropy.time.Time.html) docs to convert it to a sensible datetime object, before you make the DataFrame.
XO1_wl_transit_FLUX.txt
• col1 - Julian Date
• col2 - Flux
• col3 - Error on Flux
• col4 - RAW Flux
• col5 - RAW Error on flux

In [60]:
# load in the file using numpyloadtext
import numpy as np

In [61]:
# read in a dictionary
ep_dict = {'flux':ep_data[:,1], 'err_flux':ep_data[:,2]}

In [62]:
ep_df = pd.DataFrame(data=ep_dict, index=ep_data[:,0])
ep_df.index = pd.to_datetime(ep_df.index)

In [64]:
from astropy.time import Time
t = Time(ep_data[:, 0], format='jd')
UTC = t.datetime

In [67]:
ep_df.index = UTC
ep_df

Out[67]:
err_flux flux
2011-09-30 04:17:53.324159 0.000514 1.000044
2011-09-30 04:19:46.335374 0.000514 1.000107
2011-09-30 04:21:39.320640 0.000514 1.000036
2011-09-30 04:23:32.331855 0.000514 1.000133
2011-09-30 04:25:25.325771 0.000514 1.000100
2011-09-30 04:27:18.336946 0.000514 1.000345
2011-09-30 04:29:11.322252 0.000514 0.999863
2011-09-30 04:31:04.333427 0.000514 1.000216
2011-09-30 04:32:57.327342 0.000514 1.000233
2011-09-30 04:40:29.328954 0.000514 1.000665
2011-09-30 05:25:29.328954 0.000514 0.999732
2011-09-30 05:27:22.331520 0.000514 1.000129
2011-09-30 05:29:15.325435 0.000514 0.999950
2011-09-30 05:31:08.336651 0.000514 1.000162
2011-09-30 05:33:01.321916 0.000514 1.000086
2011-09-30 05:34:54.333132 0.000514 1.000284
2011-09-30 05:36:47.327047 0.000514 0.999538
2011-09-30 05:38:40.329612 0.000514 0.999926
2011-09-30 05:40:33.323528 0.000514 0.999636
2011-09-30 05:42:26.334703 0.000514 0.999515
2011-09-30 05:44:19.328659 0.000514 0.999927
2011-09-30 05:46:12.331184 0.000514 0.999824
2011-09-30 05:48:05.325140 0.000514 0.999906
2011-09-30 05:49:58.336315 0.000514 1.000277
2011-09-30 05:51:51.321580 0.000514 1.000037
2011-09-30 05:53:44.332796 0.000514 0.999905
2011-09-30 05:55:37.326711 0.000514 1.000126
2011-09-30 05:57:30.329277 0.000514 1.000073
2011-09-30 05:59:23.323192 0.000514 1.000145
2011-09-30 06:01:16.334408 0.000514 1.000216
... ... ...
2011-09-30 09:07:14.332788 0.000509 0.981747
2011-09-30 09:09:07.326703 0.000509 0.981346
2011-09-30 09:11:00.329269 0.000509 0.981607
2011-09-30 09:12:53.323184 0.000509 0.981533
2011-09-30 09:14:46.334400 0.000509 0.982140
2011-09-30 09:16:39.328315 0.000509 0.981786
2011-09-30 09:18:32.330881 0.000509 0.981695
2011-09-30 09:20:25.324796 0.000509 0.981920
2011-09-30 09:22:18.336012 0.000509 0.982121
2011-09-30 09:24:11.321277 0.000509 0.981889
2011-09-30 09:26:04.332493 0.000509 0.982647
2011-09-30 09:27:57.326408 0.000509 0.982922
2011-09-30 10:12:55.321913 0.000514 0.999597
2011-09-30 10:14:48.333128 0.000514 1.000026
2011-09-30 10:16:41.327044 0.000514 0.999945
2011-09-30 10:18:34.329609 0.000514 1.000247
2011-09-30 10:20:27.323525 0.000514 0.999967
2011-09-30 10:22:20.334700 0.000514 1.000256
2011-09-30 10:24:13.328656 0.000514 1.000084
2011-09-30 10:26:06.348481 0.000514 1.000002
2011-09-30 10:27:59.325137 0.000514 1.000057
2011-09-30 10:29:52.336312 0.000514 1.000053
2011-09-30 10:31:45.321617 0.000514 0.999866
2011-09-30 10:33:38.332793 0.000514 1.000203
2011-09-30 10:35:31.326708 0.000514 0.999659
2011-09-30 10:37:24.329274 0.000514 0.999868
2011-09-30 10:39:17.323189 0.000514 1.000053
2011-09-30 10:41:10.351665 0.000514 0.999834
2011-09-30 10:43:03.328320 0.000514 0.999975
2011-09-30 10:44:56.330886 0.000514 1.000356

111 rows × 2 columns

In [76]:
fig1, ax1 = plt.subplots(1, figsize=(10,5))
ep_df['flux'].plot(ax=ax1, fmt='.', yerr=ep_df['err_flux'])

Out[76]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f6e9e9cb810>
In [ ]: