Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
Philliec459 opened this issue Sep 5, 2020 · 6 comments

Comments

@Philliec459
Copy link

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
Copy link
Author

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

@joelostblom
Copy link
Contributor

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 #2318 and this issue for automatic resizing of the overall chart area #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.

@Philliec459
Copy link
Author

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

@joelostblom
Copy link
Contributor

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

@Philliec459
Copy link
Author

Philliec459 commented Aug 15, 2022 via email

@joelostblom
Copy link
Contributor

This is now part of the documentation after #3219, so closing this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants