Customize Anchor System

Customize Anchor System

Artemis provides you a host of tools and customization features to speed up and customize your Artemis experience. You can create preprocessor macros called fields, create custom output types, configure the information generated in the "System Information" card, and tweak different aspects of Artemis' runtime behavior. All of this customization takes place inside configuration files. These configuration files are applied to a script when you use the @import anchor in the entry point file for your code.

Creating a Configuration File

You can generate a template configuration file by running the command below in your console. This template configuration file contains examples of creating custom fields, creating custom output types, adding custom information to the "System Information" card, and customizing the runtime behavior of Artemis.

artemis_labs config

Using a Configuration File

You can use a configuration file in your script using the @import anchor

# @import ./config.py

Elements Of a Configuration File

Here are the four different aspects of the Artemis anchor system that you can customize in a configuration file.

Custom fields covers how you can create custom fields which may be used across your codebase.

Custom runtime information walks through how to add additional information to the "System Information" card at the top of every Artemis codebase.

Customize runtime behavior shows how customize the values of your code in useful forms, such as tables, text, images, graphs, and more. Use outputs to visualize datasets, intermediate values, and results from your work.

Custom output types overviews how you can create your own output types for use with the `@output` anchor.

Elements Of a Configuration File - Detailed

Below, you can find detailed documentation on the different elements of a configuration file.

Custom Fields

You can define your own custom fields by adding the following code to your configuration file

fields = {
   'field_name_1' : 'field_value_1',
   'field_name_2' : 'field_value_2',
   'field_name_3' : 'field_value_3',
}
ArtemisRuntimeManager.register_fields(fields)

If you include this configuration file in your code using the @import anchor, you can now use the fields "field_name_1", "field_name_2", and "field_name_3" in your code.

''' @blockdoc
Field 1: %%field_name_1%%
Field 2: %%field_name_2%%
Field 3: %%field_name_3%%
'''
717717

Custom Runtime Information

You can add your own custom fields to the "System Information" card (the first card of every Archive) by adding the following code to your configuration file

run_information = {
    'Information 1' : 'Value 1',
    'Information 2' : 'Value 2',
    'Information 3' : 'Value 3'
}
ArtemisRuntimeManager.register_run_information(run_information)

Including this configuration file in your code would make the "System information" card look like such:

663663

Custom Runtime Information

You can customize different aspects of Artemis runtime behavior by adding the following code to your configuration file:

Supported PropertyEffect
delayDefault delay after each @card anchor
runtime_settings = {
    'delay' : 0
}
ArtemisRuntimeManager.register_runtime_settings(runtime_settings)

Custom Output Types

You can create custom output types to visualize variables in ways not natively supported by Artemis. To create a custom output type, add the following code to your config file.

def custom_output_function(data , named_args_dict : Dict) -> Tuple:

    # Do stuff to data...
    
    # Serialize data
    serialized_data = ArtemisHelper.serialize(data, ArtemisType.SERIALIZATION_TYPE, named_args_dict)

    # Return serialized_data
    return serialized_data
  
ArtemisConfigManager.register_function(custom_output_function, 'custom_output_type')

Let's break this code down:

  1. Whenever you create a custom output type, you must first create a function which can be called when your output type is invoked. This function should have have the function prototype def custom_output_function(data , named_args_dict : Dict) -> Tuple:. When your output is called, Artemis will pass the "data" named argument in the data argument and all other named arguments in the "named_args_dict" field.
  2. Inside your function, you should use "data" and "named_args_dict" to create the final data that you would like to output. This could involve plotting the data to create a graph or preprocessing data to be displayed as a table.
  3. The last part of your function should serialize your output variable by calling ArtemisHelper.serialize and return that serialized data. The will convert your data into a standardized form Artemis can render in the browser. Artemis supports the following serializations:
Variable TypeArtemis TypeExample
Matplotlib FigureArtemisType.MATPLOTLIB_FIGUREArtemisHelper.serialize(fig, ArtemisType.MATPLOTLIB_FIGURE)
  1. Finally, you should bind this function to the output type by calling ArtemisConfigManager.register_function(custom_output_function, 'custom_output_type')
  2. Now, when you call # @output custom_output_type data=x named_arg_1=y named_arg_2=z, it will call your custom_output_type function, passing x as the data arg, and the dictionary { "named_arg_1" : y, "named_arg_2" : z} as named_args_dict

Here's an example of creating a custom histogram output:

def histogram(arr , named_args_dict : Dict) -> Tuple:
    '''
    This takes in a 1D container of numerical values and named args,
    plots a histogram using those numerical values, using
    named arguments to customize the graph,
    and returns a serialized form of the matplotlib figure
    :param arr: 1D container of values to graph (List or Numpy)
    :param named_args_dict: Named arguments provided when invoking decorator
    :return: Serialized histogram
    '''

    # Convert type to numpy array if it is a list
    arr = ArtemisHelper.convert_if(arr, ArtemisType.LIST, ArtemisType.NUMPY_ARRAY)

    # Validate input
    ArtemisHelper.assert_input_is_type(arr, np.ndarray)

    # Setup plot arguments
    setup_plot_args(named_args_dict)

    # Actually plot data
    plt.hist(arr, 50)

    # Serialize plot
    serialized_plot = ArtemisHelper.serialize(None, ArtemisType.MATPLOTLIB_PLOT, named_args_dict)

    # Close figure
    plt.close()

    # Return serialized plot
    return serialized_plot
ArtemisConfigManager.register_function(histogram, 'histogram')