diff --git a/cmlreaders/base_reader.py b/cmlreaders/base_reader.py
index 37ef9ea..06e3f98 100644
--- a/cmlreaders/base_reader.py
+++ b/cmlreaders/base_reader.py
@@ -1,4 +1,5 @@
-from typing import Optional
+from pathlib import Path
+from typing import Optional, Union
 
 from .path_finder import PathFinder
 from .exc import UnsupportedOutputFormat, ImproperlyDefinedReader
@@ -72,6 +73,22 @@ class BaseCMLReader(object, metaclass=_MetaReader):
         self.data_type = data_type
         self.rootdir = rootdir
 
+    @classmethod
+    def fromfile(cls, path: Union[str, Path]):
+        """Directly load data from a file using the default representation.
+        This is equivalent to creating a reader with the ``file_path`` keyword
+        argument given but without the need to then call ``load`` or specify
+        other, unnecessary arguments.
+
+        Parameters
+        ----------
+        path
+            Path to the file to load.
+
+        """
+        reader = cls("", "", "", -1, file_path=str(path))
+        return reader.load()
+
     def load(self):
         """ Load data into memory """
         method_name = "_".join(["as", self.default_representation])
diff --git a/cmlreaders/readers/electrodes.py b/cmlreaders/readers/electrodes.py
index 4d4c4c4..9c0f245 100644
--- a/cmlreaders/readers/electrodes.py
+++ b/cmlreaders/readers/electrodes.py
@@ -1,4 +1,5 @@
 import json
+import os.path
 from typing import List
 
 import pandas as pd
@@ -31,7 +32,17 @@ class MontageReader(BaseCMLReader):
         from multiprocessing import cpu_count
 
         with open(self._file_path) as f:
-            data = json.load(f)[self.subject][self.data_type]
+            raw = json.load(f)
+
+            # we're using fromfile, so we need to infer subject/data_type
+            if not len(self.data_type):
+                self.subject = list(raw.keys())[0]
+                self.data_type = (
+                    "contacts" if "contacts" in os.path.basename(self._file_path)
+                    else "pairs"
+                )
+
+            data = raw[self.subject][self.data_type]
 
         labels = [l for l in data]
 

Improve usability of specific readers
Generally, we want to use `CMLReader` to interact with specific readers indirectly. But there are some use cases where other readers are useful, such as the one for reading Ramulator event log files (this is helpful for me when analyzing output from tests). At present, it's a bit awkward to use:

```python
reader = RamulatorEventLogReader("experiment_log", "fake subject", "fake experiment", 0, file_path="event_log.json")
events = reader.as_dataframe()
```

All that I *really* need to pass in this case is that path to the file, but the constructor requires subject, experiment, and session. I propose we add a new class method which works like this:

```python
events = RamulatorEventLogReader.fromfile("event_log.json")
```

This has the advantage of not making the constructor overly complicated (e.g., arguments are optional if `file_path` is not specified, otherwise they are required).
diff --git a/cmlreaders/test/test_readers.py b/cmlreaders/test/test_readers.py
index 5895cb4..826b4ab 100644
--- a/cmlreaders/test/test_readers.py
+++ b/cmlreaders/test/test_readers.py
@@ -379,3 +379,14 @@ class TestClassifierContainerReader:
         callable_method(exp_output, overwrite=True)
         assert os.path.exists(exp_output)
         os.remove(exp_output)
+
+
+@pytest.mark.parametrize("cls,path,dtype", [
+    (ElectrodeCategoriesReader, datafile("electrode_categories.txt"), dict),
+    (MontageReader, datafile("pairs.json"), pd.DataFrame),
+    (MontageReader, datafile("contacts.json"), pd.DataFrame),
+    (RamulatorEventLogReader, datafile("event_log.json"), pd.DataFrame),
+])
+def test_fromfile(cls, path, dtype):
+    data = cls.fromfile(path)
+    assert isinstance(data, dtype)

