man-group / dtale

Visualizer for pandas data structures
http://alphatechadmin.pythonanywhere.com
GNU Lesser General Public License v2.1
4.62k stars 390 forks source link

Export charts as Plotly objects when using `offline_chart` API #851

Closed Miautawn closed 2 months ago

Miautawn commented 3 months ago

Hey there! I have a QOL improvement idea for jupyter notebook users - ability to easily export charts as plotly figure objects via offline_chart function.

Currently, I use the offline_chart API, since in my opinion, it's the best option to create plots using Dtale within notebooks while still keeping them reproducible and easily readable, which is extremely important for me (might be a personal thing).

However, sometimes you need to do something advanced, like combining the plots, and it's pretty hard to do when the offline_chart simply returns a rendered HTML, instead of the plotly figure object.

My idea addresses just that - an option to get the resulting plotly figure object when creating plots using the convenient & powerful offline_chart API. As a matter of fact, you can do it right now, by simply calling the functions that offline_chart uses under the hood - dtale.dash_application.charts.build_raw_chart.

Below is a working example of the proposed use case:

from dtale.utils import make_list, dict_merge
from dtale.dash_application.charts import build_raw_chart

def modified_offline_chart(
    chart_type=None,
    query=None,
    x=None,
    y=None,
    z=None,
    group=None,
    agg=None,
    window=None,
    rolling_comp=None,
    barmode=None,
    barsort=None,
    yaxis=None,
    title=None,
    **kwargs
):
    """
    Identical function to `offline_chart()`
        but returns plotly figure object instead
    """
    params = dict(
        chart_type=chart_type,
        query=query,
        x=x,
        y=make_list(y),
        z=z,
        group=make_list(group),
        agg=agg,
        window=window,
        rolling_comp=rolling_comp,
        barmode=barmode,
        barsort=barsort,
        yaxis=yaxis,
        title=title,
    )
    params = dict_merge(params, kwargs)
    chart = build_raw_chart(d._data_id, **params)

    return chart
from plotly.subplots import make_subplots

fig1 = modified_offline_chart(
    chart_type="bar",
    x="label",
    y="index",
    agg="pctct",
    group="sender_to_reciever_feed_link_valid",
    load=40,
)

fig2 = modified_offline_chart(
    chart_type="bar",
    x="label",
    y="index",
    agg="pctct",
    group="thread_author_to_reciever_feed_link_valid",
    load=40,
)

# combine the figures to be side by side
fig = make_subplots(rows=1, cols=2)

for trace in fig1["data"]:
    fig.add_trace(trace, row=1, col=1)

for trace in fig2["data"]:
    fig.add_trace(trace, row=1, col=2)

fig.update_layout(
    title_text="Side by Side Charts",
    width=1000,
)

fig.show()

Result: image

aschonfeld commented 2 months ago

@Miautawn sorry for the long wait. So I'm thinking i'll add a return_object parameter to the offline_chart function. It will be False by default and if you pass return_object=True to this function it will do what you're asking. Will keep you posted when it gets released

Miautawn commented 2 months ago

Hey there! Thank you, this is exactly what I was thinking about :)

aschonfeld commented 2 months ago

@Miautawn this has been added in v3.12.0 on pypi (soon to be on conda-forge as well). Let me know how it goes. Also, whenever you get a sec would you mind tossing your ⭐ on the repo? Thanks 🙏