Automotive & data work

Compare multiple test conditions on the same time axis

Validate three synthetic demonstration CSV files, then overlay curves that share the same time samples and acceleration units on one chart.

Show contents

This translation was generated by AI. Check the code, units, and numbers against the original. Native-speaker review has not yet been completed for each language. 한국어

Who this is forPython beginners in the automotive field who want to overlay test results from multiple conditions

What you need
  • Have Python 3.12 and a terminal ready. Check the version with python --version.
  • Extract the entire downloaded ZIP and open a terminal in the folder containing example.py.
  • Start with the included practice data, then compare the results with the original files.
  • case_a.csv, case_b.csv, and case_c.csv in the inputs folder are all synthetic demonstration data.
  • All inputs use time in s, acceleration in m/s^2, and the same time samples.

01Align the conditions needed for comparison

To overlay several curves in one chart, time and the vertical-axis units must mean the same thing. This example plots the synthetic demonstration data Case A, Case B, and Case C on common axes of time in s and acceleration in m/s^2. Condition names are read from the condition column in each file.

02Prepare the folder and input format

The script reads the .csv files in the inputs folder in name order. There must be at least two files, and each file must contain only one condition. Every row must have six columns: dataset_note, condition, time, time_unit, acceleration, and acceleration_unit.

FieldIncluded example
dataset_noteSynthetic demonstration data
conditionCase A (ASCII letters and numbers)
time / time_unit0.0 / s
acceleration / acceleration_unit0.8 / m/s^2

This example compares only when the time arrays of the files are exactly the same. It stops if the number of samples, the start time, or any time value differs. The chart axis shows the shared unit as m/s².

03Prepare the files and run the example

  1. Extract the ZIP and check that the input file listed in README.txt is in the same folder as example.py. Do not run the example from inside the ZIP archive.
  2. Run the commands below one line at a time in the folder containing example.py. On Windows, if python is unavailable but py is available, replace python in each command with py -3.12.
  3. After the completion message appears, open the new outputs folder. If outputs already exists, first rename it to keep the previous results, then run the example again.
bash
python --version
python -m pip install -r requirements.txt
python example.py

Installation requires an internet connection. BASE in the code sets the input and output paths relative to example.py, not the current terminal folder.

04Full code and pre-comparison checks

After checking the time order and units in each file, it checks for duplicate condition names. It compares the remaining arrays against the time array of the first file, and adds lines to one Axes only when all of them match. Sorting, time shifting, interpolation, and unit conversion are not done automatically.

example.py
"""Overlay explanatory synthetic test conditions on the same axes.

All files must have the same explicit units and matching time samples.
No interpolation, clock shifting, filtering, or safety assessment is performed.
"""
import csv
import math
from pathlib import Path

import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt

BASE = Path(__file__).resolve().parent
HEADERS = ["dataset_note", "condition", "time", "time_unit", "acceleration", "acceleration_unit"]
NOTE = "설명용 합성 데이터"


def read_condition(path):
    times, values = [], []
    label = None
    with path.open(encoding="utf-8-sig", newline="") as file:
        reader = csv.DictReader(file)
        if reader.fieldnames != HEADERS:
            raise ValueError(f"{path.name}: expected headers {HEADERS}")
        for line, row in enumerate(reader, start=2):
            if None in row or any(value is None or not value.strip() for value in row.values()):
                raise ValueError(f"{path.name}:{line}: missing or extra field.")
            if row["dataset_note"] != NOTE:
                raise ValueError(f"{path.name}:{line}: synthetic-data label is required.")
            if row["time_unit"] != "s" or row["acceleration_unit"] != "m/s^2":
                raise ValueError(f"{path.name}:{line}: expected units s and m/s^2; no automatic conversion.")
            if not row["condition"].isascii():
                raise ValueError(f"{path.name}:{line}: use an ASCII condition label for portable plotting.")
            label = row["condition"] if label is None else label
            if row["condition"] != label:
                raise ValueError(f"{path.name}:{line}: condition label changes within one file.")
            time, value = float(row["time"]), float(row["acceleration"])
            if not math.isfinite(time) or not math.isfinite(value) or time < 0:
                raise ValueError(f"{path.name}:{line}: expected finite values and nonnegative time.")
            if times and time <= times[-1]:
                raise ValueError(f"{path.name}:{line}: duplicate or decreasing time.")
            times.append(time)
            values.append(value)
    if len(times) < 2:
        raise ValueError(f"{path.name}: at least two samples are required.")
    return label, times, values


