Is there a good way to code review EDA (exploratory data analysis)?

Hi!

I’ve been using streamlit extensively in place of Jupyter for EDA. For our team processes, we submit our analysis through code review. One of the common questions I’ve had from reviewers used to Jupyter is, “Is there a way to quickly see which code has generated the chart?” I’m accustomed to doing quick searches in the streamlit code to the accompanying text in the browser, but it’s a flow change that’s difficult for other folks new to streamlit.

Has anyone come up with any good solutions to bridge this?

Thanks!
Danny

Hi Danny,

You can use st.echo to display both your code and the associated chart. If you wish to not always display the code, but to have an option to switch it on or off, you could use the following (not very elegant) work-around:

show_python_code = st.sidebar.checkbox("Show the Python Code")

if show_python_code:
    with st.echo():
        table = df.describe()
    st.write(table)
else:
    st.write(df.describe())

If someone has a better solution for this then I am curious to know as well.

1 Like

Hi Bjorn,

I like this solution. For large code executions it becomes unwieldy due to having to write the execution in the echo block and else block. Have you found a way around that?

Thanks!

I agree, but I have not found a way around it yet.

Hi @Danny_Nguyen,
in our hello.py example we have toggable source code in the app: https://github.com/streamlit/streamlit/blob/develop/lib/streamlit/hello/hello.py#L101

We use inspect.getsourcelines to do this. That said, it would be nice to integrate this better with Streamlit. Feel free to open a Feature Request here.

Matteo

1 Like

Another option is to roll your own st.echo that shows the checkbox. This is just a straight copy-paste adaptation that adds a checkbox:

import contextlib
import textwrap
import traceback

import streamlit as st
from streamlit import source_util
from streamlit.compatibility import is_running_py3


@contextlib.contextmanager
def maybe_echo():
    if not st.checkbox("Show Code"):
        yield
        return

    code = st.empty()
    try:
        frame = traceback.extract_stack()[-3]
        if is_running_py3():
            filename, start_line = frame.filename, frame.lineno
        else:
            filename, start_line = frame[:2]
        yield
        frame = traceback.extract_stack()[-3]
        if is_running_py3():
            end_line = frame.lineno
        else:
            end_line = frame[1]
        lines_to_display = []
        with source_util.open_python_file(filename) as source_file:
            source_lines = source_file.readlines()
            lines_to_display.extend(source_lines[start_line:end_line])
            initial_spaces = st._SPACES_RE.match(lines_to_display[0]).end()
            for line in source_lines[end_line:]:
                indentation = st._SPACES_RE.match(line).end()
                # The != 1 is because we want to allow '\n' between sections.
                if indentation != 1 and indentation < initial_spaces:
                    break
                lines_to_display.append(line)
        lines_to_display = textwrap.dedent("".join(lines_to_display))

        code.code(lines_to_display, "python")

    except FileNotFoundError as err:  # noqa: F821
        code.warning("Unable to display code. %s" % err)


with maybe_echo():
    some_computation = "Hello, world!"
    st.write(some_computation)

1 Like