pip install -e .
parse_log_pytest
requirements.txt
pytest pytest-cov
apt-get update apt-get install -y gcc
3.6
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
alabaster==0.7.13
async-generator==1.10
attrs==22.2.0
Babel==2.11.0
bleach==4.1.0
cached-property==1.5.2
certifi==2021.5.30
charset-normalizer==2.0.12
-e git+https://github.com/pennmem/cmlreaders.git@93f826340ac27413c13d0151b1297d8c0a344b92#egg=cmlreaders
codecov==2.1.13
coverage==6.2
decorator==5.1.1
defusedxml==0.7.1
docutils==0.18.1
entrypoints==0.4
flake8==3.9.2
h5py==3.1.0
idna==3.10
imagesize==1.4.1
importlib-metadata==4.8.3
iniconfig==1.1.1
ipython-genutils==0.2.0
Jinja2==3.0.3
jsonschema==3.2.0
jupyter-client==7.1.2
jupyter-core==4.9.2
jupyterlab-pygments==0.1.2
MarkupSafe==2.0.1
mccabe==0.6.1
mistune==0.8.4
mne==0.23.4
nbclient==0.5.9
nbconvert==6.0.7
nbformat==5.1.3
nbsphinx==0.8.8
nest-asyncio==1.6.0
numpy==1.19.5
packaging==21.3
pandas==1.1.5
pandocfilters==1.5.1
pluggy==1.0.0
py==1.11.0
pycodestyle==2.7.0
pyflakes==2.3.1
Pygments==2.14.0
pyparsing==3.1.4
pyrsistent==0.18.0
pytest==7.0.1
pytest-cov==4.0.0
python-dateutil==2.9.0.post0
pytz==2025.2
pyzmq==25.1.2
requests==2.27.1
scipy==1.5.4
six==1.17.0
snowballstemmer==2.2.0
Sphinx==5.3.0
sphinx-rtd-theme==2.0.0
sphinxcontrib-applehelp==1.0.2
sphinxcontrib-devhelp==1.0.2
sphinxcontrib-htmlhelp==2.0.0
sphinxcontrib-jquery==4.1
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==1.0.3
sphinxcontrib-serializinghtml==1.1.5
testpath==0.6.0
tomli==1.2.3
tornado==6.1
traitlets==4.3.3
typing_extensions==4.1.1
urllib3==1.26.20
webencodings==0.5.1
zipp==3.6.0

name: cmlreaders
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=21.2.2=py36h06a4308_0
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - alabaster==0.7.13
      - async-generator==1.10
      - attrs==22.2.0
      - babel==2.11.0
      - bleach==4.1.0
      - cached-property==1.5.2
      - charset-normalizer==2.0.12
      - codecov==2.1.13
      - coverage==6.2
      - decorator==5.1.1
      - defusedxml==0.7.1
      - docutils==0.18.1
      - entrypoints==0.4
      - flake8==3.9.2
      - h5py==3.1.0
      - idna==3.10
      - imagesize==1.4.1
      - importlib-metadata==4.8.3
      - iniconfig==1.1.1
      - ipython-genutils==0.2.0
      - jinja2==3.0.3
      - jsonschema==3.2.0
      - jupyter-client==7.1.2
      - jupyter-core==4.9.2
      - jupyterlab-pygments==0.1.2
      - markupsafe==2.0.1
      - mccabe==0.6.1
      - mistune==0.8.4
      - mne==0.23.4
      - nbclient==0.5.9
      - nbconvert==6.0.7
      - nbformat==5.1.3
      - nbsphinx==0.8.8
      - nest-asyncio==1.6.0
      - numpy==1.19.5
      - packaging==21.3
      - pandas==1.1.5
      - pandocfilters==1.5.1
      - pluggy==1.0.0
      - py==1.11.0
      - pycodestyle==2.7.0
      - pyflakes==2.3.1
      - pygments==2.14.0
      - pyparsing==3.1.4
      - pyrsistent==0.18.0
      - pytest==7.0.1
      - pytest-cov==4.0.0
      - python-dateutil==2.9.0.post0
      - pytz==2025.2
      - pyzmq==25.1.2
      - requests==2.27.1
      - scipy==1.5.4
      - six==1.17.0
      - snowballstemmer==2.2.0
      - sphinx==5.3.0
      - sphinx-rtd-theme==2.0.0
      - sphinxcontrib-applehelp==1.0.2
      - sphinxcontrib-devhelp==1.0.2
      - sphinxcontrib-htmlhelp==2.0.0
      - sphinxcontrib-jquery==4.1
      - sphinxcontrib-jsmath==1.0.1
      - sphinxcontrib-qthelp==1.0.3
      - sphinxcontrib-serializinghtml==1.1.5
      - testpath==0.6.0
      - tomli==1.2.3
      - tornado==6.1
      - traitlets==4.3.3
      - typing-extensions==4.1.1
      - urllib3==1.26.20
      - webencodings==0.5.1
      - zipp==3.6.0
prefix: /opt/conda/envs/cmlreaders

