BPT (Baldwin, Phillips & Terlevich) plot with galamo¶
Welcome to the tutorial on using galamo, a Python package designed for comprehensive galaxy analysis.
Abstract: In this tutorial, we'll explore the bpt module that helps in classifying galaxy types on the basis of initial spectral data of the galaxies. bpt works on mathematical formulation given by Kewley and Kauffman.
This module is especially useful for astrophysics researchers and students working with AGNs (Active Galactic Nuclei) host galaxies from surveys like SDSS.
Keywords: pandas, astroquery, astropy, flux, matplotlib, bpt
Author: Jashanpreet Singh Dingra
References:
- https://ned.ipac.caltech.edu/level5/Glossary/Essay_bpt.html
- https://ui.adsabs.harvard.edu/abs/2001ApJ...556..121K/abstract (Kewley et al. (2001))
- https://ui.adsabs.harvard.edu/abs/2003MNRAS.346.1055K/abstract (Kauffmann et al. (2003))
Let’s get started!
!pip install galamo
!pip show galamo #check requirements
Name: galamo Version: 1.1.2 Summary: An open source Python package for comprehensive galaxy analysis, integrating machine learning and statistical methods. It provides automated tools for morphology classification, kinematics, photometry, and spectral analysis to aid astrophysical research. Home-page: https://www.galamo.org Author: Jashanpreet Singh Dingra Author-email: astrodingra@gmail.com License: Location: /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages Requires: huggingface_hub, joblib, matplotlib, numpy, opencv-python, pandas, requests, scipy, tensorflow, termcolor, tqdm Required-by:
Imports¶
from astroquery.sdss import SDSS
from astropy.table import Table
import pandas as pd
from galamo import bpt
Data Query using astroquery¶
# Define SQL query
query = """
SELECT TOP 1000
i.specobjid,
i.plateid,
i.mjd,
i.fiberid,
i.z,
i.ra,
i.dec,
-- Emission Line Fluxes
l.h_alpha_flux,
l.h_beta_flux,
l.oiii_5007_flux,
l.nii_6584_flux,
l.oi_6300_flux,
l.sii_6717_flux,
l.sii_6731_flux,
-- Equivalent Widths
l.h_alpha_eqw,
l.nii_6584_eqw,
-- Flux Errors
l.h_alpha_flux_err,
l.h_beta_flux_err,
l.oiii_5007_flux_err,
l.nii_6584_flux_err,
l.oi_6300_flux_err,
l.sii_6717_flux_err,
l.sii_6731_flux_err
FROM
galSpecInfo AS i
JOIN
galSpecLine AS l ON i.specobjid = l.specobjid
WHERE
i.z BETWEEN 0 AND 0.3
AND l.h_alpha_flux_err > 0 AND l.h_alpha_flux / l.h_alpha_flux_err > 5
AND l.h_beta_flux_err > 0 AND l.h_beta_flux / l.h_beta_flux_err > 5
AND l.oiii_5007_flux_err > 0 AND l.oiii_5007_flux / l.oiii_5007_flux_err > 5
AND l.nii_6584_flux_err > 0 AND l.nii_6584_flux / l.nii_6584_flux_err > 5
AND l.sii_6717_flux_err > 0 AND l.sii_6717_flux / l.sii_6717_flux_err > 5
AND l.sii_6731_flux_err > 0 AND l.sii_6731_flux / l.sii_6731_flux_err > 5
AND l.oi_6300_flux_err > 0 AND l.oi_6300_flux / l.oi_6300_flux_err > 5
"""
# Run query
result = SDSS.query_sql(query)
# Convert to Astropy Table and optionally save as CSV
if result:
table = Table(result)
table.write("AGN_data.csv", format="csv", overwrite=True)
print("Query successful. Data saved to AGN_data.csv")
else:
print("No results returned.")
Query successful. Data saved to AGN_data.csv
Plotting BPT Diagrams¶
Galamo's bpt module provides tools for generating BPT (Baldwin, Phillips & Terlevich) diagnostic diagrams, which are essential for classifying emission-line galaxies based on their ionization mechanisms.
Available Map Styles¶
The module currently supports the following visualization styles:
defaultbubblesoft
Export Options¶
All BPT diagrams can be exported in a wide range of formats, including:
- PNG
- SVG
- EPS
This allows for seamless integration into publications, presentations, or reports.
bpt.draw("AGN_data.csv") # default map
✅ Columns matched
Applying maps¶
- Bubble
bpt.draw("AGN_data.csv", map="bubble") # bubble map
✅ Columns matched
- Soft
bpt.draw("AGN_data.csv", map="soft") # bubble map
✅ Columns matched
Saving the diagram¶
bpt.draw("AGN_data.csv", map="bubble", save_figure=True, output_filename="BPT_diagram.pdf") # bubble map and saved as pdf
✅ Columns matched
Exported File:

