Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Passing arguments to a nested function in Python

I have two functions, called update_y_with_x and update_x

which are as follows:

update_y_with_x

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

def update_y_with_x(chosen_tissue):
    for i, trace in enumerate(f.data):
        if trace.type == "scatter":
            # reset all line width
            f.data[i].line.width = 1

            if chosen_tissue in trace.text:
                f.data[i].line.width = 1 + 9

update_x


def update_x(trace, points, selector):
    if len(points.point_inds) == 0:
        return

    # Remove existing bar shades and linked lines' highlights
    f.layout.shapes = ()

    for i, trace in enumerate(f.data):
        if trace.type == "scatter" and f.data[i].line.width != 1:
            f.data[i].line.width = 1

    # Get tissue identity
    chosen_tissue = f.data[points.trace_index].y[points.point_inds[0]]

    # Get the index of the chosen tissue
    possible_trace_indices = [
        i for i, trace in enumerate(f.data) if trace.type == "bar"
    ]
    chosen_tissue_ranks = [
        list(f.data[index].y).index(chosen_tissue) for index in possible_trace_indices
    ]

    for i, _ in enumerate(possible_trace_indices):
        # Specify the y-range around the clicked bar for shading
        y0 = chosen_tissue_ranks[i] + 0.5
        y1 = y0 - 1

        f.add_hrect(
            y0=y0,
            y1=y1,
            line_width=0,
            fillcolor="grey",
            opacity=0.3,
            row=1,
            col=i * 2 + 1,
        )

    # Update lines
    update_y_with_x(chosen_tissue)

as you can see, update_x calls the update_y_with_x function, at the moment, both use a hard-coded plotly go figurewidget, where

f = go.FigureWidget(fig)

and are called like so:

for i, trace in enumerate(f.data):
    if trace.type == 'bar':  # Check if it's a barplot
        f.data[i].on_click(update_x)

I would like to do two things:

  1. Move these two functions to an independent function file and import them into the main.ipynb file I’m working with

  2. Pass f as a parameter to each function, rather than having it hard – coded as it currently exists in the function, and make sure that it is passed to update_y_with_x prior to it being used in update_x

If I’ve missed something key please let me know and would be incredibly grateful for any help 🙂

Edit:
update_x click events on a bar plot. When a bar is clicked, it removes existing shapes, resets line widths for linked scatter plots, adds shaded rectangles around the clicked bars, and updates lines which link these bars together.

What I tried:
I initially exported these functions to a new file called "click_events.py", and added in the argument for each figure_widget, like so:

  • def update_x(trace, points, selector, figure_widget): (replaced f in file)

  • def update_y_with_x(chosen_tissue, figure_widget): (replaced f in file)

  • modify the code in update_x so that update_y_with_x(chosen_tissue, figure_widget = figure_widget)

However, I believe that when I imported and try to run these functions in the way mentioned above the figure_widget isn’t being passed to ‘update_y_with_x’.

>Solution :

For the two goals you mentioned, moving the functions to an independent file and passing f as a parameter

Steps:

1. Create an Independent Function File:

Create a new Python file (let’s call it plot_utils.py for example) and move the functions update_y_with_x and update_bar into this file. The content of plot_utils.py would look like this:

# plot_utils.py

import plotly.graph_objects as go

def update_y_with_x(fig, chosen_tissue):
    for i, trace in enumerate(fig.data):
        if trace.type == "scatter":
            # reset all line width
            fig.data[i].line.width = 1

            if chosen_tissue in trace.text:
                fig.data[i].line.width = 1 + 9

def update_bar(fig, trace, points, selector):
    if len(points.point_inds) == 0:
        return

    # Remove existing bar shades and linked lines' highlights
    fig.layout.shapes = ()

    for i, trace in enumerate(fig.data):
        if trace.type == "scatter" and fig.data[i].line.width != 1:
            fig.data[i].line.width = 1

    # Get tissue identity
    chosen_tissue = fig.data[points.trace_index].y[points.point_inds[0]]

    # Get the index of the chosen tissue
    possible_trace_indices = [
        i for i, trace in enumerate(fig.data) if trace.type == "bar"
    ]
    chosen_tissue_ranks = [
        list(fig.data[index].y).index(chosen_tissue) for index in possible_trace_indices
    ]

    for i, _ in enumerate(possible_trace_indices):
        # Specify the y-range around the clicked bar for shading
        y0 = chosen_tissue_ranks[i] + 0.5
        y1 = y0 - 1

        fig.add_hrect(
            y0=y0,
            y1=y1,
            line_width=0,
            fillcolor="grey",
            opacity=0.3,
            row=1,
            col=i * 2 + 1,
        )

    # Update lines
    update_y_with_x(fig, chosen_tissue)

2. In your Main Jupyter Notebook (main.ipynb):

In your main Jupyter Notebook, you can import these functions and use them as follows:

# main.ipynb

import plot_utils
import plotly.graph_objects as go

# Create the initial figure
f = go.FigureWidget(fig)

# Register the on_click event
for i, trace in enumerate(f.data):
    if trace.type == 'bar':  # Check if it's a barplot
        f.data[i].on_click(lambda trace, points, selector: plot_utils.update_bar(f, trace, points, selector))

Now, both update_y_with_x and update_bar are in a separate file, and you can import and use them in your main notebook. The f figure is passed as a parameter to both functions, making them more flexible and avoiding hard coding.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading