Ask Your Question

Revision history [back]

Setting zmin and zmax to get a chosen z-range

Missing functionality

Inspecting the plot method of hyperplanes arrangement reveals this is not implemented in Sage yet.

Searching Ask Sage and sage-support, we find that many 3d plotting functions similarly lack the ability to limit the z-range. Providing this missing functionality is now tracked at

Workaround

Some of the questions on this theme were answered with a suggestion to use implicit_plot3d. For hyperplanes, this works very well.

We can therefore mimic the plot method of hyperplane arrangements and cook up a function which, if given only an x-range and a y-range, will simply call the plot method (which adapts the z-range to the full range of z values corresponding to the x-range and y-range), but if additionally given a z-range, will use implicit plots to limit the z-range.

Here is such a function:

def ha_plot(A, ranges, **opt):
    r"""
    Return a plot of this hyperplane arrangement.

    INPUT:

    - ``A`` -- a hyperplane arrangement

    - ``ranges`` -- a list consisting of an x-range, a y-range,
      and optionally a z-range
    """
    from colorsys import hsv_to_rgb
    if len(ranges) == 2:
        return A.plot(ranges=ranges, **opt)
    elif len(ranges) != 3:
        raise ValueError("ranges should consist in two or three tuples")
    hh = [h.coefficients() for h in A.hyperplanes()]
    N = len(hh)
    HSV_tuples = [(i*1.0/N, 0.8, 0.9) for i in range(N)]
    cols = [hsv_to_rgb(*x) for x in HSV_tuples]
    ff = lambda a, b, c, d: lambda x, y, z: d + a*x + b*y + c*z
    ip = lambda f, col: implicit_plot3d(f, *ranges, color=col, **opt)
    hp = lambda a, b, c, d, col: ip(ff(a, b, c, d), col)
    return sum(hp(a, b, c, d, col) for (d, a, b, c), col in zip(hh, cols))

Usage is as follows.

One can provide only an x-range and a y-range:

sage: ha_plot(A, [(-1, 1), (-1, 1)]).show(aspect_ratio=(1, 1, 0.25))

and get the exact same picture as in the question.

Or one can additionally provide a z-range:

sage: ha_plot(A, [(-1, 1), (-1, 1), (-1, 1)]).show(aspect_ratio=1)

Hyperplane arrangement with chosen z-range

Optional extra arguments are passed to implicit_plot3d.

This for instance allows to set the opacity:

sage: ha_plot(A, [(-1, 1), (-1, 1), (-1, 1)], opacity=0.5).show(aspect_ratio=1)

The function could be improved to accept a choice of colours. Currently it uses the same default as the plot method of hyperplane arrangements.

Setting zmin and zmax to get a chosen z-range

Missing functionality

Inspecting the plot method of hyperplanes arrangement reveals this is not implemented in Sage yet.

Searching Ask Sage and sage-support, we find that many 3d plotting functions similarly lack the ability to limit the z-range. Providing this missing functionality is now tracked at

Workaround

Some of the questions on this theme were answered with a suggestion to use implicit_plot3d. For hyperplanes, this works very well.

We can therefore mimic the plot method of hyperplane arrangements and cook up a function which, if given only an x-range and a y-range, will simply call the plot method (which adapts the z-range to the full range of z values corresponding to the x-range and y-range), but if additionally given a z-range, will use implicit plots to limit the z-range.

Here is such a function:

def ha_plot(A, ranges, **opt):
    r"""
    Return a plot of this hyperplane arrangement.

    INPUT:

    - ``A`` -- a hyperplane arrangement

    - ``ranges`` -- a list consisting of an x-range, a y-range,
      and optionally a z-range
    """
    from colorsys import hsv_to_rgb
    if len(ranges) == 2:
        return A.plot(ranges=ranges, **opt)
    elif len(ranges) != 3:
        raise ValueError("ranges should consist in two or three tuples")
    hh = [h.coefficients() for h in A.hyperplanes()]
    N = len(hh)
    HSV_tuples = [(i*1.0/N, 0.8, 0.9) for i in range(N)]
    cols = [hsv_to_rgb(*x) for x in HSV_tuples]
    ff = lambda a, b, c, d: lambda x, y, z: d + a*x + b*y + c*z
    ip = lambda f, col: implicit_plot3d(f, *ranges, color=col, **opt)
    hp = lambda a, b, c, d, col: ip(ff(a, b, c, d), col)
    return sum(hp(a, b, c, d, col) for (d, a, b, c), col in zip(hh, cols))

Usage is as follows.

One can provide only an x-range and a y-range:

sage: ha_plot(A, [(-1, 1), (-1, 1)]).show(aspect_ratio=(1, 1, 0.25))

and get the exact same picture as in the question.

Or one can additionally provide a z-range:

sage: ha_plot(A, [(-1, 1), (-1, 1), (-1, 1)]).show(aspect_ratio=1)

Hyperplane arrangement with chosen z-range

Optional extra arguments are passed to implicit_plot3d.

This for instance allows to set the opacity:

sage: ha_plot(A, [(-1, 1), (-1, 1), (-1, 1)], opacity=0.5).show(aspect_ratio=1)

The function could be improved to accept a choice of colours. Currently it uses the same default as the plot method of hyperplane arrangements.

Solution using the add_condition method of 3D plots

Added on 2021-08-01, inspired by @FrédéricC's answer to:

One could alternatively use the add_condition method of 3D graphics objects.

One needs to pay attention to the fact that the plot of a hyperplane arrangement is in fact the sum of the graphs of the individual hyperplanes.

The add_condition method applies to each of those, rather than to their sum.

Define the hyperplane arrangement and name its plot:

H3.<x, y, z> = HyperplaneArrangements(QQ)
A = H3([(1, 2, 1), 0],
       [(-4, -3, -2), 0],
       [(3, 3, -2), 0],
       [(1, -4, 3), 0],
       [(-2, 2, 1), 0])
a = A.plot(ranges=[(-1, 1), (-1, 1)], aspect_ratio=(1, 1, 0.25))

Define bounds and sum the reworked plots of individual arrangements truncated using add_condition:

z_bounds = lambda x, y, z: -1 < z < 1
aa = sum(h.add_condition(z_bounds) for h in a.all)

Show the result:

aa

Hyperplane arrangements plot, truncated using add_condition