Altair Chart Conditional Text Opacity - python

Given the image below some values are smaller than 50. I want values smaller than 50 not to be on the chart.
Is it possible to hide, remove or shrink opacity for this?
Code is:
import altair as alt
from vega_datasets import data
import streamlit as st
source=data.barley()
bars = alt.Chart(source).mark_bar().encode(
x=alt.X('sum(yield):Q', stack='zero'),
y=alt.Y('variety:N'),
color=alt.Color('site')
)
text = alt.Chart(source).mark_text(dx=-15, dy=3, color='white').encode(
x=alt.X('sum(yield):Q', stack='zero'),
y=alt.Y('variety:N'),
detail='site:N',
text=alt.Text('sum(yield):Q', format='.1f')
)
st.altair_chart(bars + text, theme="streamlit", use_container_width=True)

You can use an aggregate transform to have access to the aggregated values in a condition and filter based on a threshold:
import altair as alt
from vega_datasets import data
base = alt.Chart(data.barley())
bars = base.mark_bar().encode(
x=alt.X('sum(yield):Q', stack='zero'),
y=alt.Y('variety:N'),
color=alt.Color('site'),
)
text = base.mark_text(dx=-2, color='white', align='right').transform_aggregate(
yield_sum='sum(yield)',
groupby=['variety', 'site']
).encode(
x=alt.X('yield_sum:Q', stack='zero'),
y=alt.Y('variety:N'),
text=alt.Text('yield_sum:Q', format='.0f'),
opacity=alt.condition('datum.yield_sum > 50', alt.value(1), alt.value(0)),
order='site' # This is needed because the transform_aggregate return a different order of the values than the bar chart
)
bars + text

Related

Combining string and aggregate function within bar chart label in Altair

I have made two interactive linked histograms with crossfiltering using Altair. I have created labels over each bar with the sum of the filtered items by using mark_text(). Below is an image of the linked charts:
I would like learn how to concatenate a string in the label so that it would look something like: 'error: 481.1'. This is the relevant code snippet:
crossfilter = alt.selection(type='interval', encodings=['x'])
tick_up = alt.Chart().transform_filter(crossfilter).mark_tick(color='black').encode(
x = x,
y = alt.Y(plus_error+':Q', aggregate='sum'))
text = tick_up.mark_text(
align='left',
baseline='middle',
dx=12
).encode(text='sum(error):Q')
When I try to change .encode(text='sum(error):Q') to something like .encode(text='"error": sum(error):Q'), it throws me an error, is there a simple way to do this? I have also tried using transform_calculate, but I need something adapts to what is being selected by crossfilter.
I would also like to learn how to create a label with multiple lines, for example:
curr_error: 123.1
previous_error: 110
You can use + in transform_calculate to concatenate a string and a number. I believe you will also need transform_joinaggregate to have your sum accessible in the calculation transformation. Something like this:
import altair as alt
from vega_datasets import data
source = data.cars()
chart = alt.Chart(source).mark_text(align='left', dx=2).encode(
x='sum(Horsepower)',
y='Origin',
text='label:N'
).transform_joinaggregate(
sum_hp = 'sum(Horsepower)',
groupby=['Origin']
).transform_calculate(
label = "'error: ' + datum.sum_hp"
)
chart.mark_bar() + chart
This also works with a selection, but make sure the transform_filter is before the other transforms so that only the selected data points are used for the calculations:
import altair as alt
from vega_datasets import data
source = data.cars()
brush = alt.selection_interval()
scatter = alt.Chart(source).mark_point().encode(
x='Horsepower',
y='Weight_in_lbs',
color='Origin'
).add_selection(
brush
)
bars = alt.Chart(source).mark_text(align='left', dx=2).encode(
x='sum(Horsepower)',
y='Origin',
text='label:N'
).transform_filter(
brush
).transform_joinaggregate(
sum_hp = 'sum(Horsepower)',
groupby=['Origin']
).transform_calculate(
label = "'error: ' + datum.sum_hp"
)
scatter & bars.mark_bar() + bars

How to move axis label to opposite side in Altair horizontal bar chart