Error Detection in data¶
If the queried data is missing any critical parameters required for generating the BPT diagram, the module will raise an error and provide a clear message indicating the missing parameter and its expected location in the data structure. This ensures data integrity and helps guide users to correct their input before proceeding with the analysis.
bpt.draw("wrong.csv")
--------------------------------------------------------------------------- FileNotFoundError Traceback (most recent call last) Cell In[8], line 1 ----> 1 bpt.draw("wrong.csv") File /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/galamo/bpt.py:23, in draw(input_file, map, save_figure, output_filename) 19 required_columns = ['h_alpha_flux', 'h_beta_flux', 'oiii_5007_flux', 'nii_6584_flux', 20 'oi_6300_flux', 'sii_6717_flux', 'sii_6731_flux'] 22 # Read the data ---> 23 df = pd.read_csv(input_file) 24 actual_columns = df.columns.tolist() 26 # Check if all required columns are present File /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/pandas/io/parsers/readers.py:1026, in read_csv(filepath_or_buffer, sep, delimiter, header, names, index_col, usecols, dtype, engine, converters, true_values, false_values, skipinitialspace, skiprows, skipfooter, nrows, na_values, keep_default_na, na_filter, verbose, skip_blank_lines, parse_dates, infer_datetime_format, keep_date_col, date_parser, date_format, dayfirst, cache_dates, iterator, chunksize, compression, thousands, decimal, lineterminator, quotechar, quoting, doublequote, escapechar, comment, encoding, encoding_errors, dialect, on_bad_lines, delim_whitespace, low_memory, memory_map, float_precision, storage_options, dtype_backend) 1013 kwds_defaults = _refine_defaults_read( 1014 dialect, 1015 delimiter, (...) 1022 dtype_backend=dtype_backend, 1023 ) 1024 kwds.update(kwds_defaults) -> 1026 return _read(filepath_or_buffer, kwds) File /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/pandas/io/parsers/readers.py:620, in _read(filepath_or_buffer, kwds) 617 _validate_names(kwds.get("names", None)) 619 # Create the parser. --> 620 parser = TextFileReader(filepath_or_buffer, **kwds) 622 if chunksize or iterator: 623 return parser File /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/pandas/io/parsers/readers.py:1620, in TextFileReader.__init__(self, f, engine, **kwds) 1617 self.options["has_index_names"] = kwds["has_index_names"] 1619 self.handles: IOHandles | None = None -> 1620 self._engine = self._make_engine(f, self.engine) File /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/pandas/io/parsers/readers.py:1880, in TextFileReader._make_engine(self, f, engine) 1878 if "b" not in mode: 1879 mode += "b" -> 1880 self.handles = get_handle( 1881 f, 1882 mode, 1883 encoding=self.options.get("encoding", None), 1884 compression=self.options.get("compression", None), 1885 memory_map=self.options.get("memory_map", False), 1886 is_text=is_text, 1887 errors=self.options.get("encoding_errors", "strict"), 1888 storage_options=self.options.get("storage_options", None), 1889 ) 1890 assert self.handles is not None 1891 f = self.handles.handle File /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/pandas/io/common.py:873, in get_handle(path_or_buf, mode, encoding, compression, memory_map, is_text, errors, storage_options) 868 elif isinstance(handle, str): 869 # Check whether the filename is to be opened in binary mode. 870 # Binary mode does not support 'encoding' and 'newline'. 871 if ioargs.encoding and "b" not in ioargs.mode: 872 # Encoding --> 873 handle = open( 874 handle, 875 ioargs.mode, 876 encoding=ioargs.encoding, 877 errors=errors, 878 newline="", 879 ) 880 else: 881 # Binary mode 882 handle = open(handle, ioargs.mode) FileNotFoundError: [Errno 2] No such file or directory: 'wrong.csv'
For any issue in the module raise @ https://github.com/galamo-org/galamo/issues
from astroquery.sdss import SDSS
from astropy.table import Table
query = """
SELECT TOP 1000
s.specObjID,
s.ra, s.dec, s.z,
l.h_alpha_flux, l.h_alpha_flux_err,
l.h_beta_flux, l.h_beta_flux_err,
l.oiii_5007_flux, l.oiii_5007_flux_err,
l.nii_6584_flux, l.nii_6584_flux_err,
l.oi_6300_flux, l.oi_6300_flux_err,
l.sii_6717_flux, l.sii_6717_flux_err,
l.sii_6731_flux, l.sii_6731_flux_err
FROM SpecObj AS s
JOIN galSpecLine AS l ON s.specObjID = l.specObjID
WHERE
s.class = 'GALAXY' AND
l.h_alpha_flux > 0 AND
l.h_beta_flux > 0 AND
l.oiii_5007_flux > 0 AND
l.nii_6584_flux > 0 AND
l.oi_6300_flux > 0 AND
l.sii_6717_flux > 0 AND
l.sii_6731_flux > 0
"""
# Run the query using astroquery
results = SDSS.query_sql(query)
results.write('bpt_data.csv', format='csv', overwrite=True)
print("Saved to bpt_data.csv")
Saved to bpt_data.csv