Altair mark_text labels where domain in x-axis is linked - python

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

Related

How to make the mark_rule in Altair change based on user input?

I would like to make the mark_rule (significance level) to be adjustable. I have tried to do it using user input code and change the value in the rule from 0.05 to 'user input' but the chart turned out weird.
There are two things that I would like to ask for help with:
Make the mark_rule change through user input (top priority)
Make the color of the bars (factors) below the mark_rule change (optional)
I have tried many codes in this, by far, I can only make the mark_rule move using mouseover but it is not exactly what I want to do.
Any help would be very much appreciated.
import pandas as pd
import altair as alt
Sheet2 = 'P-value'
df = pd.read_excel('Life Expectancy Data- Clean.xlsx', sheet_name=Sheet2)
highlight = alt.selection(type='single', on='mouseover',
fields=['Factor'], nearest=True, empty="none")
bar = alt.Chart(df).mark_bar(strokeWidth=5, stroke="steelblue", strokeOpacity=0.1).encode(
x = alt.X('Factor:O', sort='y'),
y = alt.Y('P-value:Q'),
tooltip = [alt.Tooltip('Factor:O'),alt.Tooltip('P-value:Q',format='.4f')],
color= alt.condition(
highlight,
alt.value("orange"),
alt.value("steelblue"))
).add_selection(
highlight
)
rule = alt.Chart(pd.DataFrame({'y': [0.05]})).mark_rule(color='red').encode(y='y')
alt.layer(
bar, rule
).properties(
title='Factors that Contribute to Life Expectancy in Malaysia',
width=500, height=300
)
Current graph
Building upon the example in the Altair docs, you could do something like this, which gives you a slider that controls the position of the rule and highlights the bars in different colors depending on if they are above or below the slider value:
import altair as alt
import pandas as pd
import numpy as np
rand = np.random.RandomState(42)
df = pd.DataFrame({
'xval': range(10),
'yval': rand.randn(10).cumsum()
})
slider = alt.binding_range(min=0, max=5, step=0.5, name='cutoff:')
selector = alt.selection_single(name="SelectorName", bind=slider, init={'cutoff': 2.5})
rule = alt.Chart().mark_rule().transform_calculate(
rule='SelectorName.cutoff'
).encode(
# Take the mean to avoid creating multiple lines on top of eachother
y='mean(rule):Q',
)
bars = alt.Chart(df).mark_bar().encode(
x='xval:O',
y='yval',
color=alt.condition(
alt.datum.yval < selector.cutoff,
alt.value('coral'), alt.value('steelblue')
)
).add_selection(
selector
)
bars + rule

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)

Rolling average on a layered faceted chart in Altair

I successfully got layers to work in faceted charts and rolling average to work in layered charts. I now want to sort of combine the two i.e have a rolling average in a layered faceted chart.
Intuitively combining the two gives me an error -
Javascript Error: Cannot read property 'concat' of undefined
This usually means there's a typo in your chart specification. See the javascript console for the full traceback.
Code (gives the above error):
# Data Preparation
df = pd.read_csv('https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_confirmed_global.csv')
idf = df[df['Country/Region'] == 'India']
idf = idf[df.columns[4:]]
idf = idf.T
idf = idf.reset_index()
idf.columns = ['day', 'case']
idf['country'] = 'india'
gdf = df[df['Country/Region'] == 'Germany']
gdf = gdf[df.columns[4:]]
gdf = gdf.T
gdf = gdf.reset_index()
gdf.columns = ['day', 'case']
gdf['country'] = 'germany'
fdf = pd.concat([idf,gdf])
# Charting
a = alt.Chart().mark_bar(opacity=0.5).encode(
x='day:T',
y='case:Q'
)
c = alt.Chart().mark_line().transform_window(
rolling_mean='mean(case:Q)',
frame=[-7, 0]
).encode(
x='day:T',
y='rolling_mean:Q'
)
alt.layer(a, c, data=fdf).facet(alt.Column('country', sort=alt.EncodingSortField('case', op='max', order='descending')))
If you remove the transform_window and replace y='rolling_mean:Q' with y='case:Q', you'd get a layered faceted chart. It is this chart on which I want a 7 day rolling average.
You should replace your window transform with this:
.transform_window(
rolling_mean='mean(case)',
frame=[-7, 0],
groupby=['country']
)
There were two issues with your original transform:
type shorthands are only used in encodings, never in transforms. When you wrote mean(case:Q), you were specifying a rolling mean of the field named "case:Q", which does not exist.
since you are faceting by country, you need to group by country when computing the rolling mean.
The result looks like this:
Try to use transform_window by sort=[{'field': 'date'}]
https://vega.github.io/vega-lite/docs/window.html#cumulative-frequency-distribution
Or:
https://altair-viz.github.io/gallery/scatter_marginal_hist.html
https://altair-viz.github.io/gallery/layered_chart_with_dual_axis.html#layered-chart-with-dual-axis
https://altair-viz.github.io/gallery/parallel_coordinates.html#parallel-coordinates-example
import altair as alt
from vega_datasets import data
source = data.iris()
alt.Chart(source).transform_window(
index='count()'
).transform_fold(
['petalLength', 'petalWidth', 'sepalLength', 'sepalWidth']
).mark_line().encode(
x='key:N',
y='value:Q',
color='species:N',
detail='index:N',
opacity=alt.value(0.5)
).properties(width=500)
https://altair-viz.github.io/user_guide/compound_charts.html?highlight=repeat#horizontal-concatenation
import altair as alt
from vega_datasets import data
iris = data.iris.url
chart1 = alt.Chart(iris).mark_point().encode(
x='petalLength:Q',
y='petalWidth:Q',
color='species:N'
).properties(
height=300,
width=300
)
chart2 = alt.Chart(iris).mark_bar().encode(
x='count()',
y=alt.Y('petalWidth:Q', bin=alt.Bin(maxbins=30)),
color='species:N'
).properties(
height=300,
width=100
)

Is there anyway to popping out of part of Map or change of color on selection in Altair

I am trying to plot the states of India in altair.I am able to plot and in the tooltip state names are appearing.I want the state to pop out or change in color on selection.Is there any way to do it.
I tried to use selection_interval.But not able to do it as i am newbie
'''python
import altair as alt
url = "https://raw.githubusercontent.com/deldersveld/topojson/master/countries/india/india-states.json"
source = alt.topo_feature(url, "IND_adm1")
alt.Chart(source).mark_geoshape().encode(
tooltip='properties.NAME_1:N',
color=alt.value('lightgray')
).properties(
width=800,
height=500
)
You can use a Single Selection with a conditional color to do something like this:
import altair as alt
url = "https://raw.githubusercontent.com/deldersveld/topojson/master/countries/india/india-states.json"
source = alt.topo_feature(url, "IND_adm1")
hover = alt.selection_single(on='mouseover', empty='none')
alt.Chart(source).mark_geoshape().encode(
tooltip='properties.NAME_1:N',
color=alt.condition(hover, alt.value('steelblue'), alt.value('lightgray'))
).properties(
width=800,
height=500
).add_selection(
hover
)

Categories

Resources