Altair: Boxplot with round corners - altair

For a bar chart, I can set round corners in the following way:
alt.Chart(
...
).mark_bar(
cornerRadiusTopLeft=4,
cornerRadiusTopRight=4
).encode(
...
)
Is it somehow possible to do the same for boxplots (of course for all four corners)?
Thank you!

You can specify the box argument using a dict, like below:
alt.Chart(source).mark_boxplot(box={'cornerRadius':8}, extent='min-max').encode(
x='age:O',
y='people:Q'
)

Related

Having both X and Y axes' Scales in Altair respond to a selection interval

I'm bringing this question from Altair's github. (https://github.com/altair-viz/altair/issues/2456) Is there a way to get the Scale on Y-axis in the bottom chart to respond to the selection brush? I'd like to be able to pan around the top chart with a selection and see the zoomed-in results in the bottom chart. If I uncomment the alt.Y, then both the X and Y axes show Years and it's messed up. Is there a way to pass just an X or Y value in the 'brush' maybe? Thank you very much!
brush = alt.selection_interval(init={'x':[1950, 1970], 'y':[1500000, 2500000]}, encodings=['x', 'y'])
base = alt.Chart().mark_line().encode(
x=alt.X('Year:Q', title=None),
y='Deaths:Q',
color='Entity:N'
)
alt.vconcat(
base.add_selection(brush).encode().properties(height=150, width=150),
base.encode(
alt.X('Year:Q', scale=alt.Scale(domain=brush)),
#alt.Y('Deaths:Q', scale=alt.Scale(domain=brush)) # (un)commenting this line makes it work/fail only along the x-axis
).properties(
height=500, width=500
),
data='https://vega.github.io/vega-datasets/data/disasters.csv'
)
Yes, see Open the Chart in the Vega Editor
It filters the data of the 2nd chart using a filter transform on the brush param.

Shared axis labels with independent scale

When facet/concat-ing charts, I would like the axis labels to be shared (so only 1 label per column/row, here: Horsepower), but the scale to be independent. Is this possible?
I thought a combination of resolve_axis and resolve_scale would be the way to go, as the title is a part of Axis, but I didn't get it to work.
I'm also wondering what resolve_axis actually does different than resolve_scale, anyone has an example?
base = alt.Chart(source).mark_circle().encode(
x=alt.X('Horsepower:Q',),
y=alt.Y('Miles_per_Gallon:Q'),
color='Origin:N',
row=alt.Row('Origin:N'),
).properties(
width=200, height=100
)
base.resolve_axis(
x='shared' # doesn't do anything obvious
).resolve_scale(
x='independent'
)
Open the Chart in the Vega Editor
I found a hacky way to do this, by misusing the facet header:
base = alt.Chart(source).mark_circle(size=60).encode(
x=alt.X('Horsepower:Q',),
y=alt.Y('Miles_per_Gallon:Q',
axis=alt.Axis(title=''),),
color='Origin:N',
column=alt.Column('Origin:N', header=alt.Header(title='Miles_per_Gallon')),
).properties(
width=200, height=200
).configure_header(
labelExpr="['Origin',datum.value]",
titleOrient='left'
)
display(base.resolve_scale(y='shared'))
display(base.resolve_scale(y='independent'))
I don't know of any way to do what you're hoping for (independent scales with only a single outer axis title) via scale and guide resolution.
As to your question of the difference between resolve_scale and resolve_axis, an example may help.
Here's a chart with independent y scale:
import altair as alt
from vega_datasets import data
source = data.cars()
base = alt.Chart(source).mark_circle().encode(
x=alt.X('Horsepower:Q',),
y=alt.Y('Miles_per_Gallon:Q'),
color='Origin:N',
column=alt.Column('Origin:N'),
).properties(
width=150, height=150
)
base.resolve_scale(
y='independent'
)
And here's one with independent y axis:
base.resolve_axis(
y='independent'
)
In both cases, each chart gets its own axis (because independent scales imply independent axes), but only with an independent scale do the axes scales differ from each other.

Ticks on color bar are overlapping because the values are very close to each other

I'm trying to display the exact values on one axis of the color bar and a basic scale on the other. However, some of the exact values are so close together their names overlap on the color bar. Is there a way for me to make the overlapping names appear as a list or just to the side the other values name? I've already tried rotation of the labels, setting vmin/vmax in the color bar method, and setting the ylim's of the second axis. I'm at a lose at what to try next. It feels like this is something matplotlib would allow but I can't find what method or kwargs that allow this manipulation. Many of the commented out tlines are the attempts I've made with help from many posts on StackOverflow. Thank you!!
Previous code deleted for clarity
UPDATE: Paul H here is a workable example with the same issue I'm trying to fix
# Make random data with same issue
x, y = np.linspace(-3, 1.5, 20), np.linspace(0, 0.5, 20)
# two different ranges used to simulate the same issue in my data
fake_phase = np.append(np.random.random_sample(15), np.arange(0.0, .005, 0.001))
fake_labels = np.array(['V439Oph', 'ALVir', 'YZVir', 'XXVir', 'V716Oph', 'BFSer', 'BLHer',
'RXLib', 'CEHer', 'V465Oph', 'V1180Sgr', 'CSCas', 'DQAnd', 'IXCas',
'UYEri', 'TWCap', 'AUPeg', 'MZCyg', 'SWTau', 'TXDel'], dtype=object)
# Plot data
fig, ax = plt.subplots(1,1,figsize=(15,10))
plt.tight_layout()
plt.plot(x, y, marker='.', ms=17, mew=2, linestyle='none')
# Make the same colorbar
norm = cm.colors.Normalize(vmin=0.0, vmax=1.0, clip=False)
cbar = fig.colorbar(cm.ScalarMappable(norm=norm, cmap='rainbow'), ax=ax, extend='both',
orientation='vertical', pad=0.005, use_gridspec=True)
cbar.set_ticks(fake_phase)
cbar.set_ticklabels(fake_labels)
cbar.ax.tick_params(which='major', labelsize='large', width=1.5, length=6)
cbar.set_label(label='Phase', size='xx-large', labelpad=40)
cbar.ax.set_aspect('auto')
ax2 = cbar.ax.twinx()
pos = cbar.ax.get_position()
pos.x0 += 0.1
ax2.set_position(pos)
plt.show();
The output of this code: Output of workable example
My issue is that the secondary axis on the colorbar (left axis) has values that are so close together their labels overlap. I'm hoping to find a way to space the labels so they are readable. I thought I found a way to accomplish this using axis.set_ticklabels() (set_ticklabels() documentation. In the **kargs section of the doc it references using text properties. In the text properties documentation text properties doc the property 'y' says you can set the y-position of the text. However, when I add this keyword to set_ticklabels() I get an error that the keyword is not recognized.. I've tried adding the property 'y' as a keyword and attribute but I get a keyword error or does not have that attribute error...
I'm calling the property wrong but I've never gotten this detailed in editing these parameters. I honestly don't know if this is the best way to solve this, but it's the closest I've gotten so far. I was hoping to use it to offset the labels so they were stacked vertically on top of each other in the same order but far enough apart that the label is readable.
Thanks for any input!

Altair color bar chart by value not presented

Trying to color a bar chart using a condition based on a value that is not presented in the chart.
I got this dataframe:
I would like to color the bar green if row.presented_value > row.coloring_value , else color red.
I saw examples of conditions by constant values and by displayed values, but couldn't make it work for me.
In the code example below I would like both foo and bar to be red.
import pandas as pd
df = pd.DataFrame({'name':['bar','foo'],
'presented_value':[10,20],
'coloring_value':[15,25]})
(alt.Chart(df, height=250, width=375).mark_bar()
.encode(x='name', y=alt.Y('presented_value', axis=alt.Axis(orient='right')),
color=alt.condition(alt.datum['presented_value'] > df.loc[df.name==alt.datum.x,
'coloring_value'].values[0],
alt.value('lightgreen'),alt.value('darkred'))
)
)
Changing the first value of coloring_value to <10 both bars will be green even though I would expect only bar to be green.
df = pd.DataFrame({'name':['bar','foo'],
'presented_value':[10,20],
'coloring_value':[5,25]})
(alt.Chart(df, height=250, width=375).mark_bar()
.encode(x='name', y=alt.Y('presented_value', axis=alt.Axis(orient='right')),
color=alt.condition(alt.datum['presented_value'] > df.loc[df.name==alt.datum.x,
'coloring_value'].values[0],
alt.value('lightgreen'),alt.value('darkred'))))
Still not coloring by the correct values. Any idea on how to get it done?
Thanks in advance!
Condition expressions cannot use pandas constructs; they must map to vega expressions. Altair provides the alt.datum and alt.expr object as convenience wrappers for this.
In your case, when you want to compare two values in the row, the best way to do that is to compare them directly:
(alt.Chart(df, height=250, width=375).mark_bar()
.encode(
x='name',
y=alt.Y('presented_value', axis=alt.Axis(orient='right')),
color=alt.condition(
alt.datum.presented_value > alt.datum.coloring_value,
alt.value('lightgreen'),
alt.value('darkred')
)
)
)

Plotting values using matplotlib and find minimum by looking the graph

I have dictionary as:
```{'0.0': 2.445616223564293,
'0.05': 2.445594095119315,
'0.1': 2.4455740588234223,
'0.15': 2.4455560866270947,
'0.2': 2.4455401509059596,
'0.25': 2.4455262244535803,
'1.0': 2.4455411399961293,
'1.05': 2.44555597697399,
'1.1': 2.4455724183134344,
'1.15': 2.4455904432448716,
'1.2': 2.445610031303073,
'1.25': 2.4456311623222002,
'2.0': 2.4461204322901566,
'3.0': 2.447205696789686,
'4.0': 2.4486856713473726,
'5.0': 2.4504762863004363,
'10.0': 2.4623061878090624,
'20.0': 2.4922549001247876}```
Here all the values are different by some small factor. However when I plot it using matplotlib the plot is not distinctive.
I want to plot "keys" in x-axis and "values" in y-axis and then find x which has minimum y value by looking the plot.
I tried this code:
```plt.plot(*zip(*data))```
But the plot is not clear. How can I solve this problem such that plot is clearly able to show the difference in values.
The problem is your interpretation of zip(*data). I would suggest before plotting you first print and see what you are trying to plot.
print (list(zip(*data))) would print a list of splitted strings (keys of your data). To plot the keys on the x-axis and the values of the y-axis, simply do the following. I leave the visualization of the minimum up to you. If you want to plot the difference, subtract the first value from the complete list of values and then plot it on the y-axis.
plt.plot(data.keys(), data.values(), '-bx')
plt.xticks(rotation=45)

Resources