Querying Materials Data from the Materials Project using Pymatgen#

In this tutorial, we will learn how to query material data from the Materials Project database using pymatgen, a powerful Python library for materials science.

By the end of this tutorial, you will be able to:

  • Set up your Materials Project API key

  • Query materials by formula, elements, or material ID

  • Retrieve structural, thermodynamic, and electronic properties

  • Download .cif files for visualization and simulations

  • Perform a sneak peek into structure manipulation using pymatgen

In the previous tutorials we have become familiar with Materials Project and Pymatgen. Now we are going to use them together.


Step 1 - Import Necessary Libraries#

Before importing the libraries, we make sure that they are installed.

# Google Colab setup
!pip install pymatgen mp-api
Requirement already satisfied: pymatgen in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (2025.6.14)
Requirement already satisfied: mp-api in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (0.45.8)
Requirement already satisfied: bibtexparser>=1.4.0 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from pymatgen) (1.4.3)
Requirement already satisfied: joblib>=1 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from pymatgen) (1.5.2)
Requirement already satisfied: matplotlib>=3.8 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from pymatgen) (3.10.6)
Requirement already satisfied: monty>=2025.1.9 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from pymatgen) (2025.3.3)
Requirement already satisfied: networkx>=2.7 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from pymatgen) (3.5)
Requirement already satisfied: numpy<3,>=1.25.0 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from pymatgen) (2.3.2)
Requirement already satisfied: orjson<4,>=3.10 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from pymatgen) (3.11.3)
Requirement already satisfied: palettable>=3.3.3 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from pymatgen) (3.3.3)
Requirement already satisfied: pandas>=2 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from pymatgen) (2.3.2)
Requirement already satisfied: plotly>=5.0.0 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from pymatgen) (6.3.0)
Requirement already satisfied: requests>=2.32 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from pymatgen) (2.32.5)
Requirement already satisfied: ruamel.yaml>=0.17.0 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from pymatgen) (0.18.15)
Requirement already satisfied: scipy>=1.13.0 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from pymatgen) (1.16.1)
Requirement already satisfied: spglib>=2.5 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from pymatgen) (2.6.0)
Requirement already satisfied: sympy>=1.3 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from pymatgen) (1.14.0)
Requirement already satisfied: tabulate>=0.9 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from pymatgen) (0.9.0)
Requirement already satisfied: tqdm>=4.60 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from pymatgen) (4.67.1)
Requirement already satisfied: uncertainties>=3.1.4 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from pymatgen) (3.2.3)
Requirement already satisfied: setuptools in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from mp-api) (78.1.1)
Requirement already satisfied: msgpack in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from mp-api) (1.1.1)
Requirement already satisfied: maggma>=0.57.1 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from mp-api) (0.72.0)
Requirement already satisfied: typing-extensions>=3.7.4.1 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from mp-api) (4.15.0)
Requirement already satisfied: emmet-core>=0.84.3rc6 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from mp-api) (0.84.10rc2)
Requirement already satisfied: smart_open in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from mp-api) (7.3.0.post1)
Requirement already satisfied: pyparsing>=2.0.3 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from bibtexparser>=1.4.0->pymatgen) (3.2.3)
Requirement already satisfied: pydantic>=2.0 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from emmet-core>=0.84.3rc6->mp-api) (2.11.7)
Requirement already satisfied: pydantic-settings>=2.0 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from emmet-core>=0.84.3rc6->mp-api) (2.10.1)
Requirement already satisfied: pymatgen-io-validation>=0.1.0 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from emmet-core>=0.84.3rc6->mp-api) (0.1.1)
Requirement already satisfied: pybtex~=0.24 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from emmet-core>=0.84.3rc6->mp-api) (0.25.1)
Requirement already satisfied: PyYAML>=3.01 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from pybtex~=0.24->emmet-core>=0.84.3rc6->mp-api) (6.0.2)
Requirement already satisfied: latexcodec>=1.0.4 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from pybtex~=0.24->emmet-core>=0.84.3rc6->mp-api) (3.0.1)
Requirement already satisfied: pymongo<4.11,>=4.2.0 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from maggma>=0.57.1->mp-api) (4.10.1)
Requirement already satisfied: mongomock>=3.10.0 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from maggma>=0.57.1->mp-api) (4.3.0)
Requirement already satisfied: pydash>=4.1.0 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from maggma>=0.57.1->mp-api) (8.0.5)
Requirement already satisfied: jsonschema>=3.1.1 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from maggma>=0.57.1->mp-api) (4.25.1)
Requirement already satisfied: jsonlines>=4.0.0 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from maggma>=0.57.1->mp-api) (4.0.0)
Requirement already satisfied: aioitertools>=0.5.1 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from maggma>=0.57.1->mp-api) (0.12.0)
Requirement already satisfied: pyzmq>=25.1.1 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from maggma>=0.57.1->mp-api) (27.0.2)
Requirement already satisfied: dnspython>=1.16.0 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from maggma>=0.57.1->mp-api) (2.8.0)
Requirement already satisfied: sshtunnel>=0.1.5 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from maggma>=0.57.1->mp-api) (0.4.0)
Requirement already satisfied: boto3>=1.20.41 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from maggma>=0.57.1->mp-api) (1.40.25)
Requirement already satisfied: python-dateutil>=2.8.2 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from maggma>=0.57.1->mp-api) (2.9.0.post0)
Requirement already satisfied: botocore<1.41.0,>=1.40.25 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from boto3>=1.20.41->maggma>=0.57.1->mp-api) (1.40.25)
Requirement already satisfied: jmespath<2.0.0,>=0.7.1 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from boto3>=1.20.41->maggma>=0.57.1->mp-api) (1.0.1)
Requirement already satisfied: s3transfer<0.14.0,>=0.13.0 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from boto3>=1.20.41->maggma>=0.57.1->mp-api) (0.13.1)
Requirement already satisfied: urllib3!=2.2.0,<3,>=1.25.4 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from botocore<1.41.0,>=1.40.25->boto3>=1.20.41->maggma>=0.57.1->mp-api) (2.5.0)
Requirement already satisfied: six>=1.5 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from python-dateutil>=2.8.2->maggma>=0.57.1->mp-api) (1.17.0)
Requirement already satisfied: attrs>=19.2.0 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from jsonlines>=4.0.0->maggma>=0.57.1->mp-api) (25.3.0)
Requirement already satisfied: jsonschema-specifications>=2023.03.6 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from jsonschema>=3.1.1->maggma>=0.57.1->mp-api) (2025.4.1)
Requirement already satisfied: referencing>=0.28.4 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from jsonschema>=3.1.1->maggma>=0.57.1->mp-api) (0.36.2)
Requirement already satisfied: rpds-py>=0.7.1 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from jsonschema>=3.1.1->maggma>=0.57.1->mp-api) (0.27.1)
Requirement already satisfied: contourpy>=1.0.1 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from matplotlib>=3.8->pymatgen) (1.3.3)
Requirement already satisfied: cycler>=0.10 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from matplotlib>=3.8->pymatgen) (0.12.1)
Requirement already satisfied: fonttools>=4.22.0 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from matplotlib>=3.8->pymatgen) (4.59.2)
Requirement already satisfied: kiwisolver>=1.3.1 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from matplotlib>=3.8->pymatgen) (1.4.9)
Requirement already satisfied: packaging>=20.0 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from matplotlib>=3.8->pymatgen) (25.0)
Requirement already satisfied: pillow>=8 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from matplotlib>=3.8->pymatgen) (11.3.0)
Requirement already satisfied: pytz in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from mongomock>=3.10.0->maggma>=0.57.1->mp-api) (2025.2)
Requirement already satisfied: sentinels in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from mongomock>=3.10.0->maggma>=0.57.1->mp-api) (1.1.1)
Requirement already satisfied: tzdata>=2022.7 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from pandas>=2->pymatgen) (2025.2)
Requirement already satisfied: narwhals>=1.15.1 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from plotly>=5.0.0->pymatgen) (2.3.0)
Requirement already satisfied: annotated-types>=0.6.0 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from pydantic>=2.0->emmet-core>=0.84.3rc6->mp-api) (0.7.0)
Requirement already satisfied: pydantic-core==2.33.2 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from pydantic>=2.0->emmet-core>=0.84.3rc6->mp-api) (2.33.2)
Requirement already satisfied: typing-inspection>=0.4.0 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from pydantic>=2.0->emmet-core>=0.84.3rc6->mp-api) (0.4.1)
Requirement already satisfied: python-dotenv>=0.21.0 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from pydantic-settings>=2.0->emmet-core>=0.84.3rc6->mp-api) (1.1.1)
Requirement already satisfied: charset_normalizer<4,>=2 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from requests>=2.32->pymatgen) (3.4.3)
Requirement already satisfied: idna<4,>=2.5 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from requests>=2.32->pymatgen) (3.10)
Requirement already satisfied: certifi>=2017.4.17 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from requests>=2.32->pymatgen) (2025.8.3)
Requirement already satisfied: ruamel.yaml.clib>=0.2.7 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from ruamel.yaml>=0.17.0->pymatgen) (0.2.12)
Requirement already satisfied: paramiko>=2.7.2 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from sshtunnel>=0.1.5->maggma>=0.57.1->mp-api) (4.0.0)
Requirement already satisfied: bcrypt>=3.2 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from paramiko>=2.7.2->sshtunnel>=0.1.5->maggma>=0.57.1->mp-api) (4.3.0)
Requirement already satisfied: cryptography>=3.3 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from paramiko>=2.7.2->sshtunnel>=0.1.5->maggma>=0.57.1->mp-api) (45.0.7)
Requirement already satisfied: invoke>=2.0 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from paramiko>=2.7.2->sshtunnel>=0.1.5->maggma>=0.57.1->mp-api) (2.2.0)
Requirement already satisfied: pynacl>=1.5 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from paramiko>=2.7.2->sshtunnel>=0.1.5->maggma>=0.57.1->mp-api) (1.5.0)
Requirement already satisfied: cffi>=1.14 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from cryptography>=3.3->paramiko>=2.7.2->sshtunnel>=0.1.5->maggma>=0.57.1->mp-api) (1.17.1)
Requirement already satisfied: pycparser in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from cffi>=1.14->cryptography>=3.3->paramiko>=2.7.2->sshtunnel>=0.1.5->maggma>=0.57.1->mp-api) (2.22)
Requirement already satisfied: mpmath<1.4,>=1.1.0 in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from sympy>=1.3->pymatgen) (1.3.0)
Requirement already satisfied: wrapt in /home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages (from smart_open->mp-api) (1.17.3)
# Import main tools
from mp_api.client import MPRester
from pymatgen.core import Structure

