Plotting¶
[1]:
from optiwindnet.importer import load_repository
from optiwindnet.interarraylib import G_from_S
from optiwindnet.mesh import make_planar_embedding
from optiwindnet.pathfinding import PathFinder
from optiwindnet.heuristics import EW_presolver
Create a sample network¶
[2]:
locations = load_repository()
L = locations.london
P, A = make_planar_embedding(L)
S = EW_presolver(A, capacity=7)
Gʹ = G_from_S(S, A)
G = PathFinder(Gʹ, planar=P, A=A).create_detours()
Using Matplotlib-based gplot()¶
Matplotlib can produce inline plots in Jupyter notebooks using different formats. The default is PNG and it works ok, but the embedding of the binary image in the text-only .ipynb file makes them big and generates many false-positives when searching for short strings (outside of Jupyter, e.g. ripgrep).
By using the SVG format, the notebooks are smaller in size and the false-positives are avoided. In addition, the vector-based figures saved within the notebook can be exported as editable SVG files without needing to run the notebook again. On JupyterLab:
Shift+Right_click -> “Open image in new tab”
Menu “File” -> “Save”
The ‘svg.fonttype’ rcParams entry set to ‘none’ prevents Matplotlib from converting text to paths, which also helps with reducing image sizes (the drawback being possible visual differences if the fonts used at creation are not available when visualizing the figures).
One drawback of SVG plots in Jupyter notebooks is having to mark the notebook as Trusted to display the figures when opening it on a different computer than the one that created it. In JupyterLab <Ctrl+Shift+C>, search for ‘trust’ and select “Trust Notebook”.
[3]:
import matplotlib.pyplot as plt
%config InlineBackend.figure_formats = ['svg']
plt.rcParams['svg.fonttype'] = 'none'
The Matplotlib-based plotting functions in OptiWindNet are gplot() and pplot().
[4]:
from optiwindnet.plotting import pplot, gplot
[5]:
ax = gplot(G)
If G is assigned cable types, it is encoded in the thickness of the edges (higher capacities represented by thicker lines). The total network cost is also added to the infobox.
[6]:
from optiwindnet.interarraylib import assign_cables
[7]:
# one 2-tuple for each cable type: (capacity, linear cost)
# capacities must be increasing
assign_cables(G, cables=[(2, 400), (4, 600), (7, 900)])
[8]:
ax = gplot(G)
gplot() returns a plt.Axes object, which can be used to adjust many aspects of the figure, or to save it to a file in a variety of formats, e.g.:
ax.figure.savefig('myfig.pdf')
It is also possible to provide a pre-existing plt.Axes object within a matplotlib figure:
[9]:
fig, (ax1, ax2) = plt.subplots(1, 2, facecolor='none', figsize=(9, 3))
pplot(P, A, ax=ax1)
gplot(A, ax=ax2)
[9]:
<Axes: >
pplot(P, A) is only useful for tinkering with the pathfinding algorithm and most OptiWindNet users will not need to use it. Plotting the available edges graph A is useful mainly for debugging.
The main advantages of gplot() over svgplot() are node tags and figure legends:
[10]:
gplot(G, node_tag='label', infobox=False, legend=True)
[10]:
<Axes: >
Alternatively, the internal index of the nodes can be shown instead of their labels:
[11]:
gplot(G, node_tag=True, infobox=False)
[11]:
<Axes: >
The nodes can also be tagged by the power they export towards the substation:
[12]:
gplot(G, node_tag='load')
[12]:
<Axes: >
Using svgplot()¶
[13]:
from optiwindnet.svg import svgplot
Most plots in the examples are created with svgplot(). The figures are visually similar to the ones generated with gplot, except for the lack of the node_tag and legend options. The infobox position here is fixed to the lower-right corner, while gplot() tries to place it in the least-obtrusive position.
The advantage of an SVG created by svgplot() over the one produced by Matplotlib is its smaller and simpler structure, which is also better suited for further editing (e.g. using Inkscape).
[14]:
import networkx as nx
[15]:
# disable cable type encoding by resetting cable assignments
del G.graph['cables']
nx.set_edge_attributes(G, 0, 'cable')
# disable cost display by removing currency
del G.graph['currency']
[16]:
svgplot(G)
[16]:
The svgplot() does not create an inline image upon being called, the SVG is displayed when the object returned by the svgplot() call is the cell output. To display figures created within the code cell, use IPython.display.display.
To save to a file:
svgplot(G).save('myfig.svg')
[17]:
for cap in [9, 7, 5]:
S = EW_presolver(A, capacity=cap)
Gʹ = G_from_S(S, A)
G = PathFinder(Gʹ, planar=P, A=A).create_detours()
display(svgplot(G))
Dark and Light plotting themes¶
Both gplot() and svgplot() try to match the colors used in the figure to the operating system’s theme via Python package darkdetect. This package detects the system’s theme and not JupyterLab’s theme, so it may lead to non-ideal results if they do not match.
The example notebooks are created from a dark-themed system, but the figures might have a light background when the notebooks are run on a different computer.
The theme can be enforced programmatically by setting the argument dark to True or False:
[18]:
svgplot(G, dark=False)
[18]:
Rotated locations¶
Each location included in OptiWindNet has a graph attribute called ‘landscape_angle’.
[19]:
L.graph['landscape_angle']
[19]:
-95
This is the angle that will rotate the site to be in the best orientation for a landscape figure. If the user prefers the orientation to be with the north always up, the argument landscape can be used. Alternatively, ‘landscape_angle’ could be set to 0.
[20]:
svgplot(G, landscape=False)
[20]: