sagemath/sage

improve piecewise plotting

kcrisman opened this issue · 15 comments

Until we actually totally rewrite piecewise functions (done in #14801), we should improve some things.

For concreteness, here is one thing that should work but doesn't. I'm sure there are more - add to this list, and then whatever isn't fixed in this ticket can be moved to another ticket. I just want to make sure they're listed in one place, not ten tickets.

List:

  • plotting more than one
sage: f = Piecewise([[(0,1),x^3], [(1,2),x^2]], x)
sage: plot([f,x^3],(x,0,2))

A very similar example was at this ask.sagemath.org post:

sage: f = Piecewise([[(-2,1),1],[(1,4),x]])
sage: g =  Piecewise([[(-2,1),1],[(1,4),2*x]])
sage: plot([f,g])
AttributeError: PiecewisePolynomial instance has no attribute '__float__'

Both examples work in the new piecewise (#14801):

sage: f = piecewise([[(0,1),x^3], [(1,2),x^2]], var=x)
sage: plot([f,x^3],(x,0,2))
sage: f = piecewise([[(-2,1),1],[(1,4),x]])
sage: g =  piecewise([[(-2,1),1],[(1,4),2*x]])
sage: plot([f,g], xmin=-3, xmax=5)
  • plotting a product of a piecewise with a symbolic (well, the problem is multiplying the two, but still worth putting here - see this sage-support thread)

    fixed in new piecewise

  • Maybe unify with plot_step_function, which currently is sort of its own thing?

  • In this example:

sage: zero_func(x)=0
sage: g = Piecewise([[(-1000,1),zero_func],[(1,1000),(x-1)^3]],x)
sage: G = g.plot()
sage: G.show(xmin=-5,xmax=5,ymax=100)
sage: g(1)
0
  • You can use oo (infinity) for endpoints, but then the plot code for Piecewise gets screwed up.

  • You can try putting in zero instead of defining this new zero function, but then g(1) and g(-1) etc. won't work.

  • You can try using extend_by_zero to make the zero part, but it gives the same problem.

  • You can plot without xmin and xmax, but that gives the whole function.

  • You can plot without ymax, but that gives the range further out than you want.

  • You can try plot(g), but that turns out to uncover a very strange error that may or may not be a bug.

    In new piecewise (#14801) 0 is no longer in the domain (open intervals?); and there is now support for unbounded intervals.

sage: zero_func(x)=0
sage: g = piecewise([[(-1000,1),zero_func],[(1,1000),(x-1)^3]])
sage: G = g.plot()
sage: G.show(xmin=-5,xmax=5,ymax=100)
Launched png viewer for Graphics object consisting of 1 graphics primitive
sage: g(1)
ValueError: point 1 is not in the domain

See also #1773.

Depends on #14801

CC: @wdjoyner @jasongrout @jondo @kcrisman @vbraun @slel @mkoeppe @eviatarbach @rwst

Component: graphics

Keywords: piecewise

Issue created by migration from https://trac.sagemath.org/ticket/11225

Description changed:

--- 
+++ 
@@ -1,10 +1,12 @@
-Until we actual totally rewrite piecewise functions, we should improve some things.
+Until we actually totally rewrite piecewise functions, we should improve some things.
 
 For concreteness, here is one thing that should work but doesn't. I'm sure there are more - add to this list, and then whatever isn't fixed in this ticket can be moved to another ticket.  I just want to make sure they're listed in one place, not ten tickets.
+
+List:
 * plotting more than one
 
 ```
 sage: f = Piecewise([[(0,1),x^3], [(1,2),x^2]], x)
 sage: plot([f,x^3],(x,0,2))
 ```
-
+* Maybe unify with `plot_step_function`, which currently is sort of its own thing?

Description changed:

--- 
+++ 
@@ -10,3 +10,19 @@
 sage: plot([f,x^3],(x,0,2))
 ```
 * Maybe unify with `plot_step_function`, which currently is sort of its own thing?
+* In this example:
+
+```
+sage: zero_func(x)=0
+sage: g = Piecewise([[(-1000,1),zero_func],[(1,1000),(x-1)^3]],x)
+sage: G = g.plot()
+sage: G.show(xmin=-5,xmax=5,ymax=100)
+sage: g(1)
+0
+```
+* You can use oo (infinity) for endpoints, but then the plot code for Piecewise gets screwed up.
+* You can try putting in zero instead of defining this new zero function, but then g(1) and g(-1) etc. won't work.
+* You can try using extend_by_zero to make the zero part, but it gives the same problem.
+* You can plot without xmin and xmax, but that gives the whole function.
+* You can plot without ymax, but that gives the range further out than you want.
+* You can try plot(g), but that turns out to uncover a very strange error that may or may not be a bug.

Description changed:

--- 
+++ 
@@ -9,6 +9,7 @@
 sage: f = Piecewise([[(0,1),x^3], [(1,2),x^2]], x)
 sage: plot([f,x^3],(x,0,2))
 ```
+* plotting a product of a piecewise with a symbolic (well, the problem is multiplying the two, but still worth putting here - see [this sage-support thread](http://groups.google.com/group/sage-support/browse_thread/thread/7357d08529de32dd))
 * Maybe unify with `plot_step_function`, which currently is sort of its own thing?
 * In this example:
 

Description changed:

--- 
+++ 
@@ -27,3 +27,7 @@
 * You can plot without xmin and xmax, but that gives the whole function.
 * You can plot without ymax, but that gives the range further out than you want.
 * You can try plot(g), but that turns out to uncover a very strange error that may or may not be a bug.
+
+
+See also #1773.
+
comment:5

Regarding the first item (can't plot two of them), It probably wouldn't even be that hard to fix. The problem is that setup_for_eval_on_grid wants to use fast_float but Piecewise guys don't have that, or more precisely don't have __float__.

Description changed:

--- 
+++ 
@@ -8,6 +8,14 @@
 ```
 sage: f = Piecewise([[(0,1),x^3], [(1,2),x^2]], x)
 sage: plot([f,x^3],(x,0,2))
+```
+   A very similar example was at [this ask.sagemath.org post](http://ask.sagemath.org/question/868/two-piecewise-defined-functions-in-one-plot):
+
+```
+sage: f = Piecewise([[(-2,1),1],[(1,4),x]])
+sage: g =  Piecewise([[(-2,1),1],[(1,4),2*x]])
+sage: plot([f,g])
+AttributeError: PiecewisePolynomial instance has no attribute '__float__'
 ```
 * plotting a product of a piecewise with a symbolic (well, the problem is multiplying the two, but still worth putting here - see [this sage-support thread](http://groups.google.com/group/sage-support/browse_thread/thread/7357d08529de32dd))
 * Maybe unify with `plot_step_function`, which currently is sort of its own thing?

Description changed:

--- 
+++ 
@@ -35,7 +35,7 @@
 * You can plot without xmin and xmax, but that gives the whole function.
 * You can plot without ymax, but that gives the range further out than you want.
 * You can try plot(g), but that turns out to uncover a very strange error that may or may not be a bug.
-
+* Most keywords are passed on to all component functions, but that is the wrong thing to do for legends.  See [this ask.sagemath.org question](http://ask.sagemath.org/question/925/piecewise-functions-and-legend-label).
 
 See also #1773.
 
comment:7

From DSM on this ask.sagemath.org question:

# monkeypatch legend duplication of trac #11225
def fix_piecewise(fn):
    import types
    def fixed_plot(self, *args, **kwargs): 
        from sage.plot.all import plot
        return sum([plot(f, a, b, *args, **(dict((k,v) for k,v in kwargs.items() if i == 0 or k != 'legend_label')))
                    for i, ((a,b),f) in enumerate(self.list())])
    def fn2(*args, **kwargs):
        ans = fn(*args, **kwargs)
        ans.plot = types.MethodType(fixed_plot, ans)
        return ans
    return fn2

Piecewise = fix_piecewise(Piecewise)

Nice protopatch, perhaps?

Description changed:

--- 
+++ 
@@ -35,7 +35,6 @@
 * You can plot without xmin and xmax, but that gives the whole function.
 * You can plot without ymax, but that gives the range further out than you want.
 * You can try plot(g), but that turns out to uncover a very strange error that may or may not be a bug.
-* Most keywords are passed on to all component functions, but that is the wrong thing to do for legends.  See [this ask.sagemath.org question](http://ask.sagemath.org/question/925/piecewise-functions-and-legend-label).
 
 See also #1773.
 
comment:8

I removed the last bullet point and created #12651 where I'll post a patch with dsm's fix.

Dependencies: #14801

Description changed:

--- 
+++ 
@@ -1,4 +1,4 @@
-Until we actually totally rewrite piecewise functions, we should improve some things.
+Until we actually totally rewrite piecewise functions (done in #14801), we should improve some things.
 
 For concreteness, here is one thing that should work but doesn't. I'm sure there are more - add to this list, and then whatever isn't fixed in this ticket can be moved to another ticket.  I just want to make sure they're listed in one place, not ten tickets.
 
@@ -17,7 +17,24 @@
 sage: plot([f,g])
 AttributeError: PiecewisePolynomial instance has no attribute '__float__'
 ```
+
+  Both examples work in the new `piecewise` (#14801): 
+
+```
+sage: f = piecewise([[(0,1),x^3], [(1,2),x^2]], var=x)
+sage: plot([f,x^3],(x,0,2))
+```
+
+```
+sage: f = piecewise([[(-2,1),1],[(1,4),x]])
+sage: g =  piecewise([[(-2,1),1],[(1,4),2*x]])
+sage: plot([f,g], xmin=-3, xmax=5)
+```
+
 * plotting a product of a piecewise with a symbolic (well, the problem is multiplying the two, but still worth putting here - see [this sage-support thread](http://groups.google.com/group/sage-support/browse_thread/thread/7357d08529de32dd))
+
+  fixed in new `piecewise`
+
 * Maybe unify with `plot_step_function`, which currently is sort of its own thing?
 * In this example:
 
@@ -36,5 +53,17 @@
 * You can plot without ymax, but that gives the range further out than you want.
 * You can try plot(g), but that turns out to uncover a very strange error that may or may not be a bug.
 
+  In new `piecewise` (#14801) 0 is no longer in the domain (open intervals?); and there is now support for unbounded intervals.
+
+``` 
+sage: zero_func(x)=0
+sage: g = piecewise([[(-1000,1),zero_func],[(1,1000),(x-1)^3]])
+sage: G = g.plot()
+sage: G.show(xmin=-5,xmax=5,ymax=100)
+Launched png viewer for Graphics object consisting of 1 graphics primitive
+sage: g(1)
+ValueError: point 1 is not in the domain
+```
+
 See also #1773.
 
comment:11

Updated description for new piecewise (#14801).
Didn't check the xmin/xmax etc. behavior that is mentioned in the description.

This can probably be closed when the old Piecewise (now deprecated) is removed completely.

Changed keywords from none to piecewise

It's not clear whether these things work given that #21618 is quite unresolved, so I recommend keeping it open, but I'll make a cross-link to this.