# We will also use pandas to make the data more readable
import pandas as pd
/home/paladin/anaconda3/envs/matdata/lib/python3.11/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
  from .autonotebook import tqdm as notebook_tqdm

Step 2 - Setting Up the API Key#

To query the Materials Project database, you need an API key. This is necessary to make any request to the Materials Project API and there’s a unique key for each Materials Project account.

Important

You should not share your API key with anyone.

Steps to get you API key:

  1. Go to Materials Project

  2. Log in or create a free account. This step was done when we were introducing Materials Project. If you need more guidance, please revisit the tutorial: Exploring Materials Project

  3. We are going to the main page of Materials Project after logging in, which should look like this:

  1. Then we go to the top right and click on the API button and it will shows us this new page:

Your personal API key should appear where the red line is located in the image. You can select and copy it, and then paste it in the following cell as indicated:

Note

To run this notebook, you must provide your own Materials Project API key. Log in as indicated in Materials Project → Dashboard → API Key. Replace "YOUR_API_KEY_HERE" in the code cell below.

# Replace with your own API key! (keep the "" signs)
API_KEY = "YOUR_API_KEY_HERE"


# the following lines are only to make sure
# that you are working with your API key
# please do not modify them in any way

if API_KEY == "YOUR_API_KEY_HERE":
    print("⚠️ Please replace \"YOUR_API_KEY_HERE\" with your Materials Project API key.")
    mpr = None
