user30530: I would like to test how Stockfish or other Engines change their moves and evaluations as the number of nodes increases. Is there a way to run Stockfish (or another engine) and force it to output its move preference every 1000 nodes?

user30545: One approach is by sending the command go nodes 1000, go nodes 2000 ... to the engine and record the moves and score.
Here is a sample code to do like that using python chess lib along with other  data and plotting libs.
Code
"""
This script will only work for those uci engines that supports
"go nodes <value>" command.

Requirements:
    pip install chess
    pip install pandas
    pip install matplotlib
"""

import chess
import chess.engine
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.ticker as plticker


def engine_analysis(efn, fen, nodelimit):
    engine = chess.engine.SimpleEngine.popen_uci(efn)
    try:
        engine.configure({"Hash": 128})
        engine.configure({"Threads": 1})
    except Exception as exception:
        pass
    
    board = chess.Board(fen)
    limit = chess.engine.Limit(nodes=nodelimit)

    value, sanmove, nodes, timesec = None, None, 0, 0

    with engine.analysis(board, limit=limit) as analysis:
        for info in analysis:
            
            pv = info.get('pv')
            score = info.get('score')                
            nodes = info.get('nodes')
            timesec = info.get('time')
            
            if pv is not None:
                move = pv[0]
                sanmove = board.san(move)
                
            if score is not None:
                value = score.relative.score(mate_score=32000)

    engine.quit()
    
    return sanmove, value, nodes, timesec
    
    
def run_engine():
    # fen = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1'  # startpos
    fen = 'rnbqkb1r/1p2pppp/p2p1n2/8/3NP3/2N5/PPP2PPP/R1BQKB1R w KQkq - 0 6'  # sicilian
    
    nodes_per_interval = 1000
    num_interval = 30
    
    e1 = {'name': 'Stockfish 14', 'file': 'E:/Chess/Engines/stockfish/sf14/sf14.exe'}
    e2 = {'name': 'Lc0 0.28', 'file': 'E:/Chess/Engines/Lc0/lc0-v0.28.0-windows-gpu-nvidia-cudnn-nodll/lc0.exe'}
    engines = [e1, e2]
    
    dfs = {}
    for eng in engines:
        d = []
        for i in range(num_interval):
            nodelimit = (i+1) * nodes_per_interval
            move, score, actualnodes, timesec = engine_analysis(eng['file'], fen, nodelimit)
            d.append([nodelimit, actualnodes, move, score, timesec])
            
        df = pd.DataFrame(d)
        df.columns = ['nodes', 'actualnodes', 'move', 'scorecp', 'timesec']
        dfs.update({eng['name']: df})
        
    print(f'fen: {fen}')        
    for k, v in dfs.items():
        print(f'{k}:')
        print(f'{v.to_string(index=False)}\n')

    # Plot    
    x = dfs[e1['name']]['nodes']
    y1 = dfs[e1['name']]['scorecp']
    y2 = dfs[e2['name']]['scorecp']
    
    _, (ax1, ax2) = plt.subplots(2, 1, sharex=True, figsize=(12, 6))
    
    ax1.plot(x, y1)
    ax1.set_title(f"{e1['name']} score at different node levels")
    ax1.set_ylabel('score cp')
    
    ax2.plot(x, y2)
    ax2.set_title(f"{e2['name']} score at different node levels")
    ax2.set_xlabel('nodes')
    ax2.set_ylabel('score cp')
    plt.setp(ax2.get_xticklabels(), ha="right", rotation=45)
       
    loc = plticker.MultipleLocator(base=nodes_per_interval)  # add ticks in every point
    ax2.xaxis.set_major_locator(loc)
    
    plt.savefig('engine_nodes.png')    
    plt.show()
    
    
# start
run_engine()

Output
fen: rnbqkb1r/1p2pppp/p2p1n2/8/3NP3/2N5/PPP2PPP/R1BQKB1R w KQkq - 0 6
Stockfish 14:
 nodes  actualnodes move  scorecp  timesec
  1000         1002  Be3       64    0.002
  2000         2001  Bg5      -24    0.003
  3000         3005  Nb3       46    0.003
  4000         4010  Bg5       32    0.004
  5000         5004  Bg5        4    0.004
  6000         6003  Nb3       13    0.005
  7000         7040  Bg5       19    0.006
  8000         8013  Be3       41    0.009
  9000         9003  Be2       40    0.007
 10000        10019  Be2       33    0.008
 11000        11003   f3       50    0.009
 12000        12014  Qf3       40    0.010
 13000        13004   a4       27    0.010
 14000        14014   a4       47    0.011
 15000        15006  Be2       32    0.011
 16000        16040  Nb3        6    0.012
 17000        17022  Nb3       37    0.013
 18000        18007  Nb3       52    0.014
 19000        19019   a4       17    0.014
 20000        20040   h3       21    0.020
 21000        21032  Be3       38    0.016
 22000        22011   f3       18    0.016
 23000        23039   f3       38    0.023
 24000        24036   f3       50    0.028
 25000        25019  Bg5       69    0.021
 26000        26021   h3       30    0.019
 27000        27071  Be3       27    0.019
 28000        28072  Nb3       44    0.021
 29000        29032  Be3       64    0.020
 30000        30039  Be2       34    0.022