def main():
    destination = BASE / "outputs"
    if destination.exists():
        raise ValueError("outputs already exists; rename it before running again.")
    paths = sorted((BASE / "inputs").glob("*.csv"))
    if len(paths) < 2:
        raise ValueError("At least two CSV files are required in inputs.")
    conditions = [read_condition(path) for path in paths]
    if len({label for label, _, _ in conditions}) != len(conditions):
        raise ValueError("Condition labels must be unique across files.")
    reference_times = conditions[0][1]
    if any(times != reference_times for _, times, _ in conditions[1:]):
        raise ValueError("Time samples do not match; check alignment before comparison.")

    figure, axis = plt.subplots(figsize=(8, 4.6), layout="constrained")
    for label, times, values in conditions:
        axis.plot(times, values, marker="o", linewidth=2, label=label)
    axis.set(title="Test conditions | Explanatory synthetic data", xlabel="Elapsed time (s)", ylabel="Acceleration (m/s²)")
    axis.spines[["top", "right"]].set_visible(False)
    axis.grid(alpha=0.2)
    axis.legend(frameon=False)
    destination.mkdir(exist_ok=False)
    with (destination / "comparison_summary.csv").open("x", encoding="utf-8-sig", newline="") as file:
        writer = csv.writer(file)
        writer.writerow(["dataset_note", "condition", "sample_count", "min_acceleration", "max_acceleration", "unit"])
        for label, _, values in conditions:
            writer.writerow([NOTE, label, len(values), min(values), max(values), "m/s^2"])
    figure.savefig(destination / "synthetic_comparison.png", dpi=160)
    plt.close(figure)
    print(f"Explanatory synthetic data: {len(conditions)} conditions, {len(reference_times)} matching time samples each.")
    print("Created outputs/comparison_summary.csv and outputs/synthetic_comparison.png.")


if __name__ == "__main__":
    try:
        main()
    except (OSError, ValueError, csv.Error) as error:
        raise SystemExit(f"Stopped: {error}") from error

05Read the chart and summary CSV

The three conditions are overlaid in outputs/synthetic_comparison.png. outputs/comparison_summary.csv stores the number of samples and the minimum and maximum acceleration for each condition. These numbers are a simple summary of synthetic demonstration data.

ConditionSamplesMinimumMaximum
Case A60.0 m/s²1.4 m/s²
Case B60.0 m/s²1.1 m/s²
Case C60.0 m/s²1.7 m/s²
Acceleration comparison of synthetic demonstration data Cases A, B, and C. Three curves using the same 0–1 s time and m/s² axes.
Acceleration comparison of synthetic demonstration data Cases A, B, and C. Three curves using the same 0–1 s time and m/s² axes.

At the 0.4 s sample, the values of the three curves are 1.4, 1.1, and 1.7 m/s². The lines in the chart connect the samples; they do not create new measured values between them.

06Steps to confirm the axes match

  1. Check that Case A, Case B, and Case C in the chart legend match the condition values in the input files.
  2. Check Elapsed time (s) on the x-axis and Acceleration (m/s²) on the y-axis.
  3. Compare the values of the three CSV files at 0.4 s with the chart and the summary table.
  4. In a new practice copy, change one time value in case_b.csv to 0.41. Check that it stops with the message Time samples do not match.
  5. In another new copy, change acceleration_unit to g and check that it stops without converting automatically.

07Find why the comparison stops

MessageWhat to check
expected units s and m/s^2Check the actual units and notation in the exported file.
duplicate or decreasing timeCheck the time order in that file and row.
Time samples do not matchCheck the start time, sampling interval, and missing samples. Do not simply overwrite the times without knowing the cause.
Condition labels must be uniqueUse a different condition name for each file.
condition label changesCheck that one file does not mix several conditions.
At least two CSV filesCheck that the input files are in the inputs folder.

08What the chart alone cannot tell you

  • Even with the same numeric time axis, the trigger or reference time can differ. Check the basis for alignment in real tests separately.
  • Only exactly identical time arrays are allowed. Approximate matching, resampling, interpolation, and time-delay correction are out of scope.
  • The code does not judge whether different sensor locations, coordinate systems, sampling filters, or test conditions are comparable.
  • The sample maximum does not guarantee the true maximum between samples. The chart does not provide pass/fail, performance ranking, or safety judgments.

Execution and verification record

Windows 11 (10.0.26200), CPython 3.12.14 (64-bit). openpyxl 3.1.5, Matplotlib 3.10.8. The libraries used by each example are pinned in requirements.txt.

  • Checked 3 conditions × 6 samples of synthetic demonstration data, and the minimum and maximum values
  • Checked errors for unit mismatch, duplicate or reversed times, mismatched time arrays, and duplicate condition names
  • Checked that the original hashes are unchanged, existing outputs are refused, and the PNG is created
Verification limits
  • Did not assess the comparability of real test conditions, time synchronization, measurement uncertainty, or safety.

Site-wide writing and verification principles

Example files to run yourself

Includes code, input data, and instructions. Extract the ZIP and read README.txt first.

Download example ZIP

Example code, filenames, and input keys remain unchanged. Refer to the commands and checking steps in the translated article as well.

References

The explanations and examples were written for this site. See the official sources below for the related behavior and concepts.