<jupyter_start><jupyter_text>Here, we explain how to use TransferFunctionHelper to visualize and interpret yt volume rendering transfer functions.  Creating a custom transfer function is a process that usually involves some trial-and-error. TransferFunctionHelper is a utility class designed to help you visualize the probability density functions of yt fields that you might want to volume render.  This makes it easier to choose a nice transfer function that highlights interesting physical regimes.First, we set up our namespace and define a convenience function to display volume renderings inline in the notebook.  Using `%matplotlib inline` makes it so matplotlib plots display inline in the notebook.<jupyter_code>import yt
import numpy as np
from IPython.core.display import Image
from yt.visualization.volume_rendering.transfer_function_helper import TransferFunctionHelper
from yt.visualization.volume_rendering.render_source import VolumeSource

def showme(im):
    # screen out NaNs
    im[im != im] = 0.0
    
    # Create an RGBA bitmap to display
    imb = yt.write_bitmap(im, None)
    return Image(imb)<jupyter_output><empty_output><jupyter_text>Next, we load up a low resolution Enzo cosmological simulation.<jupyter_code>ds = yt.load('Enzo_64/DD0043/data0043')<jupyter_output><empty_output><jupyter_text>Now that we have the dataset loaded, let's create a `TransferFunctionHelper` to visualize the dataset and transfer function we'd like to use.<jupyter_code>tfh = TransferFunctionHelper(ds)<jupyter_output><empty_output><jupyter_text>`TransferFunctionHelpler` will intelligently choose transfer function bounds based on the data values.  Use the `plot()` method to take a look at the transfer function.<jupyter_code># Build a transfer function that is a multivariate gaussian in temperature
tfh = TransferFunctionHelper(ds)
tfh.set_field(('gas', 'temperature'))
tfh.set_log(True)
tfh.set_bounds()
tfh.build_transfer_function()
tfh.tf.add_layers(5)
tfh.plot()<jupyter_output><empty_output><jupyter_text>Let's also look at the probability density function of the `mass` field as a function of `temperature`.  This might give us an idea where there is a lot of structure.<jupyter_code>tfh.plot(profile_field=('gas', 'mass'))<jupyter_output><empty_output><jupyter_text>It looks like most of the gas is hot but there is still a lot of low-density cool gas.  Let's construct a transfer function that highlights both the rarefied hot gas and the dense cool gas simultaneously.<jupyter_code>tfh = TransferFunctionHelper(ds)
tfh.set_field(('gas', 'temperature'))
tfh.set_bounds()
tfh.set_log(True)
tfh.build_transfer_function()
tfh.tf.add_layers(8, w=0.01, mi=4.0, ma=8.0, col_bounds=[4.,8.], alpha=np.logspace(-1,2,7), colormap='RdBu_r')
tfh.tf.map_to_colormap(6.0, 8.0, colormap='Reds')
tfh.tf.map_to_colormap(-1.0, 6.0, colormap='Blues_r')

tfh.plot(profile_field=('gas', 'mass'))<jupyter_output><empty_output><jupyter_text>Let's take a look at the volume rendering. First use the helper function to create a default rendering, then we override this with the transfer function we just created.<jupyter_code>im, sc = yt.volume_render(ds, [('gas', 'temperature')])

source = sc.get_source()
source.set_transfer_function(tfh.tf)
im2 = sc.render()

showme(im2[:,:,:3])<jupyter_output><empty_output><jupyter_text>That looks okay, but the red gas (associated with temperatures between 1e6 and 1e8 K) is a bit hard to see in the image. To fix this, we can make that gas contribute a larger alpha value to the image by using the ``scale`` keyword argument in ``map_to_colormap``.<jupyter_code>tfh2 = TransferFunctionHelper(ds)
tfh2.set_field(('gas', 'temperature'))
tfh2.set_bounds()
tfh2.set_log(True)
tfh2.build_transfer_function()
tfh2.tf.add_layers(8, w=0.01, mi=4.0, ma=8.0, col_bounds=[4.,8.], alpha=np.logspace(-1,2,7), colormap='RdBu_r')
tfh2.tf.map_to_colormap(6.0, 8.0, colormap='Reds', scale=5.0)
tfh2.tf.map_to_colormap(-1.0, 6.0, colormap='Blues_r', scale=1.0)

tfh2.plot(profile_field=('gas', 'mass'))<jupyter_output><empty_output><jupyter_text>Note that the height of the red portion of the transfer function has increased by a factor of 5.0. If we use this transfer function to make the final image:<jupyter_code>source.set_transfer_function(tfh2.tf)
im3 = sc.render()

showme(im3[:,:,:3])<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1032020271826768, 'fraction_numerical': 0.018659295093296474, 'mean_word_length': 6.384353741496598, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '9', 'dir': 'jupyter-structured-clean-dedup', 'id': '133280', 'license': 'BSD-3-Clause-Clear', 'n_tokens_mistral': 1460, 'n_tokens_neox': 1417, 'n_words': 437, 'path': 'doc/source/visualizing/TransferFunctionHelper_Tutorial.ipynb', 'repo_name': 'agurvich/yt', 'size': '4341'}