Position altair legend top-center - altair

I would like to position an altair legend top-center. Getting it to the top is simple enough by passing legend=alt.Legend(title=None, orient="top"). I also gather that this is possible in vega-lite but am having trouble making that all work together.
`

Altair does not yet support the layout property that newer versions of Vega-Lite support, but you can position your legend manually following the approach used in one of the other answers to the linked question.
For example:
import altair as alt
from vega_datasets import data
source = data.cars()
alt.Chart(source).mark_circle(size=60).encode(
x='Horsepower',
y='Miles_per_Gallon',
color=alt.Color('Origin', legend=alt.Legend(
orient='none',
legendX=130, legendY=-40,
direction='horizontal',
titleAnchor='middle'))
)

Related

Only display marker at TimeStamp using Folium TimestampedGeoJson

I am plotting ground tracks of a satellite using Folium's TimestampGeoJson plugin. I am able to plot the animated markers, but would like to only display the marker at timestamp. I want the previous markers to disappear, and only have one marker shown on the map at a time, to create the illusion of the satellite moving around the map.
Here is the code I use to generate the map:
import folium
import webbrowser
from folium.plugins import TimestampedGeoJson
def generate_map(latlon_list, geojson_data):
my_map = folium.Map(location=[0,0], height=1000, width=1000, zoom_start=2,
min_zoom=2, max_zoom=12, max_bounds=True, no_wrap=True)
map_name = "folium_1000_1000_map.html"
tgj = TimestampedGeoJson(geojson_data, period="PT1M", add_last_point=False)
my_map.add_child(tgj)
This generates the following:
I want the animation to only display one marker at a time. Here is a ref to a similar question I have found, but none of the answers mentioned there have the effect I want.
Thanks.
And the answer lies in the referenced question, i just added:
tgj = TimestampedGeoJson(satellite["geojson_data"], period="PT1M", duration="PT1M", add_last_point=False)
To my TimestampedGeoJson object, and voila ! Only markers at timestamp will be displayed now. The important option here is the duration one.

How to hide subplot labels in facet graph?

This code:
import altair as alt
from vega_datasets import data
alt.Chart(data.iris()).mark_point().encode(
x='petalLength:Q',
y='petalWidth:Q',
facet=alt.Facet('species:N', header=alt.Header(labels=False, title=None), columns=3)
).properties(
width=250,
height=250
)
produces this chart:
I have added red lines beneath what I believe are called subplot "labels". How can I remove them? This question asked how to change them, and #jakevdp said that is impossible. This question asked how to remove them (same as me), and #jakevdp hasn't answered yet. They used a column parameter to eliminate the labels, but when I try that, it complains about the columns parameter I'm using. I want to both (a) eliminate the labels and (b) limit the number of subplots per row, with automatic row wrapping.
What you did should have worked (i.e. alt.Header(title=None, labels=False)); the fact that it doesn't is probably a bug (I think it's the same issue reported here: https://github.com/altair-viz/altair/issues/2252)
As a workaround for the issue, you can use labelExpr to hide them:
alt.Chart(data.iris()).mark_point().encode(
x='petalLength:Q',
y='petalWidth:Q',
facet=alt.Facet('species:N', header=alt.Header(labelExpr="''", title=None), columns=3)
).properties(
width=250,
height=250
)

Main figure legend outside of subplots

I have a number of subplots within a single figure. Each figure plots multiple lines that represent the same thing (represented by color) but in different situations (different subplots). I would like to create a legend at the base of the figure showing what the color of the line means. However, I running into a problem with getting the legend to not overlap the subplots and if I can adjust the axes, getting the legend to save.
I have tried a few different solutions with some help here but have been unable to adapt to subplots. Below is an example code that I am working with.
import numpy as np
import matplotlib.pyplot as plt
m1=1
m2=10
x=np.linspace(0,100,num=101,endpoint=True)
y1m1=m1*x**2
y2m1=m1*x**0.5
y1m2=m2*x**2
y2m2=m2*x**0.5
fig=plt.figure(figsize=(4,4))
ax1=fig.add_subplot(211)
ax1.plot(x,y1m1,'b',label=r'$x^2$')
ax1.plot(x,y2m1,'r',label=r'$\sqrt{x}$')
ax2=fig.add_subplot(212)
ax2.plot(x,y1m2,'b')
ax2.plot(x,y2m2,'r')
fig.legend(loc='lower center',ncol=2)
fig.tight_layout()
fig.savefig('examplefig.png',dpi=300)
plt.show()
My goal is to save the output to a png for a good figure.
This is one way of doing it using the suggestion provided here. The idea is to add the legend at position with respect to a given axis object. In your case, since you want to add the legend at the base, it is preferred you specify the position relative to ax2. Using ncol=2 is a matter of personal choice.
fig=plt.figure(figsize=(4,4))
ax1=fig.add_subplot(211)
l1, = ax1.plot(x,y1m1,'b')
l2, = ax1.plot(x,y2m1,'r')
ax2=fig.add_subplot(212)
ax2.plot(x,y1m2, 'b')
ax2.plot(x,y2m2, 'r')
ax2.legend(handles = [l1,l2] , labels=[r'$x^2$', r'$\sqrt{x}$'],
bbox_to_anchor=(0.7, -0.2), ncol=2)
fig.tight_layout()

Altair empty plot: The compiled spec uses Vega v3, but current version is 4.2.0

The code below yields an empty plot:
import pandas as pd
import altair as alt
df = pd.DataFrame({'Month': [1,2,3],
'P [mm]': [90.2,100.4,80.1]})
alt.Chart(df).mark_line().encode(x='Month',
y='P [mm]')
The JavaScript console shows the message:
The compiled spec uses Vega v3, but current version is 4.2.0.
As far as I'm aware, Altair in fact doesn't appear to use Vega 4.2.0, although there seems to be some development in this sense on GitHub. The question is: how can I downgrade Vega to the Altair-compatible v3? Or is that not even what I should be trying to do?
Obs.: Using JupyterLab 0.32.1
In general, column names with non-alphanumeric should be avoided in Altair.
In particular, Vega-Lite allows field names to include special syntax based on periods and square brackets in order to access data from hierarchical JSON inputs.
These special characters can be escaped, but there is currently a bug in Vega-Lite regarding such escapes. The easiest way to address this in Altair is to rename your input data so the columns do not contain these special characters. For example:
import pandas as pd
import altair as alt
df = pd.DataFrame({'Month': [1,2,3],
'P [mm]': [90.2,100.4,80.1]})
df.rename({'P [mm]': 'P'}, axis=1, inplace=True)
alt.Chart(df).mark_line().encode(
x='Month',
y=alt.Y('P', title='P [mm]')
)

Networkx - exporting graphml with edge labels, height and width attributes, custom images

I want to automate a network topology diagram using python. I'm new to python so please bear with me. After doing some research I found out that I can use python to create graphml files which can be read by yEd.
I'm learning how to use Networkx to create the graphml files. So far I'm able to create nodes, connect them and add labels to the nodes (these labels would be the hostnames). Now I need to know how I can add labels to the edges (these labels would be the interfaces). For example:
Topology example
If possible I would like to know how to add a custom image for every node (by default the shape is a square but I would like to use a router png file).
If it is not possible then it would be helpful to know how to edit the height and width of the shape and also disabling arrows.
I've reviewed the docs on networkx website but I haven't found how to do these changes directly to the graph object. The only way I've seen it done is when drawing the graph, for example using the following function: nx.draw_networkx_labels(G, pos, labels, font_size=15, arrows=False), but this is not what I need because this is not saved to the graphml file.
If someone can guide me through this it would be really helpful, I'm attaching my code:
import networkx as nx
import matplotlib
import matplotlib.pyplot as plt
g = nx.DiGraph()
g.add_node('Hostname_A')
g.add_node('Hostname_B')
g.add_node('Hostname_C')
g.add_node('Hostname_D')
g.add_edge('Hostname_A','Hostname_B')
g.add_edge('Hostname_A','Hostname_C')
g.add_edge('Hostname_B','Hostname_D')
g.add_edge('Hostname_B','Hostname_C')
for node in g.nodes():
g.node[node]['label'] = node
nx.readwrite.write_graphml(g, "graph.graphml")
This is the solution:
for edge in g.edges():
g.edges[edge]['source'] = 'int gi0/0/0'
g.edges[edge]['destination'] = 'int gi0/0/1'

Resources