My current chart looks like this:
But I would like it to look like this with the percentages on the left side of the bar chart:
What would be the easiest way to change this? Should I add more axis properties to my chart code? This is the code I have so far for the visualization:
bars = alt.Chart(percentages_df).mark_bar().encode(
y=alt.Y('EMOJI',sort='-x'),
x=alt.X('PERCENT', axis=None)
)
text = bars.mark_text(
align='left',
# baseline='middle',
dx=3
).encode(
text=alt.Text('PERCENT_TEXT:N')
)
chart=(text+bars).configure_mark(
color='#DAC352'
).configure_scale(
bandPaddingInner = 0.1
).properties(
width = 450,
height = 180
).configure_view(
strokeWidth = 0
)
chart
I used the horizontal bar graph in the official reference as an example. First I moved the y-axis to the left and set the label value there to the position of the overall y-axis.
import altair as alt
from vega_datasets import data
source = data.wheat()
bars = alt.Chart(source).mark_bar().encode(
x='wheat:Q',
y=alt.Y("year:O", axis=alt.Axis(ticks=False, domain=False, offset=25))
)
text = bars.mark_text(
align='right',
baseline='middle',
dx=3
).encode(
x=alt.value(-5),
text='wheat:Q'
)
(bars + text).properties(height=900)

Appending sample number to X-Labels in altair

I would like to automatically append the sample # (in parentheses) corresponding to the x-labels of an altair figure. I am open to doing this outside of altair, but I thought there may be a way to do it at the figure level using altair/vega-lite. I am pasting the code using an example from the altair/vega website (part of the vega_dataset), but with a hackneyed, manual method in which I rename the labels explicitly for one of the labels. In this case, I have added the sample number of 73 to Europe.
Link to data
import altair as alt
from vega_datasets import data
df = data.cars()
df['Origin'] = df['Origin'].replace({'Europe':'Europe (n=73)'})
alt.Chart(df).transform_density(
'Miles_per_Gallon',
as_=['Miles_per_Gallon', 'density'],
extent=[5, 50],
groupby=['Origin']
).mark_area(orient='horizontal').encode(
y='Miles_per_Gallon:Q',
color='Origin:N',
x=alt.X(
'density:Q',
stack='center',
impute=None,
title=None,
axis=alt.Axis(labels=False, values=[0],grid=False, ticks=True),
),
column=alt.Column(
'Origin:N',
header=alt.Header(
titleOrient='bottom',
labelOrient='bottom',
labelPadding=0,
),
)
).properties(
width=100
).configure_facet(
spacing=0
).configure_view(
stroke=None
)
You could use pandas to generate the replacement dictionary and assign it to a new dataframe column:
import altair as alt
from vega_datasets import data
df = data.cars()
group_sizes = df.groupby('Origin').size()
replace_dict = group_sizes.index + ' (n=' + group_sizes.astype(str) + ')'
df['Origin_with_count'] = df['Origin'].replace(replace_dict)
alt.Chart(df).transform_density(
'Miles_per_Gallon',
as_=['Miles_per_Gallon', 'density'],
extent=[5, 50],
groupby=['Origin_with_count', 'Origin']
).mark_area(orient='horizontal').encode(
y='Miles_per_Gallon:Q',
color='Origin:N',
x=alt.X(
'density:Q',
stack='center',
impute=None,
title=None,
axis=alt.Axis(labels=False, values=[0],grid=False, ticks=True),
),
column=alt.Column(
'Origin_with_count:N',
header=alt.Header(
title=None,
labelOrient='bottom',
labelPadding=0,
),
)
).properties(
width=100
).configure_facet(
spacing=0
).configure_view(
stroke=None
)
You might be able to do something more elegant with labelExpr, not sure.
You could overlay a text mark with the count instead.
I was able to do this with the following code. I was not able to manage the y position of the text (see commented-out line) or use the n datum in the header labelExpr for some reason.
df = data.cars()
violin = alt.Chart(df).transform_density(
'Miles_per_Gallon',
as_=['Miles_per_Gallon', 'density'],
extent=[5, 50],
groupby=['Origin']
).mark_area(orient='horizontal').encode(
y='Miles_per_Gallon:Q',
color='Origin:N',
x=alt.X(
'density:Q',
stack='center',
impute=None,
title=None,
axis=alt.Axis(labels=False, values=[0],grid=False, ticks=True),
),
).properties(width=100)
text = alt.Chart(df).mark_text().transform_aggregate(
cnt='count()',
groupby=["Origin"]
).transform_calculate(
n = "'n=' + datum.cnt",
).encode(
# y=alt.Y('mean(Miles_per_Gallon):Q'),
text=alt.Text('n:N'),
)
(violin + text).facet(
column=alt.Column('Origin:N'),
).configure_header(
labelExpr="[datum.value, datum.n]",
)