Lc0 0.28:
 nodes  actualnodes move  scorecp  timesec
  1000         1022   f3       20    0.156
  2000         2012   f3       19    0.180
  3000         2997   f3       20    0.214
  4000         3411   f3       19    0.224
  5000         4211   f3       19    0.249
  6000         5428   f3       19    0.279
  7000         6018   f3       19    0.319
  8000         6449   f3       19    0.339
  9000         6993   f3       20    0.349
 10000         7552   f3       20    0.369
 11000         8039   f3       20    0.392
 12000         8173   f3       20    0.379
 13000         8942   f3       20    0.404
 14000         9583   f3       20    0.417
 15000        10075   f3       20    0.475
 16000        10653   f3       20    0.466
 17000        11045   f3       20    0.474
 18000        11732   f3       20    0.506
 19000        12561   f3       20    0.535
 20000        12763   f3       20    0.543
 21000        13268   f3       20    0.570
 22000        13829   f3       20    0.584
 23000        14323   f3       20    0.602
 24000        14883   f3       20    0.641
 25000        15823   f3       19    0.663
 26000        16810   f3       19    0.693
 27000        25923   f3       18    0.938
 28000        27064   f3       18    1.001
 29000        26266   f3       18    0.976
 30000        29043  Be3       18    1.052



30530: <p>I would like to test how Stockfish or other Engines change their moves and evaluations as the number of nodes increases. Is there a way to run Stockfish (or another engine) and force it to output its move preference every 1000 nodes?</p>
 30545: <p>One approach is by sending the command <code>go nodes 1000</code>, <code>go nodes 2000 ...</code> to the engine and record the moves and score.</p>
<p>Here is a sample code to do like that using <a href="https://github.com/niklasf/python-chess" rel="nofollow noreferrer">python chess lib</a> along with other  data and plotting libs.</p>
<h4>Code</h4>
<pre><code>&quot;&quot;&quot;
This script will only work for those uci engines that supports
&quot;go nodes &lt;value&gt;&quot; command.

Requirements:
    pip install chess
    pip install pandas
    pip install matplotlib
&quot;&quot;&quot;

import chess
import chess.engine
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.ticker as plticker


def engine_analysis(efn, fen, nodelimit):
    engine = chess.engine.SimpleEngine.popen_uci(efn)
    try:
        engine.configure({&quot;Hash&quot;: 128})
        engine.configure({&quot;Threads&quot;: 1})
    except Exception as exception:
        pass
    
    board = chess.Board(fen)
    limit = chess.engine.Limit(nodes=nodelimit)

    value, sanmove, nodes, timesec = None, None, 0, 0

    with engine.analysis(board, limit=limit) as analysis:
        for info in analysis:
            
            pv = info.get('pv')
            score = info.get('score')                
            nodes = info.get('nodes')
            timesec = info.get('time')
            
            if pv is not None:
                move = pv[0]
                sanmove = board.san(move)
                
            if score is not None:
                value = score.relative.score(mate_score=32000)

    engine.quit()
    
    return sanmove, value, nodes, timesec
    
    
