import matplotlib.pyplot as plt
import bluemira.geometry.tools
from bluemira import display
from bluemira.base.components import Component, PhysicalComponent
from bluemira.display.plotter import FacePlotter, WirePlotter
from bluemira.geometry.face import BluemiraFace
from bluemira.geometry.parameterisations import PrincetonD
Plotting examples
Setup
Creation of a closed wire and respective face and discretisation points.
PrincetonD parameterisation is used as example.
Note: the curve is generated on the x-z plane
p = PrincetonD()
p.adjust_variable("x1", 4, lower_bound=3, upper_bound=5)
p.adjust_variable("x2", 16, lower_bound=10, upper_bound=20)
p.adjust_variable("dz", 0, lower_bound=0, upper_bound=0)
wire = p.create_shape()
face = BluemiraFace(wire)
Default plotting
We can plot the list of points, as well as the BluemiraWire and BluemiraFace in the following way, using the display built-in function with default settings
display.plot_2d(wire)
display.plot_3d(wire)
display.plot_2d(face)
display.plot_3d(face)
In a similar way, it is possible to use specific Plotters for each entity, i.e. PointsPlotter, WirePlotter, and FacePlotter. For example:
plotter_2d = WirePlotter()
plotter_2d.plot_2d(wire)
Modifying defaults
Default plot options can be obtained in form of a dictionary instancing one of the plotters, e.g.:
my_options = display.plotter.get_default_options()
print(my_options)
Modifying the dictionary and passing it to a plot function will display the plot with the new options
my_options.wire_options = {"color": "red", "linewidth": "1.5"}
display.plot_2d(wire, my_options)
Alternatively, plot options can be modified directly inside a Plotter, e.g.:
plotter_2d.options.show_points = True
plotter_2d.options.number_points = True
plotter_2d.options.ndiscr = 15
plotter_2d.plot_2d(wire)
Once you get familiar with the options, you can also make your own dictionaries, and pass them to the plotting functions
my_options = {
"show_points": False,
"wire_options": {"color": "red", "linewidth": 3, "linestyle": "dashed"},
}
display.plot_2d(wire, **my_options)
Being matplotlib the default plot library, points_options, wire_options, and face_options are equivalent to the **kwargs passed to the functions scatter, plot, and fill, respectively.
Discretise the wire to an array of points.
points = wire.discretise(ndiscr=10, byedges=True)
Points Plot
Simple plot of the obtained points.
A 2D plot with the built-in display functions
display.plot_2d(
points, point_options={"s": 30, "facecolors": "red", "edgecolors": "black"}
)
# or with a Plotter
# pplotter = PointsPlotter(
# point_options={"s": 30, "facecolors": "red", "edgecolors": "black"}
# )
# pplotter.plot_2d(points)
3D Scatter Plot
A plot of the same points, but in 3D this time.
display.plot_3d(
points, point_options={"s": 30, "facecolors": "red", "edgecolors": "black"}
)
# pplotter = Plotter3D(
# point_options={"s": 30, "facecolors": "red", "edgecolors": "black"}
# )
# pplotter.plot_3d(points)
Wire Plot
A WirePlotter is used with the default setup with:
view = xz (this is the projection plane, not a section plane)
point size = 20
ndiscr = 15
wplotter = WirePlotter(view="xz")
wplotter.options.point_options["s"] = 20
wplotter.options.ndiscr = 15
wplotter.plot_2d(wire)
3D Curve Plot
A plot of the same wire, but in 3D this time.
display.plot_3d(wire, **wplotter.options.as_dict())
Wire Plot with Matplotlib Default Options
In this example point_options is set to an empty dict. The default matplotlib are used.
display.plot_2d(wire, point_options={})
# The plot is immediately shown by default, so it is not possible to act on the plot
Wire plot with some modifications
In this example, we choose our own matplotlib Axes onto which to plot, disable the automatic display of the plot (show=False), and apply a title to the plot
f, ax = plt.subplots()
wplotter.options.point_options = {}
wplotter.plot_2d(wire, ax=ax, show=False)
ax.set_title("Wire plot")
plt.show()
Face Plot
A FacePlotter is used with the default setup with:
view = xz (this is the projection plane, not a section plane)
ndiscr = 30
plot title
f, ax = plt.subplots()
fplotter = FacePlotter(view="xz")
fplotter.options.ndiscr = 30
fplotter.plot_2d(face, ax=ax, show=False)
ax.set_title("Face plot without points (default)")
plt.show()
Face Plot with Points
We’ve set the points to be deactivate by default, but we can enable them again for individual plotters.
f, ax = plt.subplots()
fplotter2 = FacePlotter(view="xz")
fplotter2.options.ndiscr = 30
fplotter2.options.show_points = True
fplotter2.plot_2d(face, ax=ax, show=False)
ax.set_title("Face plot with points")
plt.show()
Face Plot with only Points
Only show the wire of a face
f, ax = plt.subplots()
fplotter3 = FacePlotter(view="xz")
fplotter3.options.show_wires = True
fplotter3.options.show_faces = False
fplotter3.plot_2d(face, ax=ax, show=False)
ax.set_title("Face plot its wire")
plt.show()
Make a Second Face
A second geometry is created, surrounding our original face.
p2 = PrincetonD()
p2.adjust_variable("x1", 3.5, lower_bound=3, upper_bound=5)
p2.adjust_variable("x2", 17, lower_bound=10, upper_bound=20)
p2.adjust_variable("dz", 0, lower_bound=0, upper_bound=0)
wire2 = p2.create_shape()
face2 = BluemiraFace(wire2)
Combined Face Plot
Face and face2 are plotted using the same FacePlotter. Since no plot options have been changed, the two faces will be plotted in the same way (e.g. same color).
fplotter4 = FacePlotter(view="xz")
fplotter4.options.show_points = True
fplotter4.options.face_options = {"color": "blue"}
f, ax = plt.subplots()
fplotter4.plot_2d(face, ax=ax, show=False)
fplotter4.plot_2d(face2, ax=ax, show=False)
ax.set_title("Both faces in blue")
plt.show()
print(f"fplotter2.options: {fplotter2.options}")
Combined Face Plot with Different Colours
Plot both face with different colour.
Note: if face is plotted before face2, face2 will be “covered” by face.
f, ax = plt.subplots()
fplotter4.options.face_options = {"color": "blue"}
fplotter4.plot_2d(face2, ax=ax, show=False)
fplotter4.options.face_options = {"color": "green"}
fplotter4.plot_2d(face, ax=ax, show=False)
ax.set_title("Both faces with different colors")
plt.show()
Face with Hole
A third face is create as difference between face and face2 (a BluemiraFace object has been created using wire2 as outer boundary and wire as inner boundary).
Note:
when plotting points, it can happen that markers are not centred properly as described in https://github.com/matplotlib/matplotlib/issues/11836
face3 is created with a wire deepcopy in order to be able to modify face and face2 (and thus wire and wire2) without modifying face3
f, ax = plt.subplots()
face3 = BluemiraFace([wire2.deepcopy(), wire.deepcopy()])
fplotter5 = FacePlotter(view="xz")
fplotter5.options.show_points = True
ax = fplotter5.plot_2d(face3, ax=ax, show=False)
ax.set_title("Face with hole - points enabled")
plt.show()
f, ax = plt.subplots()
fplotter5.options.face_options["color"] = "blue"
fplotter5.options.show_points = False
fplotter5.plot_2d(face3, ax=ax, show=False)
ax.set_title("Face with hole - points disabled - blue")
plt.show()
Perform Some Face Operations
Scale and move our face, if you run the above face plots again you can see they will change.
bari = face.center_of_mass
face.scale(0.5)
new_bari = face.center_of_mass
diff = bari - new_bari
v = (diff[0], diff[1], diff[2])
face.translate(v)
Wires and Faces
Create and plot a couple of Wires and then create and plot the corresponding Faces.
points = [[0, 0, 0], [1, 0, 0], [1, 0, 3], [0, 0, 3]]
wire = bluemira.geometry.tools.make_polygon(points, closed=True)
wire1 = wire.deepcopy()
wire1.translate((3, 0, 5))
wplotter2 = WirePlotter(view="xz")
ax = wplotter2.plot_2d(wire, show=False)
ax = wplotter2.plot_2d(wire1, ax=ax, show=False)
ax.set_title("Two wires")
plt.show()
Plots with Matplotlib Default Point Options
Plot the points on a boundary of a face with matplotlib defaults.
Note that, since point_options = {}, points color is automatically changed by matplotlib.
wface = BluemiraFace(wire)
w1face = BluemiraFace(wire1)
PhysicalComponent Plot
Creates a PhysicalComponent and plots it in the xz plane
Note that if no face colour is set, a colour from the default palette will be chosen by default. This will not be the same every time.
pd_phycomp = PhysicalComponent("Comp", face)
pd_phycomp.plot_options.view = "xz"
pd_phycomp.plot_options.ndiscr = 30
ax = pd_phycomp.plot_2d(show=False)
ax.set_title("test component plot")
plt.show(block=True)
this time plots only the wire and not the face.
Note that unlike the FacePlotter when show_faces = False the wire is
shown by default.
pd_phycomp = PhysicalComponent("Comp", face)
pd_phycomp.plot_options.view = "xz"
pd_phycomp.plot_options.show_faces = False
ax = pd_phycomp.plot_2d(show=False)
ax.set_title("test component plot wire of face")
plt.show(block=True)
Component Plot
Creates a Component and plots it in the xz plane using matplotlib defaults.
Here we override some defaults and make our custom set of plot options.
The custom setting of red loses out in priority to c3 comp being set specifically
to green. In latter 2 plots shows that returns to component default settings when
custom options are default or removed.
group = Component("Components")
my_group_options = group.plot_options.as_dict()
my_group_options["wire_options"] = {}
my_group_options["face_options"] = {"color": "red"}
c1 = PhysicalComponent("Comp1", face, parent=group)
c2 = PhysicalComponent("Comp2", wface, parent=group)
c3 = PhysicalComponent("Comp3", w1face, parent=group)
c3.plot_options.face_options["color"] = "green"
display.plot_2d(group, **my_group_options)
my_group_options["face_options"] = {"color": "blue"}
display.plot_2d(group, **my_group_options)
my_group_options["face_options"] = {}
display.plot_2d(group, **my_group_options)
Note that, since wire_options = {}, wire color is automatically changed by matplotlib
Component and BluemiraGeo Combined Plot
Plots a component on the same axes as a BluemiraFace.
wplotter3 = WirePlotter(view="xz")
wplotter3.options.point_options["s"] = 20
wplotter3.options.ndiscr = 15
wplotter3.options.wire_options["color"] = "red"
ax = wplotter3.plot_2d(wface.boundary[0], show=False)
fplotter6 = FacePlotter(view="xz")
fplotter6.options.show_wires = True
fplotter6.options.face_options["color"] = "green"
fplotter6.options.wire_options["color"] = "black"
ax = fplotter6.plot_2d(w1face, ax=ax, show=False)
ax = pd_phycomp.plot_2d(ax=ax, show=False)
ax.set_title("test component + BluemiraGeo plot")
plt.show(block=True)
Show the options from our combined plot
print(f"wire plotter options: {wplotter3.options}")
print(f"face plotter options: {fplotter6.options}")
print(f"component plotter options: {pd_phycomp.plot_options}")
CAD Display
BluemiraWire and BluemiraFace can be displayed as CAD using the built-in display function:
display.show_cad(face)
For what concern Components, the component function show_cad is used.
Note that if no colour is set, a colour from the default palette will be chosen by default. This will not be the same every time.
group.show_cad()
We can also change the appearance of individual components inside the group. Colours can be specified as an R-G-B tuple, string, or hex-string.
c1.display_cad_options.modify(color=(0.1, 0.2, 0.4))
c2.display_cad_options.modify(color="g")
c3.display_cad_options.modify(color="#FF3450", transparency=0.5)
group.show_cad()