Altair mark_text labels where domain in x-axis is linked

I was trying to give text labels on some altair chart linked to a selected interval from another chart. I realize that the text given by "mark_text ()" doesn't show completely at the last points of the chart where the domain in the x-axis is specified to be the interval selected, also I didn't know how to specify the format so the dates will be given just as yyyy-mm or month-year (don't want to display the day).
Another thing that I realized, is when one specifies the tooltip doesn't show at all when the domain on the x-axis of the graph is also linked to an interval selected in another chart
, that's the reason I used the mark_text()
the code I'm using is the following
import altair as alt
from vega_datasets import data
nearest = alt.selection_single(nearest=True, on='mouseover',
encodings=['x','y'], empty='none')
interval = alt.selection_interval(encodings=['x'])
weather = data.seattle_weather()
base = alt.Chart(weather).mark_rule(size=2).encode(
x='date:T')
chart = base.mark_line().encode(
x=alt.X('date:T', scale=alt.Scale(domain=interval.ref())),
y='temp_max:Q',).properties(
width=800,
height=300)
text=base.mark_text(align='left', dx=5, dy=5).encode(
y='temp_max:Q',
text=alt.condition(nearest, 'label:N', alt.value(' '))
).transform_calculate(label='"Date: " + format(datum.date, "") '
).properties(selection=nearest,width=800,
height=300)
point=base.mark_point().encode(y='temp_max:Q',opacity=alt.condition(nearest, alt.value(1), alt.value(0)))
view = base.mark_line().add_selection(
interval).properties(width=800, height=20)
(point+text+chart) &view
It looks like you're trying to create a tooltip using a layer, and this is the cause of many of the problems you're having. Have you considered using the tooltip encoding?
import altair as alt
from vega_datasets import data
nearest = alt.selection_single(nearest=True, on='mouseover',
encodings=['x','y'], empty='none')
interval = alt.selection_interval(encodings=['x'])
weather = data.seattle_weather()
line = alt.Chart(weather).mark_line().encode(
x=alt.X('date:T', scale=alt.Scale(domain=interval)),
y='temp_max:Q'
).properties(
width=800,
height=200
)
point = line.mark_point().encode(
tooltip='yearmonth(date):N',
opacity=alt.condition(nearest, alt.value(1), alt.value(0))
).add_selection(nearest)
view = alt.Chart(weather).mark_line().encode(
x='date:T',
).properties(
width=800,
height=20
).add_selection(interval)
(point + line) & view

How to do annotations with Altair?

I am trying to write some text inside the figure to highlight something in my plot (equivalent to 'annotate' in matplotlib). Any idea? Thanks
You can get annotations into your Altair plots in two steps:
Use mark_text() to specify the annotation's position, fontsize etc.
Use transform_filter() from datum to select the points (data subset) that needs the annotation. Note the line from altair import datum.
Code:
import altair as alt
from vega_datasets import data
alt.renderers.enable('notebook')
from altair import datum #Needed for subsetting (transforming data)
iris = data.iris()
points = alt.Chart(iris).mark_point().encode(
x='petalLength',
y='petalWidth',
color='species')
annotation = alt.Chart(iris).mark_text(
align='left',
baseline='middle',
fontSize = 20,
dx = 7
).encode(
x='petalLength',
y='petalWidth',
text='petalLength'
).transform_filter(
(datum.petalLength >= 5.1) & (datum.petalWidth < 1.6)
)
points + annotation
which produces:
These are static annotations. You can also get interactive annotations by binding selections to the plots.

Categories

Resources