robodraw.schematic ================== .. py:module:: robodraw.schematic .. autoapi-nested-parse:: Draw 2D and pseudo-3D diagrams programmatically using matplotlib. Attributes ---------- .. autoapisummary:: robodraw.schematic._PROJECTION_DEFAULTS robodraw.schematic._COLORS_DEFAULT robodraw.schematic.get_wong_color robodraw.schematic._COLORS_SORTED robodraw.schematic.COLORING_SEED Classes ------- .. autoapisummary:: robodraw.schematic.Drawing Functions --------- .. autoapisummary:: robodraw.schematic._readable_angle robodraw.schematic.parse_projection robodraw.schematic.parse_style_preset robodraw.schematic.simple_scale robodraw.schematic.axonometric_project robodraw.schematic.coo_to_zorder robodraw.schematic.orthographic_project robodraw.schematic.orthographic_zorder robodraw.schematic.get_color robodraw.schematic.mod_sat robodraw.schematic.auto_colors robodraw.schematic.darken_color robodraw.schematic.average_color robodraw.schematic.jitter_color robodraw.schematic.set_coloring_seed robodraw.schematic.hash_to_nvalues robodraw.schematic.hash_to_color robodraw.schematic.mean robodraw.schematic.distance robodraw.schematic.get_angle robodraw.schematic.get_rotator_and_inverse robodraw.schematic.get_rotator_and_inverse_3d robodraw.schematic.shorten_line robodraw.schematic.get_control_points robodraw.schematic.convex_hull_2d robodraw.schematic.gen_points_around Module Contents --------------- .. py:data:: _PROJECTION_DEFAULTS .. py:function:: _readable_angle(angle) Normalize an angle to (-90, 90] so text reads right-way-up. :returns: * **normalized** (*float*) -- The angle in (-90, 90]. * **flipped** (*bool*) -- Whether the angle was flipped by 180 degrees. .. py:function:: parse_projection(projection) Parse a projection specification into a normalized tuple of ``(mode, arg1, arg2)``. :param projection: The projection specification. Can be: - A 3-tuple ``(mode, arg1, arg2)`` specifying the projection mode and its parameters explicitly, e.g. ``("orthographic", 20, 40)`` or ``("axonometric", 50, 12)``. - A 2-tuple ``(arg1, arg2)`` which defaults to orthographic, e.g. ``(20, 40)`` is equivalent to ``("orthographic", 20, 40)``. - A string ``"orthographic"`` or ``"axonometric"`` which uses the default parameters for that mode. :type projection: str or tuple :returns: A 3-tuple of ``(mode, arg1, arg2)``. :rtype: tuple .. py:class:: Drawing(background=(0, 0, 0, 0), drawcolor=(0.14, 0.15, 0.16, 1.0), shapecolor=(0.45, 0.5, 0.55, 1.0), projection=('orthographic', 20, 40), xscale=1, yscale=1, zscale=1, presets=None, ax=None, adjust_lims='auto', **kwargs) Draw 2D or pseudo-3D diagrams using matplotlib. This handles the 3D projection and the z-ordering of the elements, as well as named preset styles for repeated elements, and the automatic adjustment of the figure limits. It also has basic support for drawing smooth curves and shaded areas around certain elements automatically. :param background: The background color of the figure, defaults to transparent. :type background: color, optional :param drawcolor: The default color to draw lines and text in. :type drawcolor: color, optional :param shapecolor: The default color to fill shapes with. :type shapecolor: color, optional :param projection: The 3D projection mode and parameters, specified as a tuple of ``(mode, *args)``. Available modes: - ``("orthographic", azimuth, elevation)`` : Orthographic projection (camera at infinity). ``azimuth`` is the horizontal camera angle in degrees (0 means looking along +y, i.e. the y-axis extends into the page). ``elevation`` is the vertical angle above the horizontal (0 is side-on, 90 is top-down). ``("orthographic", 0, 90)`` gives an exact top-down view. - ``("axonometric", a, b)`` : Axonometric projection where ``a`` and ``b`` are the angles of the x and y axes measured counterclockwise from horizontal, in degrees. True isometric projection is ``("axonometric", 30, 150)``, which you can also specify with the string ``"isometric"``. Default is ``("orthographic", 20, 40)``. :type projection: tuple, optional :param xscale: A factor to scale the x-axis by. :type xscale: float :param yscale: A factor to scale the y-axis by. :type yscale: float :param zscale: A factor to scale the z-axis by. :type zscale: float :param presets: A dictionary of named style presets. When you add an element to the drawing, you can specify a preset name to use as default styling. :type presets: dict[str, dict], optional :param ax: The axes to draw on. If None, a new figure is created. If an external `ax` is supplied, then note that this `Drawing` instance will not automatically adjust the limits of the axes as elements are added. :type ax: matplotlib.axes.Axes :param adjust_lims: Whether to automatically adjust the axes limits as elements are added. If "auto" (the default), then this is ``True`` if ``ax`` is None, else ``False``, i.e. only adjust limits if we own the figure. :type adjust_lims: bool or "auto", optional :param kwargs: Passed to ``plt.figure`` if ``ax`` is None. .. py:attribute:: adjust_lims :value: 'auto' .. py:attribute:: drawcolor :value: (0.14, 0.15, 0.16, 1.0) .. py:attribute:: shapecolor :value: (0.45, 0.5, 0.55, 1.0) .. py:attribute:: _xmin :value: None .. py:attribute:: _xmax :value: None .. py:attribute:: _ymin :value: None .. py:attribute:: _ymax :value: None .. py:attribute:: presets .. py:attribute:: _project_xscale :value: 1 .. py:attribute:: _project_yscale :value: 1 .. py:attribute:: _project_zscale :value: 1 .. py:attribute:: _projection .. py:attribute:: _3d_xmin :value: None .. py:attribute:: _3d_xmax :value: None .. py:attribute:: _3d_ymin :value: None .. py:attribute:: _3d_ymax :value: None .. py:attribute:: _3d_zmin :value: None .. py:attribute:: _3d_zmax :value: None .. py:attribute:: _offset :value: (0, 0, 0) .. py:attribute:: _screen_offset :value: (0, 0) .. py:method:: _axis_angle(axis) Get the screen rotation angle (in degrees) of a 3D axis. .. py:method:: _2d_project(x, y) .. py:method:: _3d_project(x, y, z) .. py:method:: _coo_to_zorder(x, y, z) .. py:method:: translate(dx=0, dy=0, dz=0) Context manager to temporarily translate all draw operations, in coordinate space (i.e. before any projection and scaling). :param dx: The x offset. :type dx: float :param dy: The y offset. :type dy: float :param dz: The z offset (only relevant for 3D coordinates). :type dz: float .. rubric:: Examples >>> d = Drawing() >>> with d.translate(10, 5): ... d.circle((0, 0)) # drawn at (10, 5) .. py:method:: translate_screen(dx=0, dy=0) Context manager to temporarily translate all draw operations in 2D screen space (i.e. *after* any projection and scaling). :param dx: The x screen offset. :type dx: float :param dy: The y screen offset. :type dy: float .. rubric:: Examples >>> d = Drawing() >>> with d.translate_screen(10, 5): ... d.circle((0, 0, 0)) # 3D projected, then shifted .. py:method:: _project_coos(coos, style, zorder_delta=0.0, zorder_aggregate='mean', project=True) Possibly project sequence of coordinates and inject zorder. .. py:method:: _adjust_lims(x, y) .. py:method:: text(coo, text, preset=None, **kwargs) Place text at the specified coordinate. :param coo: The 2D or 3D coordinate of the text. If 3D, the coordinate will be projected onto the 2D plane, and a z-order will be assigned. :type coo: tuple[int, int] or tuple[int, int, int] :param text: The text to place. :type text: str :param preset: A preset style to use for the text. :type preset: str, optional :param kwargs: Specific style options passed to ``matplotlib.axes.Axes.text``. .. py:method:: text_between(cooa, coob, text, preset=None, **kwargs) Place text between two coordinates. :param cooa: The 2D or 3D coordinates of the text endpoints. If 3D, the coordinates will be projected onto the 2D plane, and a z-order will be assigned based on average z-order of the endpoints. :type cooa: tuple[int, int] or tuple[int, int, int] :param coob: The 2D or 3D coordinates of the text endpoints. If 3D, the coordinates will be projected onto the 2D plane, and a z-order will be assigned based on average z-order of the endpoints. :type coob: tuple[int, int] or tuple[int, int, int] :param text: The text to place. :type text: str :param center: The position of the text along the line, where 0.0 is the start and 1.0 is the end. Default is 0.5. :type center: float, optional :param shorten: Shorten the implicit line by this *absolute* amount at each end. If a tuple, the first value is the start shortening, the second the end shortening. :type shorten: float or tuple[float, float], optional :param preset: A preset style to use for the text. :type preset: str, optional :param kwargs: Specific style options passed to ``matplotlib.axes.Axes.text``. .. py:method:: label_ax(x, y, text, preset=None, **kwargs) Place text at the specified location, using the axis coordinates rather than 2D or 3D data coordinates. :param x: The x and y positions of the text, relative to the axis. :type x: float :param y: The x and y positions of the text, relative to the axis. :type y: float :param text: The text to place. :type text: str :param preset: A preset style to use for the text. :type preset: str, optional :param kwargs: Specific style options passed to ``matplotlib.axes.Axes.text``. .. py:method:: label_fig(x, y, text, preset=None, **kwargs) Place text at the specified location, using the figure coordinates rather than 2D or 3D data coordinates. :param x: The x and y positions of the text, relative to the figure. :type x: float :param y: The x and y positions of the text, relative to the figure. :type y: float :param text: The text to place. :type text: str :param preset: A preset style to use for the text. :type preset: str, optional :param kwargs: Specific style options passed to ``matplotlib.axes.Axes.text``. .. py:method:: _project_and_parse_style_for_marker(coo, preset=None, project=True, **kwargs) .. py:method:: _adjust_lims_for_marker(x, y, r) .. py:method:: circle(coo, preset=None, **kwargs) Draw a circle at the specified coordinate. :param coo: The 2D or 3D coordinate of the circle. If 3D, the coordinate will be projected onto the 2D plane, and a z-order will be assigned. :type coo: tuple[int, int] or tuple[int, int, int] :param preset: A preset style to use for the circle. :type preset: str, optional :param kwargs: Specific style options passed to ``matplotlib.patches.Circle``. .. py:method:: wedge(coo, theta1, theta2, preset=None, **kwargs) Draw a wedge at the specified coordinate. :param coo: The 2D or 3D coordinate of the wedge. If 3D, the coordinate will be projected onto the 2D plane, and a z-order will be assigned. :type coo: tuple[int, int] or tuple[int, int, int] :param theta1: The angle in degrees of the first edge of the wedge. :type theta1: float :param theta2: The angle in degrees of the second edge of the wedge. :type theta2: float :param preset: A preset style to use for the wedge. :type preset: str, optional :param kwargs: Specific style options passed to ``matplotlib.patches.Wedge``. .. py:method:: dot(coo, preset=None, **kwargs) Draw a small circle with no border. Alias for circle with defaults `radius=0.1` and `linewidth=0.0`. :param coo: The 2D or 3D coordinate of the dot. If 3D, the coordinate will be projected onto the 2D plane, and a z-order will be assigned. :type coo: tuple[int, int] or tuple[int, int, int] :param preset: A preset style to use for the dot. :type preset: str, optional :param kwargs: Specific style options passed to ``matplotlib.patches.Circle``. .. py:method:: regular_polygon(coo, preset=None, **kwargs) Draw a regular polygon at the specified coordinate. :param coo: The 2D or 3D coordinate of the polygon. If 3D, the coordinate will be projected onto the 2D plane, and a z-order will be assigned. :type coo: tuple[int, int] or tuple[int, int, int] :param n: The number of sides of the polygon. :type n: int :param orientation: The orientation of the polygon in radians. Default is 0.0. :type orientation: float, optional :param preset: A preset style to use for the polygon. :type preset: str, optional :param kwargs: Specific style options passed to ``matplotlib.patches.Polygon``. .. py:method:: star(coo, preset=None, **kwargs) .. py:method:: cross(coo, preset=None, **kwargs) .. py:method:: marker(coo, preset=None, **kwargs) Draw a 'marker' at the specified coordinate. This is a shorthand for creating polygons with shape specified by a single character. :param coo: The 2D or 3D coordinate of the marker. If 3D, the coordinate will be projected onto the 2D plane, and a z-order will be assigned. :type coo: tuple[int, int] or tuple[int, int, int] :param marker: The marker shape to draw. One of ``"o.v^<>sDphH8"``. :type marker: str, optional :param preset: A preset style to use for the marker. :type preset: str, optional :param kwargs: Specific style options. .. py:method:: square(coo, preset=None, **kwargs) Draw a square of 'radius' `radius` at the specified coordinate. This is a shorthand for `Drawing.marker` with marker='s'. .. py:method:: cube(coo, preset=None, **kwargs) Draw a cube at the specified coordinate, which must be 3D. :param coo: The 3D coordinate of the cube. The coordinate will be projected onto the 2D plane, and a z-order will be assigned. :type coo: tuple[int, int, int] :param preset: A preset style to use for the cube. :type preset: str, optional :param kwargs: Specific style options passed to ``matplotlib.patches.Polygon``. .. py:method:: tetrahedron(coo, preset=None, **kwargs) Draw a tetrahedron at the specified coordinate, which must be 3D. :param coo: The 3D coordinate of the tetrahedron. The coordinate will be projected onto the 2D plane, and a z-order will be assigned. :type coo: tuple[int, int, int] :param preset: A preset style to use for the tetrahedron. :type preset: str, optional :param kwargs: Specific style options passed to ``matplotlib.patches.Polygon``. .. py:method:: octahedron(coo, preset=None, **kwargs) Draw an octahedron at the specified coordinate, which must be 3D. :param coo: The 3D coordinate of the octahedron. The coordinate will be projected onto the 2D plane, and a z-order will be assigned. :type coo: tuple[int, int, int] :param preset: A preset style to use for the octahedron. :type preset: str, optional :param kwargs: Specific style options passed to ``matplotlib.patches.Polygon``. .. py:method:: dodecahedron(coo, preset=None, **kwargs) Draw a dodecahedron at the specified coordinate, which must be 3D. :param coo: The 3D coordinate of the dodecahedron. The coordinate will be projected onto the 2D plane, and a z-order will be assigned. :type coo: tuple[int, int, int] :param preset: A preset style to use for the dodecahedron. :type preset: str, optional :param kwargs: Specific style options passed to ``matplotlib.patches.Polygon``. .. py:method:: icosahedron(coo, preset=None, **kwargs) Draw an icosahedron at the specified coordinate, which must be 3D. :param coo: The 3D coordinate of the icosahedron. The coordinate will be projected onto the 2D plane, and a z-order will be assigned. :type coo: tuple[int, int, int] :param preset: A preset style to use for the icosahedron. :type preset: str, optional :param kwargs: Specific style options passed to ``matplotlib.patches.Polygon``. .. py:method:: line(cooa, coob, preset=None, **kwargs) Draw a line between two coordinates. :param cooa: The 2D or 3D coordinates of the line endpoints. If 3D, the coordinates will be projected onto the 2D plane, and a z-order will be assigned based on average z-order of the endpoints. :type cooa: tuple[int, int] or tuple[int, int, int] :param coob: The 2D or 3D coordinates of the line endpoints. If 3D, the coordinates will be projected onto the 2D plane, and a z-order will be assigned based on average z-order of the endpoints. :type coob: tuple[int, int] or tuple[int, int, int] :param shorten: Shorten the line by this *absolute* amount at each end. If a tuple, the first value is the start shortening, the second the end shortening. :type shorten: float or tuple[float, float], optional :param stretch: Stretch the line by this *relative* factor. 1.0 is no stretch, 0.5 is half length, 2.0 is double length. Default is 1.0. :type stretch: float :param arrowhead: Draw an arrowhead at the end of the line. Default is False. If a dict, it is passed as keyword arguments to the arrowhead method. :type arrowhead: bool or dict, optional :param text_between: Add text along the line. :type text_between: str, optional :param preset: A preset style to use for the line. :type preset: str, optional :param kwargs: Specific style options passed to ``matplotlib.lines.Line2D``. .. seealso:: :py:obj:`Drawing.arrowhead`, :py:obj:`Drawing.curve` .. py:method:: line_offset(cooa, coob, offset, midlength=0.5, relative=True, preset=None, **kwargs) Draw a line between two coordinates, but curving out by a given offset perpendicular to the line. :param cooa: The 2D or 3D coordinates of the line endpoints. If 3D, the coordinates will be projected onto the 2D plane, and a z-order will be assigned based on average z-order of the endpoints. :type cooa: tuple[int, int] or tuple[int, int, int] :param coob: The 2D or 3D coordinates of the line endpoints. If 3D, the coordinates will be projected onto the 2D plane, and a z-order will be assigned based on average z-order of the endpoints. :type coob: tuple[int, int] or tuple[int, int, int] :param offset: The offset of the curve from the line, as a fraction of the total line length. This is always processed in the 2D projected plane. :type offset: float :param midlength: The length of the middle straight section, as a fraction of the total line length. Default is 0.5. :type midlength: float :param arrowhead: Draw an arrowhead at the end of the line. Default is False. If a dict, it is passed as keyword arguments to the arrowhead method. :type arrowhead: bool or dict, optional :param text_between: Add text along the line. :type text_between: str, optional :param relative: If ``True`` (the default), then ``offset`` is taken as a fraction of the line length, else in absolute units. :type relative: bool, optional :param preset: A preset style to use for the line. :type preset: str, optional :param kwargs: Specific style options passed to ``curve``. .. py:method:: zigzag(cooa, coob, preset=None, **kwargs) Draw a zig-zagging line between two coordinates. :param cooa: The coordinates of the start and end of the line. If 3D, the coordinates will be projected onto the 2D plane, and a z-order will be assigned based on average z-order of the endpoints. :type cooa: tuple[int, int] or tuple[int, int, int] :param coob: The coordinates of the start and end of the line. If 3D, the coordinates will be projected onto the 2D plane, and a z-order will be assigned based on average z-order of the endpoints. :type coob: tuple[int, int] or tuple[int, int, int] :param width: The width of the zig-zagging. Default is to aim for 8 zig-zags. :type width: float, optional :param extend: Only start zig-zagging after this distance from the end-points. :type extend: float, optional :param density: The density of the zig-zags, where 1.0 is the default density resulting in approximately 8 zig-zags along the line. :type density: float, optional :param shorten: Shorten the zigzag by this *absolute* amount at each end. If a tuple, the first value is the start shortening, the second the end shortening. :type shorten: float or tuple[float, float], optional :param preset: A preset style to use for the line. :type preset: str, optional :param kwargs: Specific style options passed to ``Drawing.curve``. .. py:method:: arrowhead(cooa, coob, preset=None, **kwargs) Draw just a arrowhead on the line between ``cooa`` and ``coob``. :param cooa: The coordinates of the start and end of the line. If 3D, the coordinates will be projected onto the 2D plane, and a z-order will be assigned based on average z-order of the endpoints. :type cooa: tuple[int, int] or tuple[int, int, int] :param coob: The coordinates of the start and end of the line. If 3D, the coordinates will be projected onto the 2D plane, and a z-order will be assigned based on average z-order of the endpoints. :type coob: tuple[int, int] or tuple[int, int, int] :param reverse: Reverse the direction by switching ``cooa`` and ``coob``. If ``"both"``, draw an arrowhead in both directions. Default is False. :type reverse: bool or "both", optional :param center: The position of the arrowhead along the line, where 0 is the start and 1 is the end. Default is 0.5. :type center: float, optional :param width: The width of the arrowhead. Default is 0.05. :type width: float, optional :param length: The length of the arrowhead. Default is 0.1. :type length: float, optional :param relative: If True, the the `width` and `length` parameters are scaled as `total_line_length ** relative`. :type relative: bool or float, optional :param preset: A preset style to use for the arrowhead, including the above options. :type preset: str, optional :param kwargs: Specific style options passed to ``matplotlib.lines.Line2D``. .. py:method:: curve(coos, preset=None, **kwargs) Draw a smooth line through the given coordinates. :param coos: The 2D or 3D coordinates of the line. If 3D, the coordinates will be projected onto the 2D plane, and a z-order will be assigned based on average z-order of the endpoints. :type coos: Sequence[tuple[int, int]] or Sequence[tuple[int, int, int]] :param smoothing: The amount of smoothing to apply to the curve. 0.0 is no smoothing, 1.0 is maximum smoothing. Default is 0.5. :type smoothing: float, optional :param shorten: Shorten the line by this *absolute* amount at each end. If a tuple, the first value is the start shortening, the second the end shortening. The shortening is calculated with respect to the first and last segments of the curve. :type shorten: float or tuple[float, float], optional :param preset: A preset style to use for the curve. :type preset: str, optional :param kwargs: Specific style options passed to ``matplotlib.patches.PathPatch``. .. py:method:: shape(coos, preset=None, **kwargs) Draw a closed shape with (sharp) corners at the given coordinates. :param coos: The coordinates of the corners' of the shape. :type coos: sequence of coordinates :param preset: A preset style to use for the shape. :type preset: str, optional :param kwargs: Specific style options passed to ``matplotlib.patches.PathPatch``. .. seealso:: :py:obj:`Drawing.patch` .. py:method:: rectangle(cooa, coob, preset=None, **kwargs) .. py:method:: patch(coos, preset=None, **kwargs) Draw a closed smooth patch through given coordinates. :param coos: The coordinates of the 'corners' of the patch, the outline is guaranteed to pass through these points. :type coos: sequence of coordinates :param smoothing: The smoothing factor, the higher the smoother. The default is 0.5. :type smoothing: float :param preset: A preset style to use for the patch. :type preset: str, optional :param kwargs: Specific style options passed to ``matplotlib.patches.PathPatch``. .. seealso:: :py:obj:`Drawing.shape`, :py:obj:`Drawing.curve` .. py:method:: patch_around(coos, *, preset=None, **kwargs) Draw a patch around the given coordinates, by contructing a convex hull around the points, optionally including an extra uniform or per coordinate radius. :param coos: The coordinates of the points to draw the patch around. If 3D, the coordinates will be projected onto the 2D plane, and a z-order will be assigned based on *min* z-order of the endpoints. :type coos: sequence[tuple[int, int]] or sequence[tuple[int, int, int]] :param radius: The radius of the patch around each point. If a sequence, must be the same length as ``coos``. Default is 0.0. :type radius: float or sequence[float], optional :param resolution: The number of points to use pad around each point. Default is 12. :type resolution: int, optional :param preset: A preset style to use for the patch. :type preset: str, optional :param kwargs: Specific style options passed to ``matplotlib.patches.PathPatch``. .. py:method:: bezier(coos, preset=None, **kwargs) Draw a bezier curve, explicitly supplying the sequence of coordinates and anchors like `[coo0, anchor0, anchor1, coo1, ...]`. :param coos: The coordinates of the points to draw the bezier curve around. :type coos: sequence[tuple[int, int]] or sequence[tuple[int, int, int]] :param preset: A preset style to use for the bezier curve. :type preset: str, optional :param kwargs: Specific style options passed to ``matplotlib.patches.PathPatch``. .. py:method:: cup(cooa, coob, extend=0.0, flatness=1.0, which='left', preset=None, **kwargs) Draw a cup shape between two points. .. py:method:: patch_around_circles(cooa, ra, coob, rb, padding=0.2, pinch=True, preset=None, **kwargs) Draw a smooth patch around two circles. :param cooa: The coordinates of the center of the first circle. If 3D, the coordinates will be projected onto the 2D plane, and a z-order will be assigned based on average z-order of the endpoints. :type cooa: tuple[int, int] or tuple[int, int, int] :param ra: The radius of the first circle. :type ra: int :param coob: The coordinates of the center of the second circle. If 3D, the coordinates will be projected onto the 2D plane, and a z-order will be assigned based on average z-order of the endpoints. :type coob: tuple[int, int] or tuple[int, int, int] :param rb: The radius of the second circle. :type rb: int :param padding: The amount of padding to add around the circles. Default is 0.2. :type padding: float, optional :param pinch: If or how much to pinch the patch in between the circles. Default is to match the padding. :type pinch: bool or float, optional :param preset: A preset style to use for the patch. :type preset: str, optional :param kwargs: Specific style options passed to ``matplotlib.patches.PathPatch``. .. seealso:: :py:obj:`Drawing.patch` .. py:method:: grid(color=(0, 0.7, 0.8), alpha=0.3, zorder=-100, subdivisions=(1 / 4, 2 / 4, 3 / 4), margin=0.5, overextend=0.0, ticklabels=True) .. py:method:: grid3d(color=(0, 0.7, 0.8), alpha=0.3, zorder_delta=-1000, subdivisions=(1 / 4, 2 / 4, 3 / 4), margin=0.5, ticklabels=True) .. py:method:: scale_figsize(scale=1.0) Scale this figure's size according to the plot limits, so that one unit in the drawing corresponds to `scale` inches in the figure. Note this should be called after all drawing including `.grid()` calls. .. py:method:: savefig(fname, dpi=300, bbox_inches='tight') Save this drawing to a file, using matplotlib's savefig and some nicer defaults. :param fname: The filename to save to. :type fname: str :param dpi: The DPI to use. Default is 300. :type dpi: int, optional :param bbox_inches: The bbox_inches parameter to pass to matplotlib's savefig. Default is 'tight'. :type bbox_inches: str or Bbox, optional .. py:function:: parse_style_preset(presets, preset, **kwargs) Parse a one or more style presets plus manual kwargs. :param presets: The dictionary of presets. :type presets: dict :param preset: The name of the preset(s) to use. If multiple, later presets take precedence. :type preset: str or sequence of str :param kwargs: Any additional manual keyword arguments are added to the style and override the presets. :returns: **style** :rtype: dict .. py:function:: simple_scale(i, j, xscale=1, yscale=1) .. py:function:: axonometric_project(i, j, k, a=15, b=120, xscale=1, yscale=1, zscale=1) Project the 3D location ``(i, j, k)`` onto the 2D plane, using the axonometric projection with the given angles ``a`` and ``b``. Both angles are measured counterclockwise from the horizontal (3 o'clock direction), following the standard math convention. The z-axis always points straight up. :param i: The 3D coordinates of the point to project. :type i: float :param j: The 3D coordinates of the point to project. :type j: float :param k: The 3D coordinates of the point to project. :type k: float :param a: The angles of the x and y axes respectively, measured counterclockwise from horizontal, in degrees. :type a: float :param b: The angles of the x and y axes respectively, measured counterclockwise from horizontal, in degrees. :type b: float :param xscale: The scaling factor for the x, y and z axes. If negative, the axis is flipped. :type xscale: float :param yscale: The scaling factor for the x, y and z axes. If negative, the axis is flipped. :type yscale: float :param zscale: The scaling factor for the x, y and z axes. If negative, the axis is flipped. :type zscale: float :returns: **x, y** -- The 2D coordinates of the projected point. :rtype: float .. py:function:: coo_to_zorder(i, j, k, a=15, b=120, xscale=1, yscale=1, zscale=1) Given the coordinates of a point in 3D space, return a z-order value that can be used to draw it on top of other elements in the diagram. The depth direction is the null space of the axonometric projection matrix: ``(cos(b), -cos(a), sin(b-a))``, with axis flipping from the sign of the scale factors. .. py:function:: orthographic_project(i, j, k, azimuth=20, elevation=40, xscale=1, yscale=1, zscale=1) Project the 3D location ``(i, j, k)`` onto the 2D plane using an orthographic projection (camera at infinity, no perspective distortion) with the given camera ``azimuth`` and ``elevation``. The camera convention is: - ``azimuth=0`` means looking along the +y direction, so the y-axis extends "into the page" (y=1 is behind y=0). - Increasing ``azimuth`` rotates the camera clockwise when viewed from above. - ``elevation=0`` is a horizontal (side-on) view, ``elevation=90`` is directly above. ``(0, 90)`` gives an exact top-down view with x to the right and y up. :param i: The 3D coordinates of the point to project. :type i: float :param j: The 3D coordinates of the point to project. :type j: float :param k: The 3D coordinates of the point to project. :type k: float :param azimuth: Horizontal camera angle in degrees. :type azimuth: float :param elevation: Vertical camera angle above the horizontal, in degrees. :type elevation: float :param xscale: Scaling factors for each axis. If negative, the axis is flipped. :type xscale: float :param yscale: Scaling factors for each axis. If negative, the axis is flipped. :type yscale: float :param zscale: Scaling factors for each axis. If negative, the axis is flipped. :type zscale: float :returns: **x, y** -- The 2D screen coordinates of the projected point. :rtype: float .. py:function:: orthographic_zorder(i, j, k, azimuth=20, elevation=40, xscale=1, yscale=1, zscale=1) Compute z-order (depth) for orthographic projection by projecting onto the camera view direction. Higher values are closer to the camera and should be drawn on top. .. py:data:: _COLORS_DEFAULT .. py:function:: get_color(which, alpha=None, hue_factor=0.0, sat_factor=1.0, val_factor=1.0) Get a color by name, optionally modifying its alpha, hue, saturation or value. These colorblind friendly colors were ppularized in an article by Wong (https://www.nature.com/articles/nmeth.1618) but originally come from Okabe & Ito (https://jfly.uni-koeln.de/color/). :param which: The name of the color to get. :type which: {'blue', 'orange', 'green', 'red', 'yellow', 'pink', 'bluedark'} :param alpha: The alpha channel value to set for the color. Default is 1.0. :type alpha: float, optional :param hue_factor: The amount to shift the hue of the color. Default is 0.0. :type hue_factor: float, optional :param sat_factor: The amount to scale the saturation of the color. Default is 1.0. :type sat_factor: float, optional :param val_factor: The amount to scale the value of the color. Default is 1.0. :type val_factor: float, optional :returns: **color** -- The RGBA color as a tuple of floats. :rtype: tuple[float, float, float, float] .. py:data:: get_wong_color .. py:data:: _COLORS_SORTED .. py:function:: mod_sat(c, mod=None, alpha=None) Modify the luminosity of color ``c``, optionally set the ``alpha`` channel, and return the final color as a RGBA tuple. .. py:function:: auto_colors(nc, alpha=None, default_sequence=False) Generate a nice sequence of ``nc`` colors. By default this uses an interpolation between the colorblind friendly colors of Okabe & Ito in hue sorted order, with luminosity moderated by a sine function to increase local distinguishability. :param nc: The number of colors to generate. :type nc: int :param alpha: The alpha channel value to set for all colors. Default is 1.0. :type alpha: float, optional :param default_sequence: If ``True``, take from the default sequence of 7 colors, un-sorted and un-modulated. :type default_sequence: bool, optional :returns: **colors** :rtype: list[tuple[float, float, float, float]] .. py:function:: darken_color(color, factor=2 / 3) Take ``color`` and darken it by ``factor``. .. py:function:: average_color(colors) Take a sequence of colors and return the RMS average in RGB space. .. py:function:: jitter_color(color, factor=0.05) Take ``color`` and add a random offset to each of its components. .. py:data:: COLORING_SEED :value: 8 .. py:function:: set_coloring_seed(seed) Set the seed for the random color generator. :param seed: The seed to use. :type seed: int .. py:function:: hash_to_nvalues(s, nval, seed=None) Hash the string ``s`` to ``nval`` different floats in the range [0, 1]. .. py:function:: hash_to_color(s, hmin=0.0, hmax=1.0, smin=0.3, smax=0.8, vmin=0.8, vmax=0.9) Generate a random color for a string ``s``. :param s: The string to generate a color for. :type s: str :param hmin: The minimum hue value. :type hmin: float, optional :param hmax: The maximum hue value. :type hmax: float, optional :param smin: The minimum saturation value. :type smin: float, optional :param smax: The maximum saturation value. :type smax: float, optional :param vmin: The minimum value value. :type vmin: float, optional :param vmax: The maximum value value. :type vmax: float, optional :returns: **color** -- A tuple of floats in the range [0, 1] representing the RGB color. :rtype: tuple .. py:function:: mean(xs) Get the mean of a list of numbers. .. py:function:: distance(pa, pb) Get the distance between two points, in arbtirary dimensions. .. py:function:: get_angle(pa, pb) Get the angle between the line from p1 to p2 and the x-axis. .. py:function:: get_rotator_and_inverse(pa, pb) Get a rotation matrix that rotates points by theta radians about the origin and then translates them by offset. .. py:function:: get_rotator_and_inverse_3d(pa, pb) Get forward and inverse functions that translate ``pa`` to the origin and rotate so that ``pb`` lies along the positive x-axis. .. py:function:: shorten_line(pa, pb, amount) .. py:function:: get_control_points(pa, pb, pc, spacing=1 / 3) Get two points that can be used to construct a bezier curve that passes smoothly through the angle `pa`, `pb`, `pc`. .. py:function:: convex_hull_2d(points) Compute the convex hull of a set of 2D points using Andrew's monotone chain algorithm. :param points: The 2D points. Each item must support indexing as ``p[0]``, ``p[1]``. :type points: sequence[tuple[float, float]] :returns: Indices into ``points`` of the hull vertices, in counter-clockwise order, matching the convention of ``scipy.spatial.ConvexHull.vertices`` for 2D inputs. Collinear points along a hull edge are excluded. :rtype: list[int] .. py:function:: gen_points_around(coo, radius=1, resolution=12) Generate points around a circle.