factoriax.analysis.actions#
Find temporal patterns in what an agent did, and draw them.
Every function takes a
Trajectory. Each plot returns
its (figure, axes) without writing or closing anything, so the
caller can change the result before saving it.
Five views, each with a plot and most with a finder that returns the numbers behind it:
A raster draws one colored cell for each episode and timestep. Phase changes and loops show up as bands.
A transition matrix counts how often each action follows each other action.
An n-gram count finds the short sequences an agent repeats.
An entropy curve measures how much the episodes of a batch agree at each timestep.
A run length measures how long an action was repeated without a break.
DEFAULT_ACTION_LABELS and DEFAULT_ACTION_COLORS are
both built from the Action enum, so neither can fall behind it and
both cover every action. The colors carry no meaning, though. Pass
colors where the scheme has to say something, such as cool tones
for movement.
Module Attributes
The name of each action, in |
|
Fallback line and cell colors, in |
- factoriax.analysis.actions.DEFAULT_ACTION_COLORS: list[str] = ['#c61010', '#4d72cb', '#b9f368', '#a63097', '#2beecd', '#dab181', '#3d10c6', '#53cb4d', '#f36896', '#307aa6', '#deee2b', '#c781da', '#10c66b', '#cb674d', '#6874f3', '#5da630', '#ee2bad', '#81d7da', '#c69810', '#874dcb', '#68f37f', '#a6303f', '#2b7dee', '#c0da81', '#c610c6', '#4dcba6', '#f3a168', '#3f30a6', '#4cee2b', '#da81aa', '#1099c6', '#cbc64d', '#c468f3', '#30a65c', '#ee3a2b', '#8194da', '#6cc610', '#cb4db2', '#68f3e7', '#a67930', '#6b2bee', '#81da84', '#c6103f', '#4d92cb', '#dcf368', '#9730a6', '#2bee9b', '#da9a81', '#1011c6', '#73cb4d', '#f368ba', '#3098a6', '#eecc2b', '#b181da', '#10c63c', '#cb4d53', '#6897f3', '#7ba630', '#ee2bdf', '#81dac7', '#c66a10', '#664dcb', '#75f368', '#a6305d', '#2baeee', '#d7da81', '#9710c6', '#4dcb86', '#f37e68', '#3040a6', '#7eee2b', '#da81c1', '#10c6c4', '#cba54d', '#a168f3', '#30a63e', '#ee2b4d', '#81abda', '#9ac610', '#c54dcb', '#68f3c3', '#a65b30', '#392bee', '#94da81', '#c6106d', '#4db2cb', '#f3e668']#
Fallback line and cell colors, in
Actionvalue order, one for each action. Generated, so the list cannot fall behind the enum the way a hand-written one does.The colors carry no meaning: two neighboring actions are not related, and an action has no fixed color. Pass
colorsto any plot that needs a chosen scheme, such as cool tones for movement.
- factoriax.analysis.actions.DEFAULT_ACTION_LABELS: list[str] = ['NOOP', 'UP', 'DOWN', 'LEFT', 'RIGHT', 'FACE_UP', 'FACE_DOWN', 'FACE_LEFT', 'FACE_RIGHT', 'MINE', 'PICKUP', 'WITHDRAW', 'REPAIR', 'ROTATE_LEFT', 'ROTATE_RIGHT', 'ROTATE_UP', 'ROTATE_DOWN', 'PLACE_MINER', 'PLACE_PALLET', 'PLACE_CONVEYOR_BELT', 'PLACE_ASSEMBLER', 'PLACE_ARM', 'PLACE_ROCKET', 'PLACE_FURNACE', 'PLACE_SCIENCE_LAB', 'PLACE_SPLITTER', 'PLACE_CROSSING', 'CRAFT_IRON_PLATE', 'CRAFT_COPPER_PLATE', 'CRAFT_TIN_PLATE', 'CRAFT_WAFER', 'CRAFT_FRAME', 'CRAFT_CIRCUIT', 'CRAFT_WIRE', 'CRAFT_MOTOR', 'CRAFT_SENSOR', 'CRAFT_TIER1_SCIENCE_PACK', 'CRAFT_TIER2_SCIENCE_PACK', 'CRAFT_REFRACTORY', 'CRAFT_HULL', 'CRAFT_ENGINE_UNIT', 'CRAFT_AVIONICS', 'CRAFT_ROCKET_CORE', 'CRAFT_TIER3_SCIENCE_PACK', 'CRAFT_MINER', 'CRAFT_PALLET', 'CRAFT_CONVEYOR_BELT', 'CRAFT_ASSEMBLER', 'CRAFT_ARM', 'CRAFT_ROCKET', 'CRAFT_FURNACE', 'CRAFT_SCIENCE_LAB', 'CRAFT_SPLITTER', 'CRAFT_CROSSING', 'DEPOSIT_COAL', 'DEPOSIT_IRON_ORE', 'DEPOSIT_COPPER_ORE', 'DEPOSIT_TIN_ORE', 'DEPOSIT_SILICON', 'DEPOSIT_LIMESTONE', 'DEPOSIT_IRON_PLATE', 'DEPOSIT_COPPER_PLATE', 'DEPOSIT_TIN_PLATE', 'DEPOSIT_WAFER', 'DEPOSIT_FRAME', 'DEPOSIT_CIRCUIT', 'DEPOSIT_WIRE', 'DEPOSIT_MOTOR', 'DEPOSIT_SENSOR', 'DEPOSIT_TIER1_SCIENCE_PACK', 'DEPOSIT_TIER2_SCIENCE_PACK', 'DEPOSIT_REFRACTORY', 'DEPOSIT_HULL', 'DEPOSIT_ENGINE_UNIT', 'DEPOSIT_AVIONICS', 'DEPOSIT_ROCKET_CORE', 'DEPOSIT_TIER3_SCIENCE_PACK', 'DEPOSIT_MINER', 'DEPOSIT_PALLET', 'DEPOSIT_CONVEYOR_BELT', 'DEPOSIT_ASSEMBLER', 'DEPOSIT_ARM', 'DEPOSIT_ROCKET', 'DEPOSIT_FURNACE', 'DEPOSIT_SCIENCE_LAB', 'DEPOSIT_SPLITTER', 'DEPOSIT_CROSSING']#
The name of each action, in
Actionvalue order. Built from the enum, so it cannot drift from it and always covers every action.
- factoriax.analysis.actions.action_entropy(traj: Trajectory, player: int | None = None, num_actions: int = 87, window: int = 1) ndarray#
Measure how much the chosen action varies across episodes.
At each timestep the function builds the distribution of actions over the episodes of the batch, then takes its Shannon entropy in bits. A value of 0 means every episode took the same action at that step. The largest possible value is
log2(num_actions).This measures agreement between episodes at one timestep. It does not measure how varied one episode is over time.
- Parameters:
traj – The recording to read. Actions of shape
(B, T),(B, T, P), and(B, T, 1)all work.player – Which player to read, or
Nonefor player 0.num_actions – How many action ids the distribution covers.
window – The width of a rolling mean over time. A
windowof 1 applies no smoothing.
- Returns:
Shape
(T,), in bits.- Return type:
Notes
The smoothing uses
mode="same", so the first and lastwindow // 2values average over fewer real timesteps and pull toward zero. Read the two ends with that in mind.
- factoriax.analysis.actions.action_ngrams(traj: Trajectory, n: int = 2, player: int | None = None, top_k: int = 20, action_labels: list[str] | None = None) list[tuple[Any, int]]#
Count the most common runs of
nactions in a row.- Parameters:
traj – The recording to read. Actions of shape
(B, T),(B, T, P), and(B, T, 1)all work.player – Which player to read, or
Nonefor player 0.n – How many actions make one gram. An
nabove the episode length gives an empty result.top_k – How many of the most common grams to return.
action_labels – The name of each action, or
Noneto key the result by action id instead of by name.
- Returns:
(gram, count)pairs, most common first. A gram is a tuple ofnaction ids, or ofnnames whenaction_labelsis given. Grams are counted inside an episode only, so none spans two episodes.- Return type:
- factoriax.analysis.actions.action_raster(traj: Trajectory, player: int | None = None, num_actions: int = 87, action_labels: list[str] | None = None, colors: Sequence[str] | None = None, episode_labels: list[str] | None = None, ax: Axes | None = None, figsize: tuple[float, float] = (14, 6), title: str | None = None) tuple[Figure, Axes]#
Draw the action of every episode and timestep as a colored cell.
One row is an episode, one column a timestep, and the color is the action. This is the first view to reach for when looking for temporal structure: phase changes, loops, and repeated sub-behaviors all show up as bands.
- Parameters:
traj – The recording to read. Actions of shape
(B, T),(B, T, P), and(B, T, 1)all work.player – Which player to read, or
Nonefor player 0.num_actions – How many actions the color scale covers.
action_labels – The name of each action, or
NoneforDEFAULT_ACTION_LABELS, which is built from theActionenum and cannot drift from it.colors – One color for each action, or
Nonefor the defaults.episode_labels – The name of each row, or
Noneto number them. The list must hold one entry for each episode.ax – The axes to draw on, or
Nonefor a new figure.figsize – The size of that new figure in inches. It is ignored when
axis given.title – The figure title, or
Nonefor a default.
- Returns:
(figure, axes). The figure is not written and not closed, so the caller owns it.- Return type:
Notes
The default colors are generated and carry no meaning. Pass
colorswhere the scheme has to say something, such as cool tones for movement.
- factoriax.analysis.actions.plot_action_distribution(traj: Trajectory, player: int | None = None, num_actions: int = 87, action_labels: list[str] | None = None, colors: Sequence[str] | None = None, window: int = 10, ax: Axes | None = None, figsize: tuple[float, float] = (14, 5), title: str | None = None) tuple[Figure, Axes]#
Draw how the mix of actions changes over an episode.
The chart is a stacked area, so each band is the share of one action at that timestep and the bands sum to 1.
- Parameters:
traj – The recording to read. Actions of shape
(B, T),(B, T, P), and(B, T, 1)all work.player – Which player to read, or
Nonefor player 0.num_actions – How many action ids to draw as bands.
action_labels – The name of each action, or
Nonefor the defaults.colors – One color for each action, or
Nonefor the defaults.window – The width of a rolling mean over time, which smooths the bands.
ax – The axes to draw on, or
Nonefor a new figure.figsize – The size of that new figure in inches. It is ignored when
axis given.title – The figure title, or
Nonefor a default.
- Returns:
(figure, axes). The figure is not written and not closed, so the caller owns it.- Return type:
Notes
The default colors are generated and carry no meaning. Pass
colorswhere the scheme has to say something, such as cool tones for movement.
- factoriax.analysis.actions.plot_entropy(traj: Trajectory, player: int | None = None, num_actions: int = 87, window: int = 5, ax: Axes | None = None, figsize: tuple[float, float] = (12, 4), title: str | None = None) tuple[Figure, Axes]#
Draw the action entropy over the course of an episode.
- Parameters:
traj – The recording to read. Actions of shape
(B, T),(B, T, P), and(B, T, 1)all work.player – Which player to read, or
Nonefor player 0.num_actions – How many action ids the distribution covers.
window – The width of the rolling mean, as in
action_entropy().ax – The axes to draw on, or
Nonefor a new figure.figsize – The size of that new figure in inches. It is ignored when
axis given.title – The figure title, or
Nonefor a default.
- Returns:
(figure, axes). The figure is not written and not closed, so the caller owns it.- Return type:
- factoriax.analysis.actions.plot_ngram_sweep(traj: Trajectory, n_range: tuple[int, int] = (2, 10), player: int | None = None, top_k: int = 3, action_labels: list[str] | None = None, colors: Sequence[str] | None = None, figsize: tuple[float, float] | None = None, title: str | None = None) tuple[Figure, ndarray]#
Draw the top grams for each length in a range, one row each.
- Parameters:
traj – The recording to read. Actions of shape
(B, T),(B, T, P), and(B, T, 1)all work.player – Which player to read, or
Nonefor player 0.n_range –
(lowest, highest)gram length, both included. One row of panels is drawn for each length.top_k – How many grams to show for each length.
action_labels – The name of each action, or
Nonefor the defaults.colors – One color for each action, or
Nonefor the defaults. Each bar takes the mean color of its gram.figsize – The size of the figure in inches, or
Noneto size it from the row count.title – The figure title, or
Nonefor a default.
- Returns:
(figure, axes), whereaxesholds one entry for each gram length. The figure is not written and not closed.- Return type:
Notes
The default colors are generated and carry no meaning. Pass
colorswhere the scheme has to say something, such as cool tones for movement.
- factoriax.analysis.actions.plot_ngrams(traj: Trajectory, n: int = 2, player: int | None = None, top_k: int = 15, action_labels: list[str] | None = None, ax: Axes | None = None, figsize: tuple[float, float] = (10, 5), title: str | None = None) tuple[Figure, Axes]#
Draw the most common grams of one length as a bar chart.
- Parameters:
traj – The recording to read. Actions of shape
(B, T),(B, T, P), and(B, T, 1)all work.player – Which player to read, or
Nonefor player 0.n – How many actions make one gram.
top_k – How many of the most common grams to draw.
action_labels – The name of each action, or
Nonefor the defaults.ax – The axes to draw on, or
Nonefor a new figure.figsize – The size of that new figure in inches. It is ignored when
axis given.title – The figure title, or
Nonefor a default.
- Returns:
(figure, axes). The figure is not written and not closed, so the caller owns it.- Return type:
- factoriax.analysis.actions.plot_phase_transitions(traj: Trajectory, phases: list[tuple[int, int]], player: int | None = None, num_actions: int = 87, action_labels: list[str] | None = None, figsize_per_phase: tuple[float, float] = (5, 4.5), cmap: str = 'Blues', phase_labels: list[str] | None = None) tuple[Figure, ndarray]#
Draw one transition matrix for each phase, side by side.
Use this to see how the behavior of a policy changes over an episode. An early phase and a late phase each get their own matrix, on a shared color scale.
- Parameters:
traj – The recording to read. Actions of shape
(B, T),(B, T, P), and(B, T, 1)all work.player – Which player to read, or
Nonefor player 0.phases – One
(start, end)timestep window for each panel. The windows can overlap and need not cover the whole episode.num_actions – The side length of each matrix.
action_labels – The name of each action, or
Nonefor the defaults.figsize_per_phase – The size of one panel in inches. The figure width grows with the number of phases.
cmap – Any matplotlib colormap name.
phase_labels – The title of each panel, or
Noneto build one from the window. The list must be as long asphases.
- Returns:
(figure, axes), whereaxesholds one entry for each phase. The figure is not written and not closed.- Return type:
- factoriax.analysis.actions.plot_run_lengths(traj: Trajectory, player: int | None = None, action_labels: list[str] | None = None, num_actions: int = 87, colors: Sequence[str] | None = None, ax: Axes | None = None, figsize: tuple[float, float] = (10, 5), title: str | None = None) tuple[Figure, Axes]#
Draw one box for each action, over its run lengths.
An action that never occurred gets no box, so the chart shows only the actions the policy used.
- Parameters:
traj – The recording to read. Actions of shape
(B, T),(B, T, P), and(B, T, 1)all work.player – Which player to read, or
Nonefor player 0.action_labels – The name of each action, or
Nonefor the defaults.num_actions – How many action ids to consider.
colors – One color for each action, or
Nonefor the defaults.ax – The axes to draw on, or
Nonefor a new figure.figsize – The size of that new figure in inches. It is ignored when
axis given.title – The figure title, or
Nonefor a default.
- Returns:
(figure, axes). The figure is not written and not closed, so the caller owns it.- Return type:
Notes
The default colors are generated and carry no meaning. Pass
colorswhere the scheme has to say something, such as cool tones for movement.
- factoriax.analysis.actions.plot_transition_matrix(traj: Trajectory, player: int | None = None, num_actions: int = 87, action_labels: list[str] | None = None, time_range: tuple[int, int] | None = None, normalize: bool = True, ax: Axes | None = None, figsize: tuple[float, float] = (8, 7), cmap: str = 'Blues', title: str | None = None) tuple[Figure, Axes]#
Draw the transition matrix as a heatmap.
- Parameters:
traj – The recording to read. Actions of shape
(B, T),(B, T, P), and(B, T, 1)all work.player – Which player to read, or
Nonefor player 0.num_actions – The side length of the matrix.
action_labels – The name of each action, or
Nonefor the defaults. The names label both axes.time_range –
(start, end)to count only that window, orNone.normalize – True for probabilities, False for raw counts. This also sets the colorbar label.
ax – The axes to draw on, or
Nonefor a new figure.figsize – The size of that new figure in inches. It is ignored when
axis given.title – The figure title, or
Nonefor a default.cmap – Any matplotlib colormap name.
- Returns:
(figure, axes). The figure is not written and not closed, so the caller owns it.- Return type:
- factoriax.analysis.actions.run_lengths(traj: Trajectory, player: int | None = None) dict[int, list[int]]#
Measure how long each action was repeated without a break.
- Parameters:
traj – The recording to read. Actions of shape
(B, T),(B, T, P), and(B, T, 1)all work.player – Which player to read, or
Nonefor player 0.
- Returns:
{action_id: [length, ...]}. A length counts the steps in one unbroken run of that action. Runs are collected inside an episode only. The run at the end of an episode is closed at the last step, and not joined to the next episode. An action that never occurred is absent from the dict.- Return type:
- factoriax.analysis.actions.transition_matrix(traj: Trajectory, player: int | None = None, num_actions: int = 87, normalize: bool = True, time_range: tuple[int, int] | None = None) ndarray#
Count how often each action follows each other action.
- Parameters:
traj – The recording to read. Actions of shape
(B, T),(B, T, P), and(B, T, 1)all work.player – Which player to read, or
Nonefor player 0.num_actions – The side length of the matrix. An action id at or above this value raises
IndexError.normalize – True to divide each row by its total, giving the probability of the next action. False to return raw counts.
time_range –
(start, end)to count only that window of timesteps, orNonefor the whole episode.
- Returns:
Shape
(num_actions, num_actions), float64. Entry(i, j)counts the steps where actioniwas followed by actionj. Pairs are counted inside an episode only, so the last step of one episode is not paired with the first of the next.- Return type:
Notes
With
normalize=True, a row for an action that never occurred is divided by 1 rather than by 0. Such a row is therefore all zeros and notNaN, so it plots as an empty row and does not sum to 1.