else:
    mpr = MPRester(API_KEY)
    print("✅ MPRester initialized successfully!")
⚠️ Please replace "YOUR_API_KEY_HERE" with your Materials Project API key.

Step 3 - Querying by Chemical Formula#

Let us start with a simple query: searching for all materials with the formula \(\text{CaTiO}_3\).

MPRester.query() lets us specify:

  • The criteria (what we are looking for)

  • The properties (what we want return)

There are plenty of properties to retrieve from the query. Here is a list of all of them:

[‘builder_meta’, ‘nsites’, ‘elements’, ‘nelements’, ‘composition’, ‘composition_reduced’, ‘formula_pretty’, ‘formula_anonymous’, ‘chemsys’, ‘volume’, ‘density’, ‘density_atomic’, ‘symmetry’, ‘property_name’, ‘material_id’, ‘deprecated’, ‘deprecation_reasons’, ‘last_updated’, ‘origins’, ‘warnings’, ‘structure’, ‘task_ids’, ‘uncorrected_energy_per_atom’, ‘energy_per_atom’, ‘formation_energy_per_atom’, ‘energy_above_hull’, ‘is_stable’, ‘equilibrium_reaction_energy_per_atom’, ‘decomposes_to’, ‘xas’, ‘grain_boundaries’, ‘band_gap’, ‘cbm’, ‘vbm’, ‘efermi’, ‘is_gap_direct’, ‘is_metal’, ‘es_source_calc_id’, ‘bandstructure’, ‘dos’, ‘dos_energy_up’, ‘dos_energy_down’, ‘is_magnetic’, ‘ordering’, ‘total_magnetization’, ‘total_magnetization_normalized_vol’, ‘total_magnetization_normalized_formula_units’, ‘num_magnetic_sites’, ‘num_unique_magnetic_sites’, ‘types_of_magnetic_species’, ‘bulk_modulus’, ‘shear_modulus’, ‘universal_anisotropy’, ‘homogeneous_poisson’, ‘e_total’, ‘e_ionic’, ‘e_electronic’, ‘n’, ‘e_ij_max’, ‘weighted_surface_energy_EV_PER_ANG2’, ‘weighted_surface_energy’, ‘weighted_work_function’, ‘surface_anisotropy’, ‘shape_factor’, ‘has_reconstructed’, ‘possible_species’, ‘has_props’, ‘theoretical’, ‘database_Ids’]

