evefile 0.1.0rc1__py3-none-any.whl → 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- evefile/boundaries/__pycache__/evefile.cpython-311.pyc +0 -0
- evefile/boundaries/evefile.py +184 -9
- evefile/controllers/__pycache__/joining.cpython-311.pyc +0 -0
- evefile/controllers/__pycache__/timestamp_mapping.cpython-311.pyc +0 -0
- evefile/controllers/__pycache__/version_mapping.cpython-311.pyc +0 -0
- evefile/controllers/joining.py +68 -111
- evefile/controllers/timestamp_mapping.py +136 -50
- evefile/controllers/version_mapping.py +181 -1
- evefile/entities/__pycache__/data.cpython-311.pyc +0 -0
- evefile/entities/__pycache__/metadata.cpython-311.pyc +0 -0
- evefile/entities/data.py +1177 -90
- evefile/entities/metadata.py +264 -0
- {evefile-0.1.0rc1.dist-info → evefile-0.2.0.dist-info}/METADATA +22 -3
- evefile-0.2.0.dist-info/RECORD +30 -0
- {evefile-0.1.0rc1.dist-info → evefile-0.2.0.dist-info}/WHEEL +1 -1
- evefile-0.1.0rc1.dist-info/RECORD +0 -30
- {evefile-0.1.0rc1.dist-info → evefile-0.2.0.dist-info}/licenses/COPYING +0 -0
- {evefile-0.1.0rc1.dist-info → evefile-0.2.0.dist-info}/licenses/LICENSE +0 -0
- {evefile-0.1.0rc1.dist-info → evefile-0.2.0.dist-info}/top_level.txt +0 -0
|
Binary file
|
evefile/boundaries/evefile.py
CHANGED
|
@@ -146,9 +146,10 @@ import os
|
|
|
146
146
|
|
|
147
147
|
import pandas as pd
|
|
148
148
|
|
|
149
|
+
import evefile.entities.data
|
|
149
150
|
from evefile.entities.file import File
|
|
150
151
|
from evefile.boundaries.eveh5 import HDF5File
|
|
151
|
-
from evefile.controllers import version_mapping, joining
|
|
152
|
+
from evefile.controllers import version_mapping, joining, timestamp_mapping
|
|
152
153
|
|
|
153
154
|
|
|
154
155
|
logger = logging.getLogger(__name__)
|
|
@@ -221,6 +222,11 @@ class EveFile(File):
|
|
|
221
222
|
The keys of the dictionary are the (guaranteed to be unique) HDF
|
|
222
223
|
dataset names, not the "given" names usually familiar to the users.
|
|
223
224
|
|
|
225
|
+
**Please note:** For monitors, in contrast to data stored in the
|
|
226
|
+
:attr:`data` attribute, names are *not unique*. Hence, the only way to
|
|
227
|
+
address an individual monitor unequivocally is by its ID that is
|
|
228
|
+
identical to the HDF dataset name.
|
|
229
|
+
|
|
224
230
|
Each item is an instance of
|
|
225
231
|
:class:`evefile.entities.data.MonitorData`.
|
|
226
232
|
|
|
@@ -261,7 +267,8 @@ class EveFile(File):
|
|
|
261
267
|
def __init__(self, filename="", load=True):
|
|
262
268
|
super().__init__()
|
|
263
269
|
self.filename = filename
|
|
264
|
-
self._join_factory = joining.JoinFactory(
|
|
270
|
+
self._join_factory = joining.JoinFactory(file=self)
|
|
271
|
+
self._monitor_mapper = timestamp_mapping.Mapper(file=self)
|
|
265
272
|
if load:
|
|
266
273
|
if not filename:
|
|
267
274
|
raise ValueError("No filename given")
|
|
@@ -387,14 +394,24 @@ class EveFile(File):
|
|
|
387
394
|
if self.metadata.preferred_axis:
|
|
388
395
|
output[0] = self.data[self.metadata.preferred_axis]
|
|
389
396
|
if self.metadata.preferred_channel:
|
|
390
|
-
|
|
397
|
+
if self.metadata.preferred_channel in self.data:
|
|
398
|
+
output[1] = self.data[self.metadata.preferred_channel]
|
|
399
|
+
else:
|
|
400
|
+
logger.warning(
|
|
401
|
+
"Dataset {} not found, possibly an "
|
|
402
|
+
"attribute or option?".format(
|
|
403
|
+
self.metadata.preferred_channel
|
|
404
|
+
)
|
|
405
|
+
)
|
|
391
406
|
if self.metadata.preferred_normalisation_channel:
|
|
392
407
|
output[2] = self.data[
|
|
393
408
|
self.metadata.preferred_normalisation_channel
|
|
394
409
|
]
|
|
395
410
|
return output
|
|
396
411
|
|
|
397
|
-
def get_joined_data(
|
|
412
|
+
def get_joined_data(
|
|
413
|
+
self, data=None, mode="AxisOrChannelPositions", include_monitors=False
|
|
414
|
+
):
|
|
398
415
|
"""
|
|
399
416
|
Retrieve data objects with commensurate dimensions.
|
|
400
417
|
|
|
@@ -420,6 +437,15 @@ class EveFile(File):
|
|
|
420
437
|
|
|
421
438
|
Default: "AxisOrChannelPositions"
|
|
422
439
|
|
|
440
|
+
include_monitors : :class:`bool`
|
|
441
|
+
Whether to include (all) monitors in joined data.
|
|
442
|
+
|
|
443
|
+
If set to :obj:`True`, all monitors available will automatically
|
|
444
|
+
be mapped to :obj:`DeviceData <evefile.entities.data.DeviceData>`
|
|
445
|
+
objects and included in the list of joined data.
|
|
446
|
+
|
|
447
|
+
Default: :obj:`False`
|
|
448
|
+
|
|
423
449
|
Returns
|
|
424
450
|
-------
|
|
425
451
|
data : :class:`list`
|
|
@@ -431,10 +457,37 @@ class EveFile(File):
|
|
|
431
457
|
"""
|
|
432
458
|
if not data:
|
|
433
459
|
data = list(self.data.values())
|
|
460
|
+
data = [
|
|
461
|
+
(
|
|
462
|
+
self._convert_str_to_data_object(item)
|
|
463
|
+
if isinstance(item, str)
|
|
464
|
+
else item
|
|
465
|
+
)
|
|
466
|
+
for item in data
|
|
467
|
+
]
|
|
468
|
+
if include_monitors:
|
|
469
|
+
monitors = self.get_monitors()
|
|
470
|
+
if isinstance(monitors, list):
|
|
471
|
+
data.extend(monitors)
|
|
472
|
+
else:
|
|
473
|
+
data.append(monitors)
|
|
434
474
|
joiner = self._join_factory.get_join(mode=mode)
|
|
435
475
|
return joiner.join(data)
|
|
436
476
|
|
|
437
|
-
def
|
|
477
|
+
def _convert_str_to_data_object(self, name_or_id=""):
|
|
478
|
+
try:
|
|
479
|
+
result = self.data[name_or_id]
|
|
480
|
+
except KeyError:
|
|
481
|
+
try:
|
|
482
|
+
result = self.get_data(name_or_id)
|
|
483
|
+
except KeyError:
|
|
484
|
+
# Valid situation: monitor
|
|
485
|
+
result = self.get_monitors(name_or_id)
|
|
486
|
+
return result
|
|
487
|
+
|
|
488
|
+
def get_dataframe(
|
|
489
|
+
self, data=None, mode="AxisOrChannelPositions", include_monitors=False
|
|
490
|
+
):
|
|
438
491
|
"""
|
|
439
492
|
Retrieve Pandas DataFrame with given data objects as columns.
|
|
440
493
|
|
|
@@ -445,6 +498,18 @@ class EveFile(File):
|
|
|
445
498
|
The names of the columns of the returned DataFrame are the names (not
|
|
446
499
|
IDs) of the respective datasets.
|
|
447
500
|
|
|
501
|
+
.. note::
|
|
502
|
+
|
|
503
|
+
At least for the time being, for each data object involved only
|
|
504
|
+
the ``data`` attribute will be contained in the returned
|
|
505
|
+
DataFrame as a column. This is of particular importance for more
|
|
506
|
+
complicated data types, such as :class:`NormalizedChannelData
|
|
507
|
+
<evefile.entities.data.NormalizedChannelData>`,
|
|
508
|
+
:class:`AverageChannelData
|
|
509
|
+
<evefile.entities.data.AverageChannelData>`,
|
|
510
|
+
and :class:`IntervalChannelData
|
|
511
|
+
<evefile.entities.data.IntervalChannelData>`.
|
|
512
|
+
|
|
448
513
|
.. important::
|
|
449
514
|
|
|
450
515
|
While working with a Pandas DataFrame may seem convenient,
|
|
@@ -457,12 +522,12 @@ class EveFile(File):
|
|
|
457
522
|
Parameters
|
|
458
523
|
----------
|
|
459
524
|
data : :class:`list`
|
|
460
|
-
(Names/IDs of) data objects whose data should be
|
|
525
|
+
(Names/IDs of) data objects whose data should be included.
|
|
461
526
|
|
|
462
527
|
You can provide either names or IDs or the actual data objects.
|
|
463
528
|
|
|
464
529
|
If no data are given, by default all data available will be
|
|
465
|
-
|
|
530
|
+
included.
|
|
466
531
|
|
|
467
532
|
Default: :obj:`None`
|
|
468
533
|
|
|
@@ -473,6 +538,19 @@ class EveFile(File):
|
|
|
473
538
|
|
|
474
539
|
Default: "AxisOrChannelPositions"
|
|
475
540
|
|
|
541
|
+
include_monitors : :class:`bool`
|
|
542
|
+
Whether to include (all) monitors in the dataframe.
|
|
543
|
+
|
|
544
|
+
If set to :obj:`True`, all monitors available will automatically
|
|
545
|
+
be mapped to :obj:`DeviceData <evefile.entities.data.DeviceData>`
|
|
546
|
+
objects and included in the dataframe.
|
|
547
|
+
|
|
548
|
+
Note that for mapped monitors, their IDs are used as column
|
|
549
|
+
names rather than the "given" names, as for monitors, names are
|
|
550
|
+
*not unique*.
|
|
551
|
+
|
|
552
|
+
Default: :obj:`False`
|
|
553
|
+
|
|
476
554
|
Returns
|
|
477
555
|
-------
|
|
478
556
|
dataframe : :class:`pandas.DataFrame`
|
|
@@ -484,11 +562,18 @@ class EveFile(File):
|
|
|
484
562
|
"""
|
|
485
563
|
if not data:
|
|
486
564
|
data = list(self.data.values())
|
|
487
|
-
joined_data = self.get_joined_data(
|
|
565
|
+
joined_data = self.get_joined_data(
|
|
566
|
+
data=data, mode=mode, include_monitors=include_monitors
|
|
567
|
+
)
|
|
568
|
+
for item in joined_data:
|
|
569
|
+
# Ensure IDs are used for monitors, as names are not unique
|
|
570
|
+
if isinstance(item, evefile.entities.data.DeviceData):
|
|
571
|
+
item.metadata.name = item.metadata.id
|
|
488
572
|
dataframe = pd.DataFrame(
|
|
489
573
|
{item.metadata.name: item.data for item in joined_data}
|
|
490
574
|
)
|
|
491
|
-
dataframe.index
|
|
575
|
+
dataframe.index = joined_data[0].position_counts
|
|
576
|
+
dataframe.index.name = "position"
|
|
492
577
|
return dataframe
|
|
493
578
|
|
|
494
579
|
def show_info(self):
|
|
@@ -552,3 +637,93 @@ class EveFile(File):
|
|
|
552
637
|
print("\nMONITORS")
|
|
553
638
|
for item in self.monitors.values():
|
|
554
639
|
print(item)
|
|
640
|
+
|
|
641
|
+
def get_monitors(self, monitors=None):
|
|
642
|
+
"""
|
|
643
|
+
Retrieve monitors as mapped device data objects by ID.
|
|
644
|
+
|
|
645
|
+
While you can get the original monitor data objects by accessing the
|
|
646
|
+
:attr:`monitors <evefile.entities.file.File.monitors>` attribute
|
|
647
|
+
directly, there, they are stored as
|
|
648
|
+
:obj:`MonitorData <evefile.entities.data.MonitorData>` objects with
|
|
649
|
+
timestamps instead of position counts. To relate monitors to the
|
|
650
|
+
measured data, the former need to be mapped to position counts.
|
|
651
|
+
|
|
652
|
+
.. note::
|
|
653
|
+
|
|
654
|
+
Monitors, in contrast to data objects stored in the
|
|
655
|
+
:attr:`data <evefile.entities.file.File.data>` attribute,
|
|
656
|
+
have *no unique names*. Hence, the only way to unequivocally
|
|
657
|
+
access a given monitor (or the respective, mapped
|
|
658
|
+
:obj:`DeviceData <evefile.entities.data.DeviceData>` object) is
|
|
659
|
+
by means of its unique ID.
|
|
660
|
+
|
|
661
|
+
|
|
662
|
+
Parameters
|
|
663
|
+
----------
|
|
664
|
+
monitors : :class:`str` | :class:`list`
|
|
665
|
+
Name or list of names of monitors to retrieve
|
|
666
|
+
|
|
667
|
+
Returns
|
|
668
|
+
-------
|
|
669
|
+
device_data : :class:`evefile.entities.data.Data` | :class:`list`
|
|
670
|
+
Device data object(s) corresponding to the ID(s).
|
|
671
|
+
|
|
672
|
+
In case of a list of data objects, each object is of type
|
|
673
|
+
:class:`evefile.entities.data.DeviceData`.
|
|
674
|
+
|
|
675
|
+
"""
|
|
676
|
+
device_data = []
|
|
677
|
+
if not monitors:
|
|
678
|
+
monitors = list(self.monitors)
|
|
679
|
+
if isinstance(monitors, (list, tuple)):
|
|
680
|
+
for item in monitors:
|
|
681
|
+
device_data.append(self._monitor_mapper.map(item))
|
|
682
|
+
else:
|
|
683
|
+
device_data.append(self._monitor_mapper.map(monitors))
|
|
684
|
+
if len(device_data) == 1:
|
|
685
|
+
device_data = device_data[0]
|
|
686
|
+
return device_data
|
|
687
|
+
|
|
688
|
+
def get_snapshots(self):
|
|
689
|
+
"""
|
|
690
|
+
Retrieve Pandas DataFrame with snapshots as rows.
|
|
691
|
+
|
|
692
|
+
Snapshots serve generally two functions:
|
|
693
|
+
|
|
694
|
+
#. Provide base values for axes.
|
|
695
|
+
|
|
696
|
+
In case of joining data using :meth:`get_joined_data`, for axes,
|
|
697
|
+
typically the previous values are used for positions no axes
|
|
698
|
+
values have been recorded. Snapshots are used if available.
|
|
699
|
+
|
|
700
|
+
#. Provide telemetry data for the setup the data were recorded with.
|
|
701
|
+
|
|
702
|
+
Snapshots regularly contain many more parameters than motor axes
|
|
703
|
+
used and detector channels recorded. Generally, this provides a
|
|
704
|
+
lot of telemetry data regarding the setup used for recording the
|
|
705
|
+
data.
|
|
706
|
+
|
|
707
|
+
The first function is served by the :meth:`get_joined_data` method
|
|
708
|
+
automatically. The second function can be served by having a look at
|
|
709
|
+
a summary containing all snapshot data. This is the aim of this
|
|
710
|
+
method: returning a Pandas DataFrame containing all snapshots as
|
|
711
|
+
rows and the position counts as columns.
|
|
712
|
+
|
|
713
|
+
|
|
714
|
+
Returns
|
|
715
|
+
-------
|
|
716
|
+
snapshot_dataframe : :class:`pandas.DataFrame`
|
|
717
|
+
Pandas DataFrame containing all snapshots as rows.
|
|
718
|
+
|
|
719
|
+
The indices (names of the rows) are the names (not IDs) of the
|
|
720
|
+
respective snapshot datasets.
|
|
721
|
+
|
|
722
|
+
"""
|
|
723
|
+
snapshot_dataframes = []
|
|
724
|
+
for snapshot in self.snapshots.values():
|
|
725
|
+
data = dict(zip(snapshot.position_counts, snapshot.data))
|
|
726
|
+
snapshot_dataframes.append(
|
|
727
|
+
pd.DataFrame(data=data, index=[snapshot.metadata.name])
|
|
728
|
+
)
|
|
729
|
+
return pd.concat(snapshot_dataframes)
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
evefile/controllers/joining.py
CHANGED
|
@@ -132,7 +132,7 @@ Monitors have not changed by definition
|
|
|
132
132
|
---------------------------------------
|
|
133
133
|
|
|
134
134
|
A monitor is by definition a device you are observing for changes in its
|
|
135
|
-
values. Hence, if no
|
|
135
|
+
values. Hence, if no change has been recorded (*i.e.*, no newer value is
|
|
136
136
|
present), the value hasn't changed. Therefore, monitor data can be
|
|
137
137
|
"filled" with the last known value, and in contrast to axes, we can be
|
|
138
138
|
certain that this is true. (For an axis, you could always argue that if
|
|
@@ -165,8 +165,12 @@ NoFill
|
|
|
165
165
|
have values."
|
|
166
166
|
|
|
167
167
|
Actually, not a filling, but mathematically an intersection, or,
|
|
168
|
-
in terms of relational databases, an ``SQL INNER JOIN``.
|
|
169
|
-
|
|
168
|
+
in terms of relational databases, an ``SQL INNER JOIN``. Note, however,
|
|
169
|
+
that in contrast to the usual terminology of relational databases,
|
|
170
|
+
no individual "tables" (*i.e.*, datasets) are joined, but only the
|
|
171
|
+
set unions of channel and axes positions, respectively. In any case,
|
|
172
|
+
data are *reduced*. Nevertheless, you will most probably end up with
|
|
173
|
+
``NaN`` or otherwise missing values. See below for details.
|
|
170
174
|
|
|
171
175
|
LastFill
|
|
172
176
|
"Use all channel data and fill in the last known position for all axes
|
|
@@ -220,7 +224,9 @@ main/standard section yet.
|
|
|
220
224
|
.. note::
|
|
221
225
|
|
|
222
226
|
Note that **none of the fill modes guarantees that there are no NaNs**
|
|
223
|
-
(or comparable null values) in the resulting data.
|
|
227
|
+
(or comparable null values) in the resulting data. The reason: Not
|
|
228
|
+
individual axes or channel datasets are joined, but always the set union
|
|
229
|
+
of all axes positions and all channel positions, respectively.
|
|
224
230
|
|
|
225
231
|
|
|
226
232
|
.. note::
|
|
@@ -235,9 +241,13 @@ main/standard section yet.
|
|
|
235
241
|
|
|
236
242
|
The IDL Cruncher seems to use LastNaNFill combined with applying some
|
|
237
243
|
"dirty" fixes to account for scans using MPSKIP and those scans
|
|
238
|
-
"monitoring" a motor position via a pseudo-detector.
|
|
239
|
-
|
|
240
|
-
|
|
244
|
+
"monitoring" a motor position via a pseudo-detector.
|
|
245
|
+
|
|
246
|
+
The ``EveHDF`` class uses LastNaNFill as a default as well but
|
|
247
|
+
additionally fills the channel values with the last known value,
|
|
248
|
+
thus making up data. Therefore, EveHDF is considered harmful with
|
|
249
|
+
potentially very serious consequences of your data analysis and cannot
|
|
250
|
+
be recommended for use.
|
|
241
251
|
|
|
242
252
|
Shall fill modes be something to change in a viewer? And which fill
|
|
243
253
|
modes are used in practice (and do we have any chance to find this out)?
|
|
@@ -330,26 +340,20 @@ final joined data array previously determined for all the other datasets
|
|
|
330
340
|
(that in turn depend on the join mode, of course).
|
|
331
341
|
|
|
332
342
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
.. important::
|
|
337
|
-
|
|
338
|
-
The classes implemented in this module have been copied from the
|
|
339
|
-
corresponding module in `evedata`_, and here particularly from the
|
|
340
|
-
"measurement" functional layer. However, the needs in ``evefile`` are
|
|
341
|
-
different, hence even the basic :class:`Join` class needs to be
|
|
342
|
-
redesigned. Further information below. Once this has been done,
|
|
343
|
-
this entire section should be removed.
|
|
344
|
-
|
|
343
|
+
How to deal with additional attributes?
|
|
344
|
+
=======================================
|
|
345
345
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
346
|
+
Joining should take into account all available attributes, not only
|
|
347
|
+
``data``, but options as well if present. This of course only applies to
|
|
348
|
+
``evefile`` if options of devices are mapped to the respective data
|
|
349
|
+
objects.
|
|
350
350
|
|
|
351
|
-
|
|
352
|
-
|
|
351
|
+
A similar case already implemented: More advanced channels such as average
|
|
352
|
+
and interval channels that come with additional data per each recorded
|
|
353
|
+
value (see :class:`AverageChannelData
|
|
354
|
+
<evefile.entities.data.AverageChannelData>` and
|
|
355
|
+
:class:`IntervalChannelData <evefile.entities.data.IntervalChannelData>`
|
|
356
|
+
for details) have these attributes handled accordingly.
|
|
353
357
|
|
|
354
358
|
|
|
355
359
|
Join modes currently implemented
|
|
@@ -466,7 +470,6 @@ import logging
|
|
|
466
470
|
from functools import reduce
|
|
467
471
|
|
|
468
472
|
import numpy as np
|
|
469
|
-
from numpy import ma
|
|
470
473
|
|
|
471
474
|
import evefile.entities
|
|
472
475
|
import evefile.entities.data
|
|
@@ -499,7 +502,7 @@ class Join:
|
|
|
499
502
|
|
|
500
503
|
Attributes
|
|
501
504
|
----------
|
|
502
|
-
|
|
505
|
+
file : :class:`evefile.boundaries.evefile.EveFile`
|
|
503
506
|
EveFile object the Join should be performed for.
|
|
504
507
|
|
|
505
508
|
Although joining is carried out for a small subset of the
|
|
@@ -508,7 +511,7 @@ class Join:
|
|
|
508
511
|
|
|
509
512
|
Parameters
|
|
510
513
|
----------
|
|
511
|
-
|
|
514
|
+
file : :class:`evefile.boundaries.evefile.EveFile`
|
|
512
515
|
EveFile object the join should be performed for.
|
|
513
516
|
|
|
514
517
|
|
|
@@ -523,7 +526,7 @@ class Join:
|
|
|
523
526
|
|
|
524
527
|
.. code-block::
|
|
525
528
|
|
|
526
|
-
join = Join(
|
|
529
|
+
join = Join(file=my_evefile)
|
|
527
530
|
# Call with data object names
|
|
528
531
|
joined_data = join.join(["name1", "name2"])
|
|
529
532
|
# Call with data objects
|
|
@@ -533,12 +536,13 @@ class Join:
|
|
|
533
536
|
|
|
534
537
|
"""
|
|
535
538
|
|
|
536
|
-
def __init__(self,
|
|
539
|
+
def __init__(self, file=None):
|
|
537
540
|
self._channel_indices = []
|
|
538
541
|
self._axes = []
|
|
539
542
|
self._channels = []
|
|
543
|
+
self._devices = []
|
|
540
544
|
self._result_positions = None
|
|
541
|
-
self.
|
|
545
|
+
self.file = file
|
|
542
546
|
|
|
543
547
|
def join(self, data=None):
|
|
544
548
|
"""
|
|
@@ -574,32 +578,18 @@ class Join:
|
|
|
574
578
|
Raised if no data are provided
|
|
575
579
|
|
|
576
580
|
"""
|
|
577
|
-
if not self.
|
|
581
|
+
if not self.file:
|
|
578
582
|
raise ValueError("Need an evefile to join data.")
|
|
579
583
|
if not data:
|
|
580
584
|
raise ValueError("Need data to join data.")
|
|
581
|
-
data = [
|
|
582
|
-
(
|
|
583
|
-
self._convert_str_to_data_object(item)
|
|
584
|
-
if isinstance(item, str)
|
|
585
|
-
else item
|
|
586
|
-
)
|
|
587
|
-
for item in data
|
|
588
|
-
]
|
|
589
585
|
return self._join(data=data)
|
|
590
586
|
|
|
591
|
-
def _convert_str_to_data_object(self, name_or_id=""):
|
|
592
|
-
try:
|
|
593
|
-
result = self.evefile.data[name_or_id]
|
|
594
|
-
except KeyError:
|
|
595
|
-
result = self.evefile.get_data(name_or_id)
|
|
596
|
-
return result
|
|
597
|
-
|
|
598
587
|
def _join(self, data=None):
|
|
599
588
|
self._sort_data(data)
|
|
600
589
|
self._assign_result_positions()
|
|
601
590
|
self._fill_axes()
|
|
602
591
|
self._fill_channels()
|
|
592
|
+
self._fill_devices()
|
|
603
593
|
return self._assign_result()
|
|
604
594
|
|
|
605
595
|
def _sort_data(self, data):
|
|
@@ -609,68 +599,35 @@ class Join:
|
|
|
609
599
|
self._channel_indices.append(idx)
|
|
610
600
|
if isinstance(item, evefile.entities.data.AxisData):
|
|
611
601
|
self._axes.append(copy.copy(item))
|
|
602
|
+
if isinstance(item, evefile.entities.data.DeviceData):
|
|
603
|
+
self._devices.append(copy.copy(item))
|
|
612
604
|
|
|
613
605
|
def _assign_result_positions(self):
|
|
614
606
|
pass
|
|
615
607
|
|
|
616
608
|
def _fill_axes(self):
|
|
617
609
|
for axis in self._axes:
|
|
618
|
-
if axis.metadata.id in self.
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
axis.
|
|
622
|
-
self.evefile.snapshots[axis.metadata.id].position_counts,
|
|
623
|
-
)
|
|
624
|
-
axis.data = np.insert(
|
|
625
|
-
axis.data,
|
|
626
|
-
axis.position_counts,
|
|
627
|
-
self.evefile.snapshots[axis.metadata.id].data,
|
|
628
|
-
)
|
|
629
|
-
positions = (
|
|
630
|
-
np.searchsorted(
|
|
631
|
-
axis.position_counts, self._result_positions, side="right"
|
|
610
|
+
if axis.metadata.id in self.file.snapshots:
|
|
611
|
+
axis.join(
|
|
612
|
+
positions=self._result_positions,
|
|
613
|
+
snapshot=self.file.snapshots[axis.metadata.id],
|
|
632
614
|
)
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
axis.position_counts = self._result_positions
|
|
636
|
-
axis.data = axis.data[positions]
|
|
637
|
-
if np.any(np.where(positions < 0)):
|
|
638
|
-
axis.data = ma.masked_array(axis.data)
|
|
639
|
-
axis.data[np.where(positions < 0)] = ma.masked
|
|
615
|
+
else:
|
|
616
|
+
axis.join(positions=self._result_positions, fill=True)
|
|
640
617
|
|
|
641
618
|
def _fill_channels(self):
|
|
642
619
|
for channel in self._channels:
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
channel.data = ma.masked_array(channel.data)
|
|
649
|
-
positions = np.setdiff1d(
|
|
650
|
-
self._result_positions, channel.position_counts
|
|
651
|
-
)
|
|
652
|
-
channel.data[
|
|
653
|
-
np.searchsorted(
|
|
654
|
-
self._result_positions, channel.position_counts
|
|
655
|
-
).astype(np.int64)
|
|
656
|
-
] = original_values
|
|
657
|
-
channel.data[
|
|
658
|
-
np.searchsorted(self._result_positions, positions).astype(
|
|
659
|
-
np.int64
|
|
660
|
-
)
|
|
661
|
-
] = ma.masked
|
|
662
|
-
elif len(self._result_positions) < len(channel.position_counts):
|
|
663
|
-
channel.data = channel.data[
|
|
664
|
-
np.searchsorted(
|
|
665
|
-
channel.position_counts, self._result_positions
|
|
666
|
-
).astype(np.int64)
|
|
667
|
-
]
|
|
668
|
-
channel.position_counts = self._result_positions
|
|
620
|
+
channel.join(positions=self._result_positions)
|
|
621
|
+
|
|
622
|
+
def _fill_devices(self):
|
|
623
|
+
for device in self._devices:
|
|
624
|
+
device.join(positions=self._result_positions)
|
|
669
625
|
|
|
670
626
|
def _assign_result(self):
|
|
671
627
|
result = [*self._axes]
|
|
672
628
|
for idx, item in enumerate(self._channels):
|
|
673
629
|
result.insert(self._channel_indices[idx], item)
|
|
630
|
+
result.extend(self._devices)
|
|
674
631
|
return result
|
|
675
632
|
|
|
676
633
|
|
|
@@ -722,7 +679,7 @@ class ChannelPositions(Join):
|
|
|
722
679
|
|
|
723
680
|
Attributes
|
|
724
681
|
----------
|
|
725
|
-
|
|
682
|
+
file : :class:`evefile.boundaries.evefile.EveFile`
|
|
726
683
|
EveFile object the join should be performed for.
|
|
727
684
|
|
|
728
685
|
Although joining may only be carried out for a small subset of the
|
|
@@ -732,7 +689,7 @@ class ChannelPositions(Join):
|
|
|
732
689
|
|
|
733
690
|
Parameters
|
|
734
691
|
----------
|
|
735
|
-
|
|
692
|
+
file : :class:`evefile.boundaries.evefile.EveFile`
|
|
736
693
|
EveFile the join should be performed for.
|
|
737
694
|
|
|
738
695
|
|
|
@@ -747,7 +704,7 @@ class ChannelPositions(Join):
|
|
|
747
704
|
|
|
748
705
|
.. code-block::
|
|
749
706
|
|
|
750
|
-
join = ChannelPositions(
|
|
707
|
+
join = ChannelPositions(file=my_evefile)
|
|
751
708
|
# Call with data object names
|
|
752
709
|
joined_data = join.join(["name1", "name2"])
|
|
753
710
|
# Call with data objects
|
|
@@ -814,7 +771,7 @@ class AxisPositions(Join):
|
|
|
814
771
|
|
|
815
772
|
Attributes
|
|
816
773
|
----------
|
|
817
|
-
|
|
774
|
+
file : :class:`evefile.boundaries.evefile.EveFile`
|
|
818
775
|
EveFile object the join should be performed for.
|
|
819
776
|
|
|
820
777
|
Although joining may only be carried out for a small subset of the
|
|
@@ -824,7 +781,7 @@ class AxisPositions(Join):
|
|
|
824
781
|
|
|
825
782
|
Parameters
|
|
826
783
|
----------
|
|
827
|
-
|
|
784
|
+
file : :class:`evefile.boundaries.evefile.EveFile`
|
|
828
785
|
EveFile the join should be performed for.
|
|
829
786
|
|
|
830
787
|
|
|
@@ -839,7 +796,7 @@ class AxisPositions(Join):
|
|
|
839
796
|
|
|
840
797
|
.. code-block::
|
|
841
798
|
|
|
842
|
-
join = AxisPositions(
|
|
799
|
+
join = AxisPositions(file=my_evefile)
|
|
843
800
|
# Call with data object names
|
|
844
801
|
joined_data = join.join(["name1", "name2"])
|
|
845
802
|
# Call with data objects
|
|
@@ -909,7 +866,7 @@ class AxisAndChannelPositions(Join):
|
|
|
909
866
|
|
|
910
867
|
Attributes
|
|
911
868
|
----------
|
|
912
|
-
|
|
869
|
+
file : :class:`evefile.boundaries.evefile.EveFile`
|
|
913
870
|
EveFile object the join should be performed for.
|
|
914
871
|
|
|
915
872
|
Although joining may only be carried out for a small subset of the
|
|
@@ -919,7 +876,7 @@ class AxisAndChannelPositions(Join):
|
|
|
919
876
|
|
|
920
877
|
Parameters
|
|
921
878
|
----------
|
|
922
|
-
|
|
879
|
+
file : :class:`evefile.boundaries.evefile.EveFile`
|
|
923
880
|
EveFile the join should be performed for.
|
|
924
881
|
|
|
925
882
|
|
|
@@ -934,7 +891,7 @@ class AxisAndChannelPositions(Join):
|
|
|
934
891
|
|
|
935
892
|
.. code-block::
|
|
936
893
|
|
|
937
|
-
join = AxisAndChannelPositions(
|
|
894
|
+
join = AxisAndChannelPositions(file=my_evefile)
|
|
938
895
|
# Call with data object names
|
|
939
896
|
joined_data = join.join(["name1", "name2"])
|
|
940
897
|
# Call with data objects
|
|
@@ -1006,7 +963,7 @@ class AxisOrChannelPositions(Join):
|
|
|
1006
963
|
|
|
1007
964
|
Attributes
|
|
1008
965
|
----------
|
|
1009
|
-
|
|
966
|
+
file : :class:`evefile.boundaries.evefile.EveFile`
|
|
1010
967
|
EveFile object the join should be performed for.
|
|
1011
968
|
|
|
1012
969
|
Although joining may only be carried out for a small subset of the
|
|
@@ -1016,7 +973,7 @@ class AxisOrChannelPositions(Join):
|
|
|
1016
973
|
|
|
1017
974
|
Parameters
|
|
1018
975
|
----------
|
|
1019
|
-
|
|
976
|
+
file : :class:`evefile.boundaries.evefile.EveFile`
|
|
1020
977
|
EveFile the join should be performed for.
|
|
1021
978
|
|
|
1022
979
|
|
|
@@ -1031,7 +988,7 @@ class AxisOrChannelPositions(Join):
|
|
|
1031
988
|
|
|
1032
989
|
.. code-block::
|
|
1033
990
|
|
|
1034
|
-
join = AxisOrChannelPositions(
|
|
991
|
+
join = AxisOrChannelPositions(file=my_evefile)
|
|
1035
992
|
# Call with data object names
|
|
1036
993
|
joined_data = join.join(["name1", "name2"])
|
|
1037
994
|
# Call with data objects
|
|
@@ -1068,13 +1025,13 @@ class JoinFactory:
|
|
|
1068
1025
|
|
|
1069
1026
|
Attributes
|
|
1070
1027
|
----------
|
|
1071
|
-
|
|
1028
|
+
file : :class:`evefile.boundaries.evefile.EveFile`
|
|
1072
1029
|
EveFile the join should be performed for.
|
|
1073
1030
|
|
|
1074
1031
|
|
|
1075
1032
|
Parameters
|
|
1076
1033
|
----------
|
|
1077
|
-
|
|
1034
|
+
file : :class:`evefile.boundaries.evefile.EveFile`
|
|
1078
1035
|
EveFile the join should be performed for.
|
|
1079
1036
|
|
|
1080
1037
|
|
|
@@ -1107,8 +1064,8 @@ class JoinFactory:
|
|
|
1107
1064
|
|
|
1108
1065
|
"""
|
|
1109
1066
|
|
|
1110
|
-
def __init__(self,
|
|
1111
|
-
self.
|
|
1067
|
+
def __init__(self, file=None):
|
|
1068
|
+
self.file = file
|
|
1112
1069
|
|
|
1113
1070
|
def get_join(self, mode="Join"):
|
|
1114
1071
|
"""
|
|
@@ -1134,5 +1091,5 @@ class JoinFactory:
|
|
|
1134
1091
|
Join instance
|
|
1135
1092
|
|
|
1136
1093
|
"""
|
|
1137
|
-
instance = globals()[mode](
|
|
1094
|
+
instance = globals()[mode](file=self.file)
|
|
1138
1095
|
return instance
|