зеркало из https://github.com/microsoft/torchgeo.git
Improve customizability of Landsat band plots (#1378)
* Improve customizability of Landsat band plots * Better xlabel * Display default values * More band customization * More band customization * Fix ylim * Fix vertical centering * Fewer sensors * flake8 fix * usetex * Shorter, simpler * Wider thermal bands padding
This commit is contained in:
Родитель
02f2a6cb81
Коммит
9e4f7d12d4
|
@ -1,31 +1,50 @@
|
|||
Satellite name,Sensor name,Band number,Wavelength start (μm),Wavelength width,Color,Resolution (m)
|
||||
Landsat 4-5,tm,6,10.4,2.1,#8c564b,120
|
||||
Landsat 7,etm,6,10.4,2.1,#8c564b,60
|
||||
Landsat 8-9,tirs,10,10.6,0.59,#8c564b,100
|
||||
Landsat 8-9,tirs,11,11.5,1.01,#8c564b,100
|
||||
Landsat 1-5,mss,1,0.5,0.1,#2ca02c,60
|
||||
Landsat 1-5,mss,2,0.6,0.1,#d62728,60
|
||||
Landsat 1-5,mss,3,0.7,0.1,#e377c2,60
|
||||
Landsat 1-5,mss,4,0.8,0.3,#ff7f0e,60
|
||||
Landsat 4-5,tm,1,0.45,0.07,#1f77b4,30
|
||||
Landsat 4-5,tm,2,0.52,0.08,#2ca02c,30
|
||||
Landsat 4-5,tm,3,0.63,0.06,#d62728,30
|
||||
Landsat 4-5,tm,4,0.76,0.14,#e377c2,30
|
||||
Landsat 4-5,tm,5,1.55,0.2,#ff7f0e,30
|
||||
Landsat 4-5,tm,7,2.08,0.27,#7f7f7f,30
|
||||
Landsat 7,etm,1,0.45,0.07,#1f77b4,30
|
||||
Landsat 7,etm,2,0.52,0.08,#2ca02c,30
|
||||
Landsat 7,etm,3,0.63,0.06,#d62728,30
|
||||
Landsat 7,etm,4,0.77,0.13,#e377c2,30
|
||||
Landsat 7,etm,5,1.55,0.2,#ff7f0e,30
|
||||
Landsat 7,etm,7,2.09,0.26,#7f7f7f,30
|
||||
Landsat 7,etm,8,0.52,0.38,#bcbd22,15
|
||||
Landsat 8-9,oli,1,0.43,0.02,#17becf,30
|
||||
Landsat 8-9,oli,2,0.45,0.06,#1f77b4,30
|
||||
Landsat 8-9,oli,3,0.53,0.06,#2ca02c,30
|
||||
Landsat 8-9,oli,4,0.64,0.03,#d62728,30
|
||||
Landsat 8-9,oli,5,0.85,0.03,#e377c2,30
|
||||
Landsat 8-9,oli,6,1.57,0.08,#ff7f0e,30
|
||||
Landsat 8-9,oli,7,2.11,0.18,#7f7f7f,30
|
||||
Landsat 8-9,oli,9,1.36,0.02,#9467bd,30
|
||||
Landsat 8-9,oli,8,0.5,0.18,#bcbd22,15
|
||||
Satellite,Sensor,Band,Wavelength Start (μm),Wavelength Width,Color,Resolution (m)
|
||||
|
||||
Landsat 1--2,RBV,1,0.475,0.1,#1f77b4,80
|
||||
Landsat 1--2,RBV,2,0.58,0.1,#2ca02c,80
|
||||
Landsat 1--2,RBV,3,0.69,0.14,#d62728,80
|
||||
|
||||
Landsat 3,RBV,1,0.505,0.245,#bcbd22,40
|
||||
|
||||
Landsat 1--5,MSS,1,0.5,0.1,#2ca02c,80
|
||||
Landsat 1--5,MSS,2,0.6,0.1,#d62728,80
|
||||
Landsat 1--5,MSS,3,0.7,0.1,#e377c2,80
|
||||
Landsat 1--5,MSS,4,0.8,0.3,#ff7f0e,80
|
||||
|
||||
Landsat 4--5,TM,1,0.45,0.07,#1f77b4,30
|
||||
Landsat 4--5,TM,2,0.52,0.08,#2ca02c,30
|
||||
Landsat 4--5,TM,3,0.63,0.06,#d62728,30
|
||||
Landsat 4--5,TM,4,0.76,0.14,#e377c2,30
|
||||
Landsat 4--5,TM,5,1.55,0.2,#ff7f0e,30
|
||||
Landsat 4--5,TM,6,10.4,2.1,#8c564b,120
|
||||
Landsat 4--5,TM,7,2.08,0.27,#7f7f7f,30
|
||||
|
||||
Landsat 6,ETM,1,0.45,0.07,#1f77b4,30
|
||||
Landsat 6,ETM,2,0.52,0.08,#2ca02c,30
|
||||
Landsat 6,ETM,3,0.63,0.06,#d62728,30
|
||||
Landsat 6,ETM,4,0.76,0.14,#e377c2,30
|
||||
Landsat 6,ETM,5,1.55,0.2,#ff7f0e,30
|
||||
Landsat 6,ETM,6,10.4,2.1,#8c564b,120
|
||||
Landsat 6,ETM,7,2.08,0.27,#7f7f7f,30
|
||||
Landsat 6,ETM,8,0.52,0.38,#bcbd22,15
|
||||
|
||||
Landsat 7,ETM+,1,0.45,0.07,#1f77b4,30
|
||||
Landsat 7,ETM+,2,0.52,0.08,#2ca02c,30
|
||||
Landsat 7,ETM+,3,0.63,0.06,#d62728,30
|
||||
Landsat 7,ETM+,4,0.77,0.13,#e377c2,30
|
||||
Landsat 7,ETM+,5,1.55,0.2,#ff7f0e,30
|
||||
Landsat 7,ETM+,6,10.4,2.1,#8c564b,60
|
||||
Landsat 7,ETM+,7,2.08,0.27,#7f7f7f,30
|
||||
Landsat 7,ETM+,8,0.52,0.38,#bcbd22,15
|
||||
|
||||
Landsat 8--9,OLI/TIRS,1,0.43,0.02,#17becf,30
|
||||
Landsat 8--9,OLI/TIRS,2,0.45,0.06,#1f77b4,30
|
||||
Landsat 8--9,OLI/TIRS,3,0.53,0.06,#2ca02c,30
|
||||
Landsat 8--9,OLI/TIRS,4,0.64,0.03,#d62728,30
|
||||
Landsat 8--9,OLI/TIRS,5,0.85,0.03,#e377c2,30
|
||||
Landsat 8--9,OLI/TIRS,6,1.57,0.08,#ff7f0e,30
|
||||
Landsat 8--9,OLI/TIRS,7,2.11,0.18,#7f7f7f,30
|
||||
Landsat 8--9,OLI/TIRS,8,0.5,0.18,#bcbd22,15
|
||||
Landsat 8--9,OLI/TIRS,9,1.36,0.02,#9467bd,30
|
||||
Landsat 8--9,OLI/TIRS,10,10.6,0.59,#8c564b,100
|
||||
Landsat 8--9,OLI/TIRS,11,11.5,1.01,#8c564b,100
|
||||
|
|
|
|
@ -3,67 +3,109 @@
|
|||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
# Licensed under the MIT License.
|
||||
|
||||
"""Plot Landsat band wavelengths and resolutions."""
|
||||
|
||||
import argparse
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
|
||||
# https://www.usgs.gov/faqs/what-are-band-designations-landsat-satellites
|
||||
df = pd.read_csv("band_data.csv")
|
||||
# Match NeurIPS template
|
||||
plt.rcParams.update(
|
||||
{
|
||||
"font.family": "Times New Roman",
|
||||
"font.size": 10,
|
||||
"axes.labelsize": 10,
|
||||
"text.usetex": True,
|
||||
}
|
||||
)
|
||||
|
||||
bar_height = 5
|
||||
# This dictionary maps a sensor and resolution to a y location on the plot
|
||||
bar_to_height_map = {
|
||||
("tm", 120): 50,
|
||||
("etm", 60): 34,
|
||||
("tirs", 100): 12,
|
||||
("mss", 60): 60,
|
||||
("tm", 30): 44,
|
||||
("etm", 30): 28,
|
||||
("etm", 15): 22,
|
||||
("oli", 30): 6,
|
||||
("oli", 15): 0,
|
||||
}
|
||||
parser = argparse.ArgumentParser(
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter, description=__doc__
|
||||
)
|
||||
parser.add_argument("skip", nargs="*", help="sensors to skip", metavar="SENSOR")
|
||||
parser.add_argument(
|
||||
"--fig-height", default=5, type=float, help="height of figure in inches"
|
||||
)
|
||||
parser.add_argument("--bar-start", default=1, type=float, help="height of first bar")
|
||||
parser.add_argument("--bar-height", default=3, type=float, help="height of each bar")
|
||||
parser.add_argument(
|
||||
"--bar-sep", default=3.5, type=float, help="separation between bars"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--bar-jump", default=2.6, type=float, help="additional height for narrow bars"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--sensor-sep", default=2, type=float, help="separation between sensors"
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
fig, (ax1, ax2) = plt.subplots(1, 2, gridspec_kw={"width_ratios": [4, 1]})
|
||||
fig.subplots_adjust(wspace=0.05)
|
||||
# https://www.usgs.gov/landsat-missions/landsat-satellite-missions
|
||||
df = pd.read_csv("band_data.csv", skip_blank_lines=True)
|
||||
df = df.iloc[::-1]
|
||||
|
||||
for sensor_name, group1 in df.groupby("Sensor name"):
|
||||
for resolution, group2 in group1.groupby("Resolution (m)"):
|
||||
# Plot one row of data
|
||||
y_position = bar_to_height_map[(sensor_name, resolution)]
|
||||
fig, ax = plt.subplots(figsize=(5.5, args.fig_height))
|
||||
ax1, ax2 = fig.subplots(nrows=1, ncols=2, gridspec_kw={"width_ratios": [3, 1]})
|
||||
|
||||
sensor_names: list[str] = []
|
||||
sensor_ylocs: list[float] = []
|
||||
res_names: list[int] = []
|
||||
res_ylocs: list[float] = []
|
||||
bar_min = args.bar_start
|
||||
|
||||
# For each satellite/sensor
|
||||
for (satellite, sensor), group1 in df.groupby(["Satellite", "Sensor"], sort=False):
|
||||
if sensor in args.skip:
|
||||
continue
|
||||
|
||||
sensor_names.append(f"{satellite}\n({sensor})")
|
||||
sensor_yloc = 0.0
|
||||
res_count = 0
|
||||
|
||||
# For each resolution
|
||||
for res, group2 in group1.groupby("Resolution (m)"):
|
||||
res_names.append(res)
|
||||
res_ylocs.append(bar_min)
|
||||
|
||||
if len(group2) > res_count:
|
||||
sensor_yloc = bar_min
|
||||
res_count = len(group2)
|
||||
|
||||
# For each band
|
||||
for i in range(group2.shape[0]):
|
||||
row = group2.iloc[i]
|
||||
wavelength_start = row["Wavelength start (μm)"]
|
||||
wavelength_width = row["Wavelength width"]
|
||||
wavelength_start = row["Wavelength Start (μm)"]
|
||||
wavelength_width = row["Wavelength Width"]
|
||||
color = row["Color"]
|
||||
band_number = row["Band number"]
|
||||
band = row["Band"]
|
||||
|
||||
# We've split the plot into two parts as the thermal bands are > 10μm
|
||||
# while the other bands are < 3μm
|
||||
y = bar_min + args.bar_height / 2
|
||||
if wavelength_width < 0.05:
|
||||
y += args.bar_jump
|
||||
|
||||
if wavelength_start < 10:
|
||||
ax1.broken_barh(
|
||||
[[wavelength_start, wavelength_width]],
|
||||
[y_position, bar_height],
|
||||
[bar_min, args.bar_height],
|
||||
edgecolor="k",
|
||||
facecolors=color,
|
||||
linewidth=0.5,
|
||||
alpha=0.8,
|
||||
)
|
||||
if wavelength_width < 0.05:
|
||||
y = y_position + 6.5
|
||||
else:
|
||||
y = y_position + 2.25
|
||||
ax1.text(
|
||||
wavelength_start + (wavelength_width / 2),
|
||||
y,
|
||||
str(band_number),
|
||||
band,
|
||||
horizontalalignment="center",
|
||||
verticalalignment="center",
|
||||
verticalalignment="center_baseline",
|
||||
)
|
||||
else:
|
||||
ax2.broken_barh(
|
||||
[[wavelength_start, wavelength_width]],
|
||||
[y_position, bar_height],
|
||||
[bar_min, args.bar_height],
|
||||
edgecolor="k",
|
||||
facecolors=color,
|
||||
linewidth=0.5,
|
||||
|
@ -71,37 +113,36 @@ for sensor_name, group1 in df.groupby("Sensor name"):
|
|||
)
|
||||
ax2.text(
|
||||
wavelength_start + (wavelength_width / 2),
|
||||
y_position + 2.25,
|
||||
str(band_number),
|
||||
y,
|
||||
band,
|
||||
horizontalalignment="center",
|
||||
verticalalignment="center",
|
||||
verticalalignment="center_baseline",
|
||||
)
|
||||
bar_min += args.bar_sep
|
||||
bar_min += args.sensor_sep
|
||||
|
||||
sensor_ylocs.append(sensor_yloc)
|
||||
|
||||
# Labels
|
||||
fig.supxlabel("Wavelength (μm)")
|
||||
ax.set_xlabel(r"Wavelength (\textmu m)")
|
||||
ax.set_xticks([0.5], labels=[0.5], alpha=0)
|
||||
ax.set_yticks([0], labels=[0], alpha=0)
|
||||
ax.spines[["bottom", "left", "top", "right"]].set_visible(False)
|
||||
|
||||
ax1.set_ylabel("Satellite (Sensor)")
|
||||
ax1.set_yticks([62.5, 46.5, 30.5, 8.5])
|
||||
ax1.set_yticklabels(
|
||||
[
|
||||
"Landsat 1–5\n(MSS)",
|
||||
"Landsat 4–5\n(TM)",
|
||||
"Landsat 7\n(ETM+)",
|
||||
"Landsat 8–9\n(OLI+TIRS)",
|
||||
]
|
||||
)
|
||||
ax1.set_ylim(-5, 70)
|
||||
ax1.spines.right.set_visible(False)
|
||||
ax1.spines.top.set_visible(False)
|
||||
ax1.set_yticks(np.array(sensor_ylocs) + args.bar_height / 2)
|
||||
ax1.set_yticklabels(sensor_names)
|
||||
ax1.set_ylim(0, max(res_ylocs) + args.bar_height + args.bar_start)
|
||||
ax1.spines[["left", "top", "right"]].set_visible(False)
|
||||
ax1.tick_params(axis="both", which="both", left=False)
|
||||
|
||||
ax2.set_xlim(10.1, 12.8)
|
||||
ax2.set_ylim(0, max(res_ylocs) + args.bar_height + args.bar_start)
|
||||
ax2.yaxis.set_label_position("right")
|
||||
ax2.yaxis.tick_right()
|
||||
ax2.set_ylabel("Resolution (m)")
|
||||
ax2.set_yticks([62.5, 52.5, 46.5, 36.5, 30.5, 24.5, 14.5, 8.5, 2.5])
|
||||
ax2.set_yticklabels([60, 120, 30, 60, 30, 15, 100, 30, 15])
|
||||
ax2.set_ylim(-5, 70)
|
||||
ax2.spines.left.set_visible(False)
|
||||
ax2.spines.top.set_visible(False)
|
||||
ax2.set_yticks(np.array(res_ylocs) + args.bar_height / 2)
|
||||
ax2.set_yticklabels(res_names)
|
||||
ax2.spines[["left", "top"]].set_visible(False)
|
||||
|
||||
# Draw axis break symbol
|
||||
d = 2
|
||||
|
@ -118,4 +159,5 @@ ax1.plot(1, 0, transform=ax1.transAxes, **kwargs)
|
|||
ax2.plot(0, 0, transform=ax2.transAxes, **kwargs)
|
||||
|
||||
plt.tight_layout()
|
||||
plt.subplots_adjust(wspace=0.1)
|
||||
plt.show()
|
||||
|
|
Загрузка…
Ссылка в новой задаче