def run_engine():
    # fen = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1'  # startpos
    fen = 'rnbqkb1r/1p2pppp/p2p1n2/8/3NP3/2N5/PPP2PPP/R1BQKB1R w KQkq - 0 6'  # sicilian
    
    nodes_per_interval = 1000
    num_interval = 30
    
    e1 = {'name': 'Stockfish 14', 'file': 'E:/Chess/Engines/stockfish/sf14/sf14.exe'}
    e2 = {'name': 'Lc0 0.28', 'file': 'E:/Chess/Engines/Lc0/lc0-v0.28.0-windows-gpu-nvidia-cudnn-nodll/lc0.exe'}
    engines = [e1, e2]
    
    dfs = {}
    for eng in engines:
        d = []
        for i in range(num_interval):
            nodelimit = (i+1) * nodes_per_interval
            move, score, actualnodes, timesec = engine_analysis(eng['file'], fen, nodelimit)
            d.append([nodelimit, actualnodes, move, score, timesec])
            
        df = pd.DataFrame(d)
        df.columns = ['nodes', 'actualnodes', 'move', 'scorecp', 'timesec']
        dfs.update({eng['name']: df})
        
    print(f'fen: {fen}')        
    for k, v in dfs.items():
        print(f'{k}:')
        print(f'{v.to_string(index=False)}\n')

    # Plot    
    x = dfs[e1['name']]['nodes']
    y1 = dfs[e1['name']]['scorecp']
    y2 = dfs[e2['name']]['scorecp']
    
    _, (ax1, ax2) = plt.subplots(2, 1, sharex=True, figsize=(12, 6))
    
    ax1.plot(x, y1)
    ax1.set_title(f&quot;{e1['name']} score at different node levels&quot;)
    ax1.set_ylabel('score cp')
    
    ax2.plot(x, y2)
    ax2.set_title(f&quot;{e2['name']} score at different node levels&quot;)
    ax2.set_xlabel('nodes')
    ax2.set_ylabel('score cp')
    plt.setp(ax2.get_xticklabels(), ha=&quot;right&quot;, rotation=45)
       
    loc = plticker.MultipleLocator(base=nodes_per_interval)  # add ticks in every point
    ax2.xaxis.set_major_locator(loc)
    
    plt.savefig('engine_nodes.png')    
    plt.show()
    
    
# start
run_engine()
</code></pre>
<h4>Output</h4>
<pre><code>fen: rnbqkb1r/1p2pppp/p2p1n2/8/3NP3/2N5/PPP2PPP/R1BQKB1R w KQkq - 0 6
Stockfish 14:
 nodes  actualnodes move  scorecp  timesec
  1000         1002  Be3       64    0.002
  2000         2001  Bg5      -24    0.003
  3000         3005  Nb3       46    0.003
  4000         4010  Bg5       32    0.004
  5000         5004  Bg5        4    0.004
  6000         6003  Nb3       13    0.005
  7000         7040  Bg5       19    0.006
  8000         8013  Be3       41    0.009
  9000         9003  Be2       40    0.007
 10000        10019  Be2       33    0.008
 11000        11003   f3       50    0.009
 12000        12014  Qf3       40    0.010
 13000        13004   a4       27    0.010
 14000        14014   a4       47    0.011
 15000        15006  Be2       32    0.011
 16000        16040  Nb3        6    0.012
 17000        17022  Nb3       37    0.013
 18000        18007  Nb3       52    0.014
 19000        19019   a4       17    0.014
 20000        20040   h3       21    0.020
 21000        21032  Be3       38    0.016
 22000        22011   f3       18    0.016
 23000        23039   f3       38    0.023
 24000        24036   f3       50    0.028
 25000        25019  Bg5       69    0.021
 26000        26021   h3       30    0.019
 27000        27071  Be3       27    0.019
 28000        28072  Nb3       44    0.021
 29000        29032  Be3       64    0.020
 30000        30039  Be2       34    0.022

Lc0 0.28:
 nodes  actualnodes move  scorecp  timesec
  1000         1022   f3       20    0.156
  2000         2012   f3       19    0.180
  3000         2997   f3       20    0.214
  4000         3411   f3       19    0.224
  5000         4211   f3       19    0.249
  6000         5428   f3       19    0.279
  7000         6018   f3       19    0.319
  8000         6449   f3       19    0.339
  9000         6993   f3       20    0.349
 10000         7552   f3       20    0.369
 11000         8039   f3       20    0.392
 12000         8173   f3       20    0.379
 13000         8942   f3       20    0.404
 14000         9583   f3       20    0.417
 15000        10075   f3       20    0.475
 16000        10653   f3       20    0.466
 17000        11045   f3       20    0.474
 18000        11732   f3       20    0.506
 19000        12561   f3       20    0.535
 20000        12763   f3       20    0.543
 21000        13268   f3       20    0.570
 22000        13829   f3       20    0.584
 23000        14323   f3       20    0.602
 24000        14883   f3       20    0.641
 25000        15823   f3       19    0.663
 26000        16810   f3       19    0.693
 27000        25923   f3       18    0.938
 28000        27064   f3       18    1.001
 29000        26266   f3       18    0.976
 30000        29043  Be3       18    1.052
</code></pre>
<p><a href="https://i.stack.imgur.com/BjbJm.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/BjbJm.png" alt="enter image description here" /></a></p>
