vega / vegafusion

Serverside scaling for Vega and Altair visualizations
https://vegafusion.io
BSD 3-Clause "New" or "Revised" License
316 stars 18 forks source link

VegaFusionWidget doesn't work tooltip=True in compound charts #497

Open cosmicfarmers opened 1 month ago

cosmicfarmers commented 1 month ago

Hi Jon,

Thanks for your project always!

I am posting a reproducible notebook about another possible bug. I must add like .add_params(alt.selection_point(fields=['DUMMY'])) to make tooltip=True work.

import altair as alt
import vegafusion as vf
import vl_convert as vlc
import pandas as pd
alt.__version__, vf.__version__, vlc.__version__, pd.__version__
('5.3.0', '1.6.9', '1.5.0', '2.1.2')
buttons_pdf = pd.DataFrame({'greeting':['hello','world']})

values_pdf = pd.DataFrame({'vals':[1,2,3,4,5],'greeting':['hello','world','hello','world','hello']})

buttons_picker = alt.selection_point(fields=['greeting'], name='buttons_picker')
values_brush = alt.selection_interval(encodings=['x'], name='values_brush')

buttons_ap = (
    alt.Chart(buttons_pdf)
        .encode(
            y='greeting:N',
            opacity=alt.condition(buttons_picker, alt.value(1), alt.value(0.2))
        )
        .mark_circle(size=200, color='crimson')
        .add_params(buttons_picker)
)

text_ap = (
    alt.Chart()
        .transform_calculate(
            GREETING="buttons_picker['greeting']+''"
        )
        .encode(
            text='GREETING:N'
        )
        .mark_text(tooltip=True)
        #.add_params(alt.selection_point(fields=['DUMMY']))
)

Altair: Tooltip WORKING

final_ap = alt.hconcat(buttons_ap, text_ap)
final_ap

altair_work

VegaFusionWidget: Tooltip NOT WORKING

vf.jupyter.VegaFusionWidget(final_ap)

vf_not_work

VegaFusionWidget: Tooltip WORKING only when I add some params.

I need a workaround .add_params(alt.selection_point(fields=['DUMMY'])).

text_ap2 = (
    alt.Chart()
        .transform_calculate(
            GREETING="buttons_picker['greeting']+''"
        )
        .encode(
            text='GREETING:N'
        )
        .mark_text(tooltip=True)
        .add_params(alt.selection_point(fields=['DUMMY']))
)
vf.jupyter.VegaFusionWidget(alt.hconcat(buttons_ap, text_ap2))

vf_workaround

jonmmease commented 1 month ago

Thanks for the report and repro! Looks like something might be going wrong in our dependency analysis. Could you take a look at the server_vega_spec, client_vega_spec, and comm_plan properties and see if anything stands out between the broken case and the workaround case? See https://vegafusion.io/planner_results.html.

cosmicfarmers commented 1 month ago

I am looking into the VegaFusionWidget instances of the cases I mentioned above. It can takes some more time on my side since I have some of my works deadline come. (but I fortunately found some workarounds.)

By the way, I found another workaround, which MIGHT be related to the quick question in this thread: https://github.com/vega/vegafusion/issues/495#issuecomment-2226884040

one quick question: sometimes all of data transformations are sent to my browser. I haven't investigated deeply because now it works like separating heavy parts work in server-side fortunately. Is there a way that I can check what part will work in server-side and which part will work in client-side before rendering it?

This is the new workaround.

I just convert the vega-lite json from altair instance (which was the input of the broken vf) into vega spec. using vl_converter, and I input the vega spec. to the VegaFusionWidget. It shows tooltips without adding a random param, although it is not utilizing server-side computation at all.

This is the code.

Workaround 2

final_ap_vega_spec = vlc.vegalite_to_vega(final_ap.to_json())
workaround2_vf = vf.jupyter.VegaFusionWidget(final_ap_vega_spec)
workaround2_vf

comm_plan of Workaround 2 (Tooltip: Yes, Server-side Computation: No)

{
  "server_to_client": [],
  "client_to_server": []
}

comm_plan of the Workaround 1 (Tooltip: Yes, Server-side Computation: Yes)

( which I added a param like .add_params(alt.selection_point(fields=['DUMMY'])) )

{
  "server_to_client": [
    {
      "namespace": "data",
      "name": "source_0",
      "scope": []
    },
    {
      "namespace": "data",
      "name": "source_0_view_4_y_domain_greeting",
      "scope": []
    }
  ],
  "client_to_server": []
}

comm_plan of the Broken (Tooltip: No, Server-side Computation: Yes)

{
  "server_to_client": [
    {
      "namespace": "data",
      "name": "source_0",
      "scope": []
    },
    {
      "namespace": "data",
      "name": "source_0_view_1_y_domain_greeting",
      "scope": []
    }
  ],
  "client_to_server": []
}

Getting back to the "quick question", I think I had a trouble with sending all data to my web browser but I guess it was fixed because I fixed the tooltip by using .add_params(alt.selection_point(fields=['DUMMY'])), which seems to be the only way for now to have benefits of both server-side computation and tooltip showing, although I am not 100% sure.

This is what I guessed what happened to me.