
                ax[li].set_yticklabels([])
        
    # colorbar
    fig.subplots_adjust(right=0.9)
    cbar_ax = fig.add_axes([0.9, 0.3, 0.02, 0.6]) # [left, bottom, width, height] 
    fig.colorbar(im, cax=cbar_ax)

    return fig


def _plot_2D(n_lbls, u_lbls, n_features, means, vmin, vmax, cmap, feature_names):
    # plot
    fig,ax = plt.subplots(1, n_lbls, figsize=(3*np.ceil(n_features[1]/5)*n_lbls, 2*np.ceil(n_features[0]/5)))
    for li in range(n_lbls):
        im = ax[li].imshow(means[li], vmin=vmin, vmax=vmax, cmap=cmap)
        ax[li].set_title(f'Macrostate {u_lbls[li]}')
        ax[li].set_xticks(range(n_features[1]))
        ax[li].set_yticks(range(n_features[0]))
        if feature_names is not None:
            ax[li].set_xticklabels(feature_names[1], rotation=45, ha='right')
            if li==0:
                ax[li].set_yticklabels(feature_names[0])
            else:
                ax[li].set_yticklabels([])

        
    # colorbar
    fig.subplots_adjust(right=0.9)
    cbar_ax = fig.add_axes([0.9, 0.3, 0.02, 0.6]) # [left, bottom, width, height] 
    fig.colorbar(im, cax=cbar_ax)

    return fig

def _plot_3D(n_lbls, u_lbls, n_features, means, vmin, vmax, cmap, feature_names):
    # plot
    fig,ax = plt.subplots(n_features[2], n_lbls, figsize=(3*np.ceil(n_features[1]/5)*n_lbls, 3*np.ceil(n_features[0]/5)*n_features[2]))
    for fi in range(n_features[2]):
        for li in range(n_lbls):
            im = ax[fi,li].imshow(means[li,:,:,fi], vmin=vmin, vmax=vmax, cmap=cmap)
            if fi==0:
                ax[fi,li].set_title(f'Macrostate {u_lbls[li]}\n{feature_names[2][fi]}')
            else:
                ax[fi,li].set_title(feature_names[2][fi])
            ax[fi,li].set_xticks(range(n_features[1]))
            ax[fi,li].set_yticks(range(n_features[0]))
            if feature_names is not None:
                if fi==n_features[2]-1:
                    ax[fi,li].set_xticklabels(feature_names[1], rotation=45, ha='right')
                else:
                    ax[fi,li].set_xticklabels([])
                if li==0:
                    ax[fi,li].set_yticklabels(feature_names[0])
                else:
                    ax[fi,li].set_yticklabels([])
        
    # colorbar
    fig.subplots_adjust(right=0.9)
    cbar_ax = fig.add_axes([0.9, 0.3, 0.02, 0.6]) # [left, bottom, width, height] 
    fig.colorbar(im, cax=cbar_ax)

    return fig
<gh_stars>0
"use strict";

const {addressToScript} = require("@ckb-lumos/helpers");
const {locateCellDep, TransactionSkeleton} = require("@ckb-lumos/helpers");
const {CellCollector} = require("@ckb-lumos/indexer");
const {secp256k1Blake160} = require("@ckb-lumos/common-scripts");
const {sealTransaction} = require("@ckb-lumos/helpers");
const {addDefaultWitnessPlaceholders, collectCapacity, describeTransaction: libDescribeTransaction, getLiveCell, sendTransaction, signMessage, waitForConfirmation, DEFAULT_LOCK_HASH} = require("../lib/index.js");
const {ckbytesToShannons, hexToInt, intToHex} = require("../lib/util.js");
const { ALICE_ADDRESS, BOB_ADDRESS, CHARLIE_ADDRESS, BOB_PK, CHARLIE_PK, ALICE_PK, DANIEL_ADDRESS } = require("./accounts.js");
const { isEqual } = require('lodash');

function describeTransaction(transaction)
{
	const options =
	{
		showCellDeps: false,
		showInputs: true,
		showInputType: false,
		showInputData: true,
		showOutputs: true,
		showOutputType: false,
		showOutputData: true,
		showWitnesses: false
	};

	return libDescribeTransaction(transaction, options);
}

async function initializeLab(nodeUrl, indexer)
{
	// Genesis account.
	const fundingAccountPrivateKey = "<KEY>";
	const fundingAccountAddress = "<KEY>";	

	// Accounts to fund.
	const ACCOUNTS_TO_FUND = [{address: ALICE_ADDRESS, privateKey: ALICE_PK}, {address: BOB_ADDRESS, privateKey: BOB_PK}, {address: CHARLIE_ADDRESS, privateKey: CHARLIE_PK}];
	const AMOUNT_TO_FUND = ckbytesToShannons(100n);

	// Transaction Fee
	const txFee = 100_000n;

	// Initialize a Lumos instance.
	let transaction = await initializeLumosSkeleton(indexer);

	// Flags to track which addresses were used.
	const addressesUsed = new Set();
	let totalRecycledCapacity = 0n;

	let addressIndex = 1;
	for (const account of ACCOUNTS_TO_FUND) {
		// Recycle all existing Cells to inputs.
		const query = {lock: addressToScript(account.address), type: null};
		const cellCollector = new CellCollector(indexer, query);
		const recycleCells = [];
		for await (const cell of cellCollector.collect())
			recycleCells.push(cell);
		if(recycleCells.length > 0)
			addressesUsed.add(addressIndex);
		transaction = transaction.update("inputs", (i)=>i.concat(recycleCells));

		// Determine the capacity from recycled Cells.
		const recycledCapacity = recycleCells.reduce((a, c)=>a+hexToInt(c.cell_output.capacity), 0n);
		totalRecycledCapacity += recycledCapacity;

		// Create cells for the funding address.
		const outputCapacity = intToHex(AMOUNT_TO_FUND);
		const output = {cell_output: {capacity: outputCapacity, lock: addressToScript(account.address), type: null}, data: "0x"};
		transaction = transaction.update("outputs", (i)=>i.push(output));

		addressIndex++;
	}	

	// Get the sum of the outputs.
	const outputCapacity = transaction.outputs.toArray().reduce((a, c)=>a+hexToInt(c.cell_output.capacity), 0n);

	// Add input capacity cells to the transaction.
	if(outputCapacity - totalRecycledCapacity + ckbytesToShannons(61n) > 0) // Only add if there isn't enough recycled capacity.
	{
		const collectedCells = await collectCapacity(indexer, addressToScript(fundingAccountAddress), outputCapacity - totalRecycledCapacity + ckbytesToShannons(61n));
		transaction = transaction.update("inputs", (i)=>i.concat(collectedCells.inputCells));
		addressesUsed.add(0);
	}

	// Determine the capacity from all input Cells.
	const inputCapacity = transaction.inputs.toArray().reduce