altair icon indicating copy to clipboard operation
altair copied to clipboard

Select data from Cross Plot and have images from the selected samples display corresponding images

Open Philliec459 opened this issue 5 years ago • 5 comments

Hello,

I am not sure if this is a capability yet in Altair, but the following image illustrates the function that I would like Altair if possible. I created this in Spotfire, but it would be nice to do in Altair.

ThinSection

Philliec459 avatar Sep 05 '20 16:09 Philliec459

I love the interactive aspects of Altair. At this moment I do not know how to select samples from the cross plot as shown above and render the images associated with then, but tooltips does allow you to render the images if you hover over the sample point as shown below. This is great. Thank you for developing this excellent tool. Now to figure out how to show the tooltips for all the selected points on the cross plot????

Clastic_Thin_Sections

Philliec459 avatar Aug 08 '22 12:08 Philliec459

It is possible to show the images of selected points by using two layered charts:

import altair as alt
import pandas as pd

source = pd.DataFrame.from_records(
    [{'a': 1, 'b': 1, 'image': 'https://altair-viz.github.io/_static/altair-logo-light.png'},
     {'a': 2, 'b': 2, 'image': 'https://avatars.githubusercontent.com/u/11796929?s=200&v=4'}]
)

brush = alt.selection_interval()
points = alt.Chart(source).mark_circle(size=200).encode(
    x='a',
    y='b',
).add_selection(
    brush
)

imgs = alt.Chart(source).mark_image(width=100, height=100).encode(
    x='a',
    y='b',
    url='image'
).transform_filter(
    brush
)

points + imgs

ezgif com-gif-maker(14)

There is no automatic dodging as in your example from Spotfire, so they will likely show up on top of each other. An alternative is to use a faceted chart below the original chart:

brush = alt.selection_interval()
points = alt.Chart(source).mark_circle(size=200).encode(
    x='a',
    y='b',
).add_selection(
    brush
)

imgs = alt.Chart(source, width=200, height=200).mark_image().encode(
    url='image'
).facet(
    alt.Facet('image', title='', header=alt.Header(labelFontSize=0))
).transform_filter(
    brush
)

points & imgs

ezgif com-gif-maker(15)

You can play around starting from these two examples and see if you can get the results you want. See this issue for how to use local image via base64 encoding instead of a URL https://github.com/altair-viz/altair/issues/2318 and this issue for automatic resizing of the overall chart area https://github.com/altair-viz/altair/issues/2512

If you want more explicit control over the selected points, you could try the Dashboarding library Panel which support custom interactions with Altair selections.

joelostblom avatar Aug 08 '22 15:08 joelostblom

This is finally what I was looking to do. I would say this is complete. Thank you for your help.

Mode_of_Image_Kurtosis_with_TS

Brush for selection

brush = alt.selection(type='interval')

vega_pane = pn.pane.Vega(chart.add_selection( brush ))

imgs = alt.Chart(source).mark_image(width=50, height=50).encode( url='image' ).facet( alt.Facet('image',title='Select Thin Sections', header=alt.Header(labelFontSize=0)), columns=2 ).transform_window( row_number='row_number()' ).transform_filter( brush ).transform_window( rank='rank(row_number)' ).transform_filter( alt.datum.rank<15 )

#------------------------------------------------

Text Data for Routine Core Analysis data

#------------------------------------------------

Base chart for data tables

ranked_text = alt.Chart(source7).mark_text(align='right').encode( y=alt.Y('row_number:O',axis=None) ).transform_window( row_number='row_number()' ).transform_filter( brush ).transform_window( rank='rank(row_number)' ).transform_filter( alt.datum.rank<28 )

Data Tables

Porosity = ranked_text.encode(text='Porosity:N').properties(title=alt.TitleParams(text='Porosity', align='right')) Permeability = ranked_text.encode(text='Permeability:N').properties(title=alt.TitleParams(text='Permeability', align='right')) Sample = ranked_text.encode(text='Sample:N').properties(title=alt.TitleParams(text='Sample', align='right')) sqrt = ranked_text.encode(text='sqrt(k/phi):N').properties(title=alt.TitleParams(text ='sqrt(k/phi)', align='right')) #Image = ranked_text.encode(tooltip ='image').properties(title=alt.TitleParams(text ='image', align='right')) RI = ranked_text.encode(text='ROCK_INDEX:N').properties(title=alt.TitleParams(text='PRT', align='right')) lith = ranked_text.encode(text='Lith:N').properties(title=alt.TitleParams(text='Lith', align='right'))