For now, we will start with a simple example that shows how to extract the following properties of the list provided above:

  • Material ID (material_id) \(\rightarrow\) Unique identifier used by Materials Project

  • Formula (formula_pretty) \(\rightarrow\) Simplified chemical formula

  • Formation energy per atom (formation_energy_per_atom) \(\rightarrow\) Energy required to form the compound (eV/atom)

  • Band gap (band_gap) \(\rightarrow\) Band gap energy in electronvolts (eV)

# Query CaTiO3 structures
results = mpr.materials.summary.search(
    formula="CaTiO3",
    fields=[
        "material_id",
        "formula_pretty",
        "formation_energy_per_atom",
        "band_gap"
    ]
)

# Convert results to DataFrame
df = pd.DataFrame([
    {
        "material_id": r.material_id,
        "formula": r.formula_pretty,
        "formation_energy": r.formation_energy_per_atom,
        "band_gap": r.band_gap
    }
    for r in results
])

df
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[4], line 2
      1 # Query CaTiO3 structures
----> 2 results = mpr.materials.summary.search(
      3     formula="CaTiO3",
      4     fields=[
      5         "material_id",
      6         "formula_pretty",
      7         "formation_energy_per_atom",
      8         "band_gap"
      9     ]
     10 )
     12 # Convert results to DataFrame
     13 df = pd.DataFrame([
     14     {
     15         "material_id": r.material_id,
   (...)     20     for r in results
     21 ])

AttributeError: 'NoneType' object has no attribute 'materials'

Important

You can avoid these errors by replacing your API key above


Step 4 - Querying by Material ID#

Suppose we want to retrieve detailed information for one specific material. We will use its Materials Project ID

# Pick the first material ID from our query
material_id = df["material_id"].iloc[0]
print("Using material ID:", material_id)

# Fetch the structure directly
structure = mpr.get_structure_by_material_id(material_id)
structure
Using material ID: mp-3442
Retrieving MaterialsDoc documents: 100%|██████████| 1/1 [00:00<00:00, 7557.30it/s]
Structure Summary
Lattice
    abc : 5.441143344248945 5.441143344248945 5.441143344248945
 angles : 120.84549073210634 120.84549073210634 88.54170096725916
 volume : 112.41312515722095
      A : np.float64(-2.68573015) np.float64(2.68573015) np.float64(3.89611961)
      B : np.float64(2.68573015) np.float64(-2.68573015) np.float64(3.89611961)
      C : np.float64(2.68573015) np.float64(2.68573015) np.float64(-3.89611961)
    pbc : True True True
PeriodicSite: Ca (2.686, 0.0, 1.948) [0.25, 0.75, 0.5]
PeriodicSite: Ca (-2.22e-16, 2.686, 1.948) [0.75, 0.25, 0.5]
PeriodicSite: Ti (0.0, 0.0, 3.896) [0.5, 0.5, -0.0]
PeriodicSite: Ti (0.0, 0.0, 0.0) [0.0, -0.0, -0.0]
PeriodicSite: O (-1.028, 1.658, 3.896) [0.8087, 0.3087, 0.1174]
PeriodicSite: O (1.028, 1.658, 2.22e-16) [0.3087, 0.1913, 0.5]
PeriodicSite: O (1.658, 1.028, 3.896) [0.6913, 0.8087, 0.5]
PeriodicSite: O (3.713, 1.028, 7.015e-17) [0.1913, 0.6913, 0.8826]
PeriodicSite: O (-1.11e-16, 1.11e-16, 5.844) [0.75, 0.75, -0.0]
PeriodicSite: O (0.0, 0.0, 1.948) [0.25, 0.25, -0.0]

Step 5 - Downloading the Structure as a .cif File#

Once we have the structure, we can save it locally in .cif format, which could be use for visualization, just like the previous tutorial, or simulations.

# Save CIF file
structure.to(filename="CaTiO3_from_MP.cif")
print("CIF file saved as 'CaTiO3_from_MP.cif'")
CIF file saved as 'CaTiO3_from_MP.cif'

Step 6 - Exploring Structure Properties#

Just as we learned on the previous tutorial, we can apply that knowledge and inspect the structure properties.

  • Lattice parameters (a, b, c)

  • Angles (α, β, γ)

  • Number of sites

  • Atomic species

# Lattice parameters
lattice = structure.lattice
print("Lattice parameters (Å):", lattice.abc)
print("Lattice angles (°):", lattice.angles)
print("Number of sites:", len(structure))
print("Atomic species:", structure.species)
Lattice parameters (Å): (5.441143344248945, 5.441143344248945, 5.441143344248945)
Lattice angles (°): (120.84549073210634, 120.84549073210634, 88.54170096725916)
Number of sites: 10
Atomic species: [Element Ca, Element Ca, Element Ti, Element Ti, Element O, Element O, Element O, Element O, Element O, Element O]

Step 7 (optional) - Teaser: Structure Manipulation#

In materials science, it’s often necessary to modify atomic structures to simulate real-world phenomena or design new materials. Two common manipulations are:

  • Vacancy creation → Removing an atom from the structure

    • Useful for studying defects, diffusion, and electronic properties.

  • Substitution → Replacing one atom with a different element

    • Used to model doping, alloying, and tuning material properties like band gaps or magnetism.

These techniques allow researchers to predict how structural modifications influence material behavior, helping design more efficient semiconductors, batteries, catalysts, and more.

Code Example: Creating Vacancies and Substitutions#

Pymatgen lets us manipulate structures in powerful ways.
Here’s a quick teaser:

  • Create a vacancy by removing an atom

  • Substitute one atom for another

print("Original structure:")
print(structure)

# --- 1. Creating a vacancy ---
# Let's remove the first calcium atom
vacancy_structure = structure.copy()
vacancy_structure.remove_sites([0])  # Index of the atom to remove

print("\nStructure after creating a Ca vacancy:")
print(vacancy_structure)
Original structure:
Full Formula (Ca2 Ti2 O6)
Reduced Formula: CaTiO3
abc   :   5.441143   5.441143   5.441143
angles: 120.845491 120.845491  88.541701
pbc   :       True       True       True
Sites (10)
  #  SP           a          b          c    magmom
---  ----  --------  ---------  ---------  --------
  0  Ca    0.25       0.75       0.5             -0
  1  Ca    0.75       0.25       0.5             -0
  2  Ti    0.5        0.5       -0               -0
  3  Ti    0         -0         -0               -0
  4  O     0.808697   0.308697   0.117394         0
  5  O     0.308697   0.191303   0.5              0
  6  O     0.691303   0.808697   0.5              0
  7  O     0.191303   0.691303   0.882606         0
  8  O     0.75       0.75      -0               -0
  9  O     0.25       0.25      -0               -0

Structure after creating a Ca vacancy:
Full Formula (Ca1 Ti2 O6)
Reduced Formula: CaTi2O6
abc   :   5.441143   5.441143   5.441143
angles: 120.845491 120.845491  88.541701
pbc   :       True       True       True
Sites (9)
  #  SP           a          b          c    magmom
---  ----  --------  ---------  ---------  --------
  0  Ca    0.75       0.25       0.5             -0
  1  Ti    0.5        0.5       -0               -0
  2  Ti    0         -0         -0               -0
  3  O     0.808697   0.308697   0.117394         0
  4  O     0.308697   0.191303   0.5              0
  5  O     0.691303   0.808697   0.5              0
  6  O     0.191303   0.691303   0.882606         0
  7  O     0.75       0.75      -0               -0
  8  O     0.25       0.25      -0               -0
from pymatgen.transformations.standard_transformations import SubstitutionTransformation

# Substitute Ti with Zr
transformation = SubstitutionTransformation({"Ti": "Zr"})
substituted_structure = transformation.apply_transformation(structure)

print("Original species:", structure.species)
print("After substitution:", substituted_structure.species)
Original species: [Element Ca, Element Ca, Element Ti, Element Ti, Element O, Element O, Element O, Element O, Element O, Element O]
After substitution: [Element Ca, Element Ca, Element Zr, Element Zr, Element O, Element O, Element O, Element O, Element O, Element O]

Step 8 - Summary#

In this tutorial, we learned how to:

  • Set up and authenticate with the Materials Project API

  • Query materials by formula, elements, or material ID

  • Retrieve properties like formation energy, band gap, and crystal system

  • Save structures as .cif files

  • Peek into pymatgen’s structure manipulation capabilities


Next Steps#

In the next tutorial, we’ll:

  • Perform data mining using Materials Project queries

  • Analyze large sets of materials to extract trends and correlations

  • Use plots and statistics to gain insights into materials properties