User Data

Functionality exists for a user to add their own data into the combined table. The function add_user_data() is a method of the MassTable class and takes data in json format and adds it to the table.

An identifier column DataSource already exists and for all published data and is set to 0. Along with providing the new data, a user can specify a value for DataSource, otherwise a value of 1 is automatically assigned. The ability to specify a value means multiple data sources can be added whilst maintaining the ability to distinguish. If no value is given, the value of 1 will always be used.

To ensure uniqueness, values for A and Z must be part of the data. With the assumption that you would like to compare and contrast this new data with the published values, the name associated with your data must also match existing columns. I know this doesn’t quite make sense, as you might not necessarily want to assign your new mass to either AME or NUBASE, but in general, the columns are generic so I’m sure you’ll work it out.

Let’s imagine I have a new measurement for the mass excess of 100Ag at -78136.4 +/- 0.6 and I want to add it to the table

>>> # Addition is done on the class level so create an instance of the MassTable
>>> from nuclearmasses.mass_table import MassTable
>>> table = MassTable()
>>> # This step doesn't need to be done, but, for demonstration purposes,
>>> # extract the table data and check the current details for 100Ag
>>> df = table.data
>>> df.query("Symbol == 'Ag' and A == 100")[['A', 'Z', 'NUBASEMassExcess', 'NUBASEMassExcessError', 'DataSource']])
        A  NUBASEMassExcess  NUBASEMassExcessError  DataSource
6976  100               NaN                    NaN           0
6977  100               NaN                    NaN           0
6978  100          -78180.0                   80.0           0
6979  100          -78150.0                   80.0           0
6980  100          -78138.0                    5.0           0
6981  100          -78138.0                    5.0           0
6982  100          -78138.0                    5.0           0
>>> # Add our new value to the NUBASE columns
>>> table.add_user_data('[{"A": 100, "Z": 47, "NUBASEMassExcess": -78136.4, "NUBASEMassExcessError": 0.6}]')
>>> # The underlying table has been modified, so we need to get the latest version
>>> df = table.data
>>> # Re-run the query to see the new value, notice the value for DataSource has been set to 1
>>> df.query("Symbol == 'Ag' and A == 100")[['A', 'Z', 'NUBASEMassExcess', 'NUBASEMassExcessError', 'DataSource']])
         A  NUBASEMassExcess  NUBASEMassExcessError  DataSource
6976   100               NaN                    NaN           0
6977   100               NaN                    NaN           0
6978   100          -78180.0                   80.0           0
6979   100          -78150.0                   80.0           0
6980   100          -78138.0                    5.0           0
6981   100          -78138.0                    5.0           0
6982   100          -78138.0                    5.0           0
21421  100          -78136.4                    0.6           1
>>> # We can add the same data but this time assign to a different source
>>> table.add_user_data('[{"A": 100, "Z": 47, "NUBASEMassExcess": -78136.4, "NUBASEMassExcessError": 0.6}]', source=5)
>>> # Again, this modifies the underlying dataframe so we need to fetch the updated version
>>> df = table.data
>>> # Run the query and see that our new data is there twice against two different sources
>>> df.query("Symbol == 'Ag' and A == 100")[['A', 'Z', 'NUBASEMassExcess', 'NUBASEMassExcessError', 'DataSource']])
         A  NUBASEMassExcess  NUBASEMassExcessError  DataSource
6976   100               NaN                    NaN           0
6977   100               NaN                    NaN           0
6978   100          -78180.0                   80.0           0
6979   100          -78150.0                   80.0           0
6980   100          -78138.0                    5.0           0
6981   100          -78138.0                    5.0           0
6982   100          -78138.0                    5.0           0
21421  100          -78136.4                    0.6           1
21422  100          -78136.4                    0.6           5

Now let’s imagine that we have a large new data set in a json file, but have forgotten to add the Experimental attribute and for reasons, it is not possible to edit or update the file with this additional information. When reading in the file, we can pass a dictionary as a parameter, and the keys will be used as the column names, with the values used as value to for all new isotopes.

In the following example, we will assume the data is in a file new_data.json and of type pathlib.

>>> import pathlib
>>> from nuclearmasses.mass_table import MassTable
>>> table = MassTable()
>>> missed_values = {'Experimental': True}
>>> new_data = pathlib.Path('new_data.json')
>>> table.add_user_data(new_data, common_values=missed_values)
>>> # All isotopes from new_data.json will have their Experimental column assigned to True

If an existing column is not populated with new data, it is assigned the value pd.NA. We do not try and infer what a value could, should or might be.