text = alt.hconcat(Sample, Porosity, Permeability,lith) # Combine data tables

#------------------------------------------------

Gray Image Data Cross Plot

#------------------------------------------------ kurt = alt.Chart(source).mark_circle(size=300).encode( alt.X('Mode_image:Q', scale=alt.Scale(domain=(0, 1))), #y='Perm', alt.Y('Kurtosis:Q',scale=alt.Scale( domain=(.0, 12))),

color=alt.condition( brush,'ROCK_INDEX:O', alt.value('lightgray'),
                    scale=alt.Scale(
                    domain=[ 1,         2,         3  ,     4         ,5,       6],
                    range =['cyan', '#1e90ff',  'blue'  , 'orange','brown' ,'black'  ])),

tooltip=['image','Sample','Porosity','Permeability','Lith'],  # Must be a list for the image to render

).properties( width=500, height=500, title='Mode of Gray Image vs. Kurtosis Colored by Lithology', ).add_selection(brush)

#------------------------------------------------

Concatenate Cross Plot, Text and Pc curves

#------------------------------------------------

Build visualization

#imgs|kurt|text works kurt|imgs|text

Philliec459 avatar Aug 11 '22 15:08 Philliec459

Great! Thanks for sharing your code! I will keep this open as a reminder to add something along these lines to the docs.

joelostblom avatar Aug 11 '22 20:08 joelostblom

Thank you for you suggestions and ideas. We were able to implement your last comments in Altair to create the following visualization. Thank you.

Best Regards,


E. Craig Phillips CEO and Chief Petrophysicist Crested Butte Petrophysical Consultants

459 Cisneros Lane Crested Butte, CO 81224 USA Office: +1 970-343-0730 Mobile: +1 970-343-0730 email: @.*** Website: www.cbpetro.com GitHub: https://github.com/Philliec459

On Aug 8, 2022, at 11:54 AM, Joel Ostblom @.***> wrote:

It is possible to show the images of selected points by using two layered charts:

import altair as alt import pandas as pd

source = pd.DataFrame.from_records( [{'a': 1, 'b': 1, 'image': 'https://altair-viz.github.io/_static/altair-logo-light.png'}, {'a': 2, 'b': 2, 'image': 'https://avatars.githubusercontent.com/u/11796929?s=200&v=4'}] )

brush = alt.selection_interval() points = alt.Chart(source).mark_circle(size=200).encode( x='a', y='b', ).add_selection( brush )

imgs = alt.Chart(source).mark_image(width=100, height=100).encode( x='a', y='b', url='image' ).transform_filter( brush )

points + imgs https://user-images.githubusercontent.com/4560057/183458561-e52a45af-6fae-425f-825e-9be4c2a83537.gif There is no automatic dodging as in your example from Spotfire, so they will likely show up on top of each other. An alternative is to use a faceted chart below the original chart:

brush = alt.selection_interval() points = alt.Chart(source).mark_circle(size=200).encode( x='a', y='b', ).add_selection( brush )

imgs = alt.Chart(source, width=200, height=200).mark_image().encode( url='image' ).facet( alt.Facet('image', title='', header=alt.Header(labelFontSize=0)) ).transform_filter( brush )

points & imgs https://user-images.githubusercontent.com/4560057/183458930-f3946780-e80c-48fb-b58c-a843f6da28ea.gif You can play around starting from these two examples and see if you can get the results you want. See this issue for how to use local image via base64 encoding instead of a URL #2318 https://github.com/altair-viz/altair/issues/2318 and this issue for automatic resizing of the overall chart area #2512 https://github.com/altair-viz/altair/issues/2512 If you want more explicit control over the selected points, you could try the Dashboarding library Panel https://pyviz-dev.github.io/panel/reference/panes/Vega.html which support custom interactions with Altair selections.

— Reply to this email directly, view it on GitHub https://github.com/altair-viz/altair/issues/2278#issuecomment-1208305563, or unsubscribe https://github.com/notifications/unsubscribe-auth/ANSKYPFDFOGGZJPTHULAATLVYEUTRANCNFSM4Q3DQLTQ. You are receiving this because you authored the thread.

Philliec459 avatar Aug 15 '22 14:08 Philliec459

This is now part of the documentation after https://github.com/altair-viz/altair/pull/3219, so closing this.

joelostblom avatar Oct 16 '23 03:10 joelostblom