Use pandas' cut method to classify the stars in the data set of Problem P9.2.3 according to their temperature by placing them into the bins labeled M, K, G, F, A, B, and O with left edges (in K) at 2400, 3700, 5200, 6000, 7500, 10 000, and 30 000.
Hence modify the code in the solution to this problem to plot the stars in a color appropriate to their temperature by establishing the following mapping:
Hint: pandas provides a map method for mapping input values from an existing column to output values in a new column using a dictionary.
Solution P9.4.1
Here is one solution:
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.ticker import ScalarFormatter
# Read in data and calculate stellar temperature from the Ballesteros formula.
df = pd.read_csv("hygdata_v3-abridged.csv")
df["T"] = 4600 * (1 / (0.92 * df["ci"] + 1.7) + 1 / (0.92 * df["ci"] + 0.62))
# Fill NaN teperatures with 0.
df["T"] = df["T"].fillna(0)
# Assign stellar temperatures to bins: invalid data (formerly NaN temperatures)
# get assigned to the first bin. The temperature bin edges below categorize
# the stars by stellar type M, K, G, F, A, B, O. labels=False ensures that
# we get indexes and not category labels.
df["cidx"] = pd.cut(
df["T"],
bins=(0, 2400, 3700, 5200, 6000, 7500, 10000, 30000),
labels=list("MKGFABO"),
right=False,
)
star_rgbs = (
"#ffffff",
"#FFB56C",
"#FFDAB5",
"#FFEDE3",
"#F9F5FF",
"#D5E0FF",
"#A2C0FF",
"#92B5FF",
)
color_mapping = {
"M": "#FFB56C",
"K": "#FFDAB5",
"G": "#FFEDE3",
"F": "#F9F5FF",
"A": "#D5E0FF",
"B": "#A2C0FF",
"O": "#92B5FF",
}
df["rgb"] = df["cidx"].map(color_mapping)
# Set the aspect ratio for maximum clarity.
DPI = 100
width, height = 600, 800
fig, ax = plt.subplots(
figsize=(width / DPI, height / DPI), subplot_kw={"facecolor": "k"}
)
ax.set_facecolor("k")
# Log-log plot with suitable ticks and labels.
ax.scatter(df["T"], df["lum"], s=0.5, c=df["rgb"])
ax.set_yscale("log")
ax.set_xscale("log")
ax.set_ylim(1.0e-6, 1.0e5)
ax.set_xlim(30000, 1000)
ax.set_xticks([30000, 10000, 5000, 3000, 1000])
# The chosen xticks don't get used unless we explicitly set a ScalarFormatter.
ax.get_xaxis().set_major_formatter(ScalarFormatter())
ax.set_xlabel("Temperature /K")
ax.set_ylabel("Luminosity relative to Sun")
plt.tight_layout()
plt.show()
The resulting image is shown below.
Coloured Hertzsprung-Russell diagram
The banding effect here is because of the relatively low resolution of the temperature bins: it could be removed by interpolation or by using more bins.