cmlreaders/test/test_readers.py::test_fromfile[ElectrodeCategoriesReader-/cmlreaders/cmlreaders/test/data/electrode_categories.txt-dict] cmlreaders/test/test_readers.py::test_fromfile[MontageReader-/cmlreaders/cmlreaders/test/data/pairs.json-DataFrame] cmlreaders/test/test_readers.py::test_fromfile[MontageReader-/cmlreaders/cmlreaders/test/data/contacts.json-DataFrame] cmlreaders/test/test_readers.py::test_fromfile[RamulatorEventLogReader-/cmlreaders/cmlreaders/test/data/event_log.json-DataFrame]
cmlreaders/test/test_readers.py::TestElectrodeCategoriesReader::test_load[R1111M-lens0] cmlreaders/test/test_readers.py::TestElectrodeCategoriesReader::test_load[R1052E-lens1] cmlreaders/test/test_readers.py::TestBaseReportDataReader::test_as_methods[R1409D-catFR1-1-classifier_summary-pyobject] cmlreaders/test/test_readers.py::TestBaseReportDataReader::test_as_methods[R1409D-catFR1-1-classifier_summary-dataframe] cmlreaders/test/test_readers.py::TestBaseReportDataReader::test_as_methods[R1409D-catFR1-1-classifier_summary-dict] cmlreaders/test/test_readers.py::TestBaseReportDataReader::test_as_methods[R1409D-catFR1-1-classifier_summary-recarray] cmlreaders/test/test_readers.py::TestBaseReportDataReader::test_to_methods[classifier_summary-hdf] cmlreaders/test/test_readers.py::TestReportSummaryReader::test_as_methods[session_summary-pyobject] cmlreaders/test/test_readers.py::TestReportSummaryReader::test_as_methods[session_summary-dataframe] cmlreaders/test/test_readers.py::TestReportSummaryReader::test_as_methods[session_summary-recarray] cmlreaders/test/test_readers.py::TestReportSummaryReader::test_as_methods[session_summary-dict] cmlreaders/test/test_readers.py::TestReportSummaryReader::test_load_nonstim_session cmlreaders/test/test_readers.py::TestClassifierContainerReader::test_as_methods[baseline_classifier-pyobject] cmlreaders/test/test_readers.py::TestClassifierContainerReader::test_as_methods[used_classifier-pyobject] cmlreaders/test/test_readers.py::TestClassifierContainerReader::test_to_methods[baseline_classifier-binary] cmlreaders/test/test_readers.py::TestClassifierContainerReader::test_to_methods[used_classifier-binary]
cmlreaders/test/test_readers.py::TestTextReader::test_as_methods[R1389J-0-voxel_coordinates-dataframe] cmlreaders/test/test_readers.py::TestTextReader::test_as_methods[R1389J-0-voxel_coordinates-recarray] cmlreaders/test/test_readers.py::TestTextReader::test_as_methods[R1389J-0-voxel_coordinates-dict] cmlreaders/test/test_readers.py::TestTextReader::test_as_methods[R1389J-0-leads-dataframe] cmlreaders/test/test_readers.py::TestTextReader::test_as_methods[R1389J-0-leads-recarray] cmlreaders/test/test_readers.py::TestTextReader::test_as_methods[R1389J-0-leads-dict] cmlreaders/test/test_readers.py::TestTextReader::test_as_methods[R1389J-0-classifier_excluded_leads-dataframe] cmlreaders/test/test_readers.py::TestTextReader::test_as_methods[R1389J-0-classifier_excluded_leads-recarray] cmlreaders/test/test_readers.py::TestTextReader::test_as_methods[R1389J-0-classifier_excluded_leads-dict] cmlreaders/test/test_readers.py::TestTextReader::test_as_methods[R1389J-0-good_leads-dataframe] cmlreaders/test/test_readers.py::TestTextReader::test_as_methods[R1389J-0-good_leads-recarray] cmlreaders/test/test_readers.py::TestTextReader::test_as_methods[R1389J-0-good_leads-dict] cmlreaders/test/test_readers.py::TestTextReader::test_as_methods[R1389J-0-jacksheet-dataframe] cmlreaders/test/test_readers.py::TestTextReader::test_as_methods[R1389J-0-jacksheet-recarray] cmlreaders/test/test_readers.py::TestTextReader::test_as_methods[R1389J-0-jacksheet-dict] cmlreaders/test/test_readers.py::TestTextReader::test_as_methods[R1389J-0-area-dataframe] cmlreaders/test/test_readers.py::TestTextReader::test_as_methods[R1389J-0-area-recarray] cmlreaders/test/test_readers.py::TestTextReader::test_as_methods[R1389J-0-area-dict] cmlreaders/test/test_readers.py::TestTextReader::test_read_jacksheet cmlreaders/test/test_readers.py::TestTextReader::test_to_methods[R1389J-0-voxel_coordinates-json] cmlreaders/test/test_readers.py::TestTextReader::test_to_methods[R1389J-0-voxel_coordinates-csv] cmlreaders/test/test_readers.py::TestTextReader::test_to_methods[R1389J-0-leads-json] cmlreaders/test/test_readers.py::TestTextReader::test_to_methods[R1389J-0-leads-csv] cmlreaders/test/test_readers.py::TestTextReader::test_to_methods[R1389J-0-classifier_excluded_leads-json] cmlreaders/test/test_readers.py::TestTextReader::test_to_methods[R1389J-0-classifier_excluded_leads-csv] cmlreaders/test/test_readers.py::TestTextReader::test_to_methods[R1389J-0-good_leads-json] cmlreaders/test/test_readers.py::TestTextReader::test_to_methods[R1389J-0-good_leads-csv] cmlreaders/test/test_readers.py::TestTextReader::test_to_methods[R1389J-0-jacksheet-json] cmlreaders/test/test_readers.py::TestTextReader::test_to_methods[R1389J-0-jacksheet-csv] cmlreaders/test/test_readers.py::TestTextReader::test_to_methods[R1389J-0-area-json] cmlreaders/test/test_readers.py::TestTextReader::test_to_methods[R1389J-0-area-csv] cmlreaders/test/test_readers.py::TestCSVReader::test_as_methods[R1409D-0-electrode_coordinates-dataframe] cmlreaders/test/test_readers.py::TestCSVReader::test_as_methods[R1409D-0-electrode_coordinates-recarray] cmlreaders/test/test_readers.py::TestCSVReader::test_as_methods[R1409D-0-electrode_coordinates-dict] cmlreaders/test/test_readers.py::TestCSVReader::test_as_methods[R1409D-0-prior_stim_results-dataframe] cmlreaders/test/test_readers.py::TestCSVReader::test_as_methods[R1409D-0-prior_stim_results-recarray] cmlreaders/test/test_readers.py::TestCSVReader::test_as_methods[R1409D-0-prior_stim_results-dict] cmlreaders/test/test_readers.py::TestCSVReader::test_as_methods[R1409D-0-target_selection_table-dataframe] cmlreaders/test/test_readers.py::TestCSVReader::test_as_methods[R1409D-0-target_selection_table-recarray] cmlreaders/test/test_readers.py::TestCSVReader::test_as_methods[R1409D-0-target_selection_table-dict] cmlreaders/test/test_readers.py::TestCSVReader::test_to_methods[R1409D-0-electrode_coordinates-json] cmlreaders/test/test_readers.py::TestCSVReader::test_to_methods[R1409D-0-electrode_coordinates-csv] cmlreaders/test/test_readers.py::TestCSVReader::test_to_methods[R1409D-0-prior_stim_results-json] cmlreaders/test/test_readers.py::TestCSVReader::test_to_methods[R1409D-0-prior_stim_results-csv] cmlreaders/test/test_readers.py::TestCSVReader::test_to_methods[R1409D-0-target_selection_table-json] cmlreaders/test/test_readers.py::TestCSVReader::test_to_methods[R1409D-0-target_selection_table-csv] cmlreaders/test/test_readers.py::TestRamulatorEventLogReader::test_as_methods[R1409D-catFR1-1-event_log-dataframe] cmlreaders/test/test_readers.py::TestRamulatorEventLogReader::test_as_methods[R1409D-catFR1-1-event_log-recarray] cmlreaders/test/test_readers.py::TestRamulatorEventLogReader::test_as_methods[R1409D-catFR1-1-event_log-dict] cmlreaders/test/test_readers.py::TestRamulatorEventLogReader::test_to_methods[R1409D-catFR1-1-event_log-json] cmlreaders/test/test_readers.py::TestRamulatorEventLogReader::test_to_methods[R1409D-catFR1-1-event_log-csv] cmlreaders/test/test_readers.py::TestBasicJSONReader::test_load cmlreaders/test/test_readers.py::TestEEGMetaReader::test_load cmlreaders/test/test_readers.py::TestEventReader::test_load cmlreaders/test/test_readers.py::TestMontageReader::test_load[contacts] cmlreaders/test/test_readers.py::TestMontageReader::test_load[pairs] cmlreaders/test/test_readers.py::TestLocalizationReader::test_load
cmlreaders/readers/electrodes.py cmlreaders/base_reader.py
cmlreaders/readers/electrodes.py cmlreaders/base_reader.py