quality_tracking
quality_tracking ¤
Quality and NOK (defective parts) tracking.
Essential module for daily quality analysis: - NOK parts by shift and part number - Scrap tracking - First pass yield - Quality rates
QualityEvents ¤
QualityEvents(
dataframe: DataFrame,
*,
time_column: str = "systime",
shift_definitions: (
dict[str, tuple[str, str]] | None
) = None
)
Bases: Base
Track NOK (defective) parts and quality metrics.
Each UUID represents one signal: - ok_counter_uuid: counter for good parts - nok_counter_uuid: counter for NOK parts - part_id_uuid: part number signal (optional) - defect_reason_uuid: defect reason code (optional)
Merge keys: [date, shift] for shift-level, [date] for daily, [part_number] for part-level.
Pipeline outputs include quality_pct (alias for first_pass_yield_pct)
so downstream modules (ShiftHandoverEvents, PeriodSummaryEvents, OEEEvents)
can join on a consistent column name.
Example
import pandas as pd, ts_shape kw = dict(n_points=20, freq="1min", noise=0, value_column="value_integer") df = pd.concat([ts_shape.make_timeseries(["ok"], drift=190, **kw), ... ts_shape.make_timeseries(["nok"], drift=19, **kw), ... ts_shape.make_id_signal("part", ["A", "B"], freq="1min")]) out = ts_shape.QualityEvents(df).quality_by_part("ok", "nok", "part") out[["part_number", "ok_parts", "nok_parts", "first_pass_yield_pct"]].round(1) part_number ok_parts nok_parts first_pass_yield_pct 0 A 90.0 9.0 90.9 1 B 100.0 10.0 90.9
Initialize quality tracker.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dataframe
|
DataFrame
|
Input DataFrame with timeseries data |
required |
time_column
|
str
|
Name of timestamp column (default: 'systime') |
'systime'
|
shift_definitions
|
dict[str, tuple[str, str]] | None
|
Dictionary mapping shift names to (start, end) times Default: 3-shift operation (06:00-14:00, 14:00-22:00, 22:00-06:00) |
None
|
nok_by_shift ¤
nok_by_shift(
ok_counter_uuid: str,
nok_counter_uuid: str,
*,
value_column: str = "value_integer",
handle_resets: bool = True,
production_day: bool = True
) -> pd.DataFrame
Calculate NOK (defective) parts per shift.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ok_counter_uuid
|
str
|
UUID for good parts counter |
required |
nok_counter_uuid
|
str
|
UUID of the NOK part counter |
required |
value_column
|
str
|
Column containing counter values |
'value_integer'
|
handle_resets
|
bool
|
When True (default), treat a decreasing counter as a reset
and count the parts accumulated after the reset, for both the
OK and NOK counters. The increments are computed once over
each whole counter signal; the increment between two readings
is spread over the time between them and split at the shift
boundaries in proportion to time (ISO 22400-2: a part belongs
to the period it was produced in), so the shifts add up to
the signal totals and the parts made in the last hour of a
night shift stay in that shift even though the reading that
reports them falls in the morning shift. Quantities can
therefore be fractional. A reset counts in the shift of the
reading that shows it. The result gains a |
True
|
production_day
|
bool
|
Attribute an overnight shift's post-midnight
readings to the shift's start date, so a night shift is one
|
True
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
DataFrame with quality metrics by shift: |
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
Example
import pandas as pd, ts_shape kw = dict(n_points=16, freq="30min", start="2025-01-01 06:00", noise=0, ... value_column="value_integer") df = pd.concat([ts_shape.make_timeseries(["ok"], drift=150, **kw), ... ts_shape.make_timeseries(["nok"], drift=15, **kw)]) out = ts_shape.QualityEvents(df).nok_by_shift("ok", "nok") out[["shift", "ok_parts", "nok_parts", "first_pass_yield_pct"]].round(1) shift ok_parts nok_parts first_pass_yield_pct 0 shift_1 150.0 15.0 90.9
quality_by_part ¤
quality_by_part(
ok_counter_uuid: str,
nok_counter_uuid: str,
part_id_uuid: str,
*,
value_column_counter: str = "value_integer",
value_column_part: str = "value_string",
handle_resets: bool = True
) -> pd.DataFrame
Calculate quality metrics by part number.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ok_counter_uuid
|
str
|
UUID for good parts counter |
required |
nok_counter_uuid
|
str
|
UUID of the NOK part counter |
required |
part_id_uuid
|
str
|
UUID for part number signal |
required |
value_column_counter
|
str
|
Column containing counter values |
'value_integer'
|
value_column_part
|
str
|
Column containing part numbers |
'value_string'
|
handle_resets
|
bool
|
When True (default), treat a decreasing counter as a reset
and count the parts accumulated after the reset. The part
number is attached to a single global counter, so the
reset-aware quantity is the sum of per-reading increments over
the full time-sorted series, grouped by part -- this also
corrects the over-count that |
True
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
DataFrame with quality by part: |
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
Example
import pandas as pd, ts_shape kw = dict(n_points=20, freq="1min", noise=0, value_column="value_integer") df = pd.concat([ts_shape.make_timeseries(["ok"], drift=190, **kw), ... ts_shape.make_timeseries(["nok"], drift=19, **kw), ... ts_shape.make_id_signal("part", ["A", "B"], freq="1min")]) out = ts_shape.QualityEvents(df).quality_by_part("ok", "nok", "part") out[["part_number", "ok_parts", "nok_parts", "nok_rate_pct"]] part_number ok_parts nok_parts nok_rate_pct 0 A 90.0 9.0 9.090909 1 B 100.0 10.0 9.090909
nok_by_reason ¤
nok_by_reason(
nok_counter_uuid: str,
defect_reason_uuid: str,
*,
value_column_counter: str = "value_integer",
value_column_reason: str = "value_string",
handle_resets: bool = True
) -> pd.DataFrame
Analyze NOK parts by defect reason.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
nok_counter_uuid
|
str
|
UUID of the NOK part counter |
required |
defect_reason_uuid
|
str
|
UUID for defect reason signal |
required |
value_column_counter
|
str
|
Column containing counter values |
'value_integer'
|
value_column_reason
|
str
|
Column containing reason codes |
'value_string'
|
handle_resets
|
bool
|
When True (default), treat a decreasing counter as a reset
and count the parts accumulated after the reset. The reason is
attached to a single global counter, so the reset-aware
quantity is the sum of per-reading increments over the full
time-sorted series, grouped by reason -- this also corrects
the over-count that |
True
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
DataFrame with NOK by reason: |
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
DataFrame
|
Canonical twin columns: |
DataFrame
|
holds the same values as the deprecated column right before it, which is |
DataFrame
|
removed in the next major release. |
Example
import pandas as pd, ts_shape kw = dict(n_points=20, freq="1min", noise=0, value_column="value_integer") df = pd.concat([ts_shape.make_timeseries(["nok"], drift=19, **kw), ... ts_shape.make_id_signal("reason", ["Scratch", "Dent"], freq="1min")]) out = ts_shape.QualityEvents(df).nok_by_reason("nok", "reason") out[["reason", "nok_parts", "share_of_total_pct", "resets"]] reason nok_parts share_of_total_pct resets 0 Dent 10.0 52.631579 0 1 Scratch 9.0 47.368421 0
daily_quality_summary ¤
daily_quality_summary(
ok_counter_uuid: str,
nok_counter_uuid: str,
*,
value_column: str = "value_integer",
handle_resets: bool = True,
production_day: bool = True
) -> pd.DataFrame
Daily quality summary.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ok_counter_uuid
|
str
|
UUID for good parts counter |
required |
nok_counter_uuid
|
str
|
UUID of the NOK part counter |
required |
value_column
|
str
|
Column containing counter values |
'value_integer'
|
handle_resets
|
bool
|
When True (default), treat a decreasing counter as a reset
and count the parts accumulated after the reset (see
:meth: |
True
|
production_day
|
bool
|
Forwarded to :meth: |
True
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
DataFrame with daily quality: |
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
Example
import pandas as pd, ts_shape kw = dict(n_points=16, freq="30min", start="2025-01-01 06:00", noise=0, ... value_column="value_integer") df = pd.concat([ts_shape.make_timeseries(["ok"], drift=150, **kw), ... ts_shape.make_timeseries(["nok"], drift=15, **kw)]) out = ts_shape.QualityEvents(df).daily_quality_summary("ok", "nok") out[["date", "ok_parts", "nok_parts", "nok_rate_pct"]].round(1) date ok_parts nok_parts nok_rate_pct 0 2025-01-01 150.0 15.0 9.1