Ticket #3806: trac_3806-2.patch

File trac_3806-2.patch, 16.5 KB (added by mhansen, 5 years ago)
  • sage/plot/plot.py

    # HG changeset patch
    # User Mike Hansen <mhansen@gmail.com>
    # Date 1218484321 25200
    # Node ID 56a0f17397ce6adcf8fbf7fc622e7acf2419cd77
    # Parent  f203f4d382fdb2511e6880fabab51397bfe4e430
    More improvements to plot.py.
    
    diff -r f203f4d382fd -r 56a0f17397ce sage/plot/plot.py
    a b  
    990990            angle --  
    991991            options -- dictionary of options 
    992992        """ 
    993         xmin = point[0] - 2*r 
    994         xmax = point[0] + 2*r 
    995         ymin = point[1] - 2*r 
    996         ymax = point[1] + 2*r 
     993        xmin = point[0] - r 
     994        xmax = point[0] + r 
     995        ymin = point[1] - r 
     996        ymax = point[1] + r 
    997997        self.__objects.append(GraphicPrimitive_Disk(point, r, angle, options)) 
    998998        self._extend_axes(xmin, xmax, ymin, ymax) 
    999999 
     
    10091009            options -- dictionary of options 
    10101010        """ 
    10111011        self.__objects.append(GraphicPrimitive_Line(xdata, ydata, options)) 
    1012         try: 
    1013             self._extend_axes(min(xdata), max(xdata), min(ydata), max(ydata)) 
    1014         except ValueError: 
    1015             pass 
     1012        self._extend_axes(*minmax_data(xdata, ydata)) 
     1013 
    10161014      
    10171015    def _matrix_plot(self, xy_data_array, xrange, yrange, options): 
    10181016        """ 
     
    10591057            options -- dictionary of options 
    10601058        """ 
    10611059        self.__objects.append(GraphicPrimitive_Point(xdata, ydata, options)) 
    1062         try: 
    1063             self._extend_axes(min(xdata), max(xdata), min(ydata), max(ydata)) 
    1064         except ValueError: 
    1065             pass 
     1060        self._extend_axes(*minmax_data(xdata, ydata)) 
    10661061             
    10671062    def _polygon(self, xdata, ydata, options): 
    10681063        """ 
     
    10761071            options -- dictionary of options 
    10771072        """ 
    10781073        self.__objects.append(GraphicPrimitive_Polygon(xdata, ydata, options)) 
    1079         try: 
    1080             self._extend_axes(min(xdata), max(xdata), min(ydata), max(ydata)) 
    1081         except ValueError: 
    1082             pass 
     1074        self._extend_axes(*minmax_data(xdata, ydata))         
    10831075 
    10841076    def _text(self, string, point, options): 
    10851077        """ 
     
    16831675        p.set_facecolor(c) 
    16841676        subplot.add_patch(p) 
    16851677 
     1678 
    16861679#TODO: make bar_chart more general 
    16871680class GraphicPrimitive_BarChart(GraphicPrimitive): 
    16881681    """ 
     
    26342627        ymin = float(minpoint[1]) 
    26352628        xmax = float(maxpoint[0]) 
    26362629        ymax = float(maxpoint[1]) 
    2637         return self._from_xdata_ydata(xmin, ymin, xmax, ymax, options=options) 
     2630 
     2631        g = Graphics(xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax) 
     2632        g._arrow(xmin, ymin, xmax, ymax, options=options) 
     2633        return g 
    26382634 
    26392635    def _reset(self): 
    26402636        self.options={'width':0.02,'rgbcolor':(0, 0, 1)} 
     
    26482644            type arrow? for help and examples 
    26492645        """ 
    26502646        return "type arrow? for help and examples" 
    2651  
    2652     def _from_xdata_ydata(self, xmin, ymin, xmax, ymax, options): 
    2653         g = Graphics(xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax) 
    2654         g._arrow(xmin, ymin, xmax, ymax, options=options) 
    2655         return g 
    26562647 
    26572648#an unique arrow instance 
    26582649arrow = ArrowFactory() 
     
    26912682        yrange = (min(datalist), max(datalist)) 
    26922683            #bardata.append([ind, pnts, xrange, yrange]) 
    26932684            #cnt += 1 
    2694         return self._from_xdata_ydata(ind, datalist, xrange, yrange, options=options) 
    2695  
    2696     def _reset(self): 
    2697         self.options={'width':0.5,'rgbcolor':(0, 0, 1)} 
    2698      
    2699     def __repr__(self): 
    2700         """ 
    2701         Returns a string representation of this BarChartFactory object. 
    2702  
    2703         TESTS: 
    2704             sage: bar_chart 
    2705             type bar_chart? for help and examples 
    2706         """ 
    2707         return "type bar_chart? for help and examples" 
    2708  
    2709     def _from_xdata_ydata(self, ind, datalist, xrange, yrange, options): 
     2685 
    27102686        g = Graphics() 
    27112687        #TODO: improve below for multiple data sets! 
    27122688        #cnt = 1 
     
    27182694        g._bar_chart(ind, datalist, xrange, yrange, options=options) 
    27192695        return g 
    27202696 
     2697    def _reset(self): 
     2698        self.options={'width':0.5,'rgbcolor':(0, 0, 1)} 
     2699     
     2700    def __repr__(self): 
     2701        """ 
     2702        Returns a string representation of this BarChartFactory object. 
     2703 
     2704        TESTS: 
     2705            sage: bar_chart 
     2706            type bar_chart? for help and examples 
     2707        """ 
     2708        return "type bar_chart? for help and examples" 
     2709 
    27212710#an unique bar_chart instance 
    27222711bar_chart = BarChartFactory() 
    27232712 
     
    27582747        ...       ocur = (rnext-r)-ocur 
    27592748        ... 
    27602749        sage: g.show(xmin=-(paths+1)^2, xmax=(paths+1)^2, ymin=-(paths+1)^2, ymax=(paths+1)^2, figsize=[6,6]) 
     2750 
     2751    TESTS: 
     2752    We test to make sure the x/y min/max data is set correctly. 
     2753        sage: p = circle((3, 3), 1) 
     2754        sage: p.xmin() 
     2755        2.0 
     2756        sage: p.ymin() 
     2757        2.0 
    27612758    """ 
    27622759    def __call__(self, point, radius, **kwds): 
    27632760        options = dict(self.options) 
    27642761        for k, v in kwds.iteritems(): 
    27652762            options[k] = v 
    2766         return self._from_xdata_ydata((float(point[0]), float(point[1])), 
    2767                                        float(radius), options=options) 
     2763 
     2764        r = float(radius) 
     2765        point = (float(point[0]), float(point[1])) 
     2766        g = Graphics(xmin=point[0]-r, xmax=point[0]+r, ymin=point[1]-r, ymax=point[1]+r) 
     2767        g._circle(point[0], point[1], r, options) 
     2768        return g 
    27682769 
    27692770    def _reset(self): 
    27702771        self.options={'alpha':1,'fill':False,'thickness':1,'rgbcolor':(0, 0, 1)} 
     
    27782779            type circle? for help and examples 
    27792780        """ 
    27802781        return "type circle? for help and examples" 
    2781  
    2782     def _from_xdata_ydata(self, point, r, options): 
    2783         g = Graphics() 
    2784         g._circle(float(point[0]), float(point[1]), float(r), options) 
    2785         return g 
    27862782 
    27872783 
    27882784#an unique circle instance 
     
    28512847        sage: contour_plot(f, (-2, 2), (-2, 2), contours=(0.1, 1.0, 1.2, 1.4), cmap='hsv') 
    28522848        sage: contour_plot(f, (-2, 2), (-2, 2), contours=(1.0,), fill=False) 
    28532849 
     2850 
     2851    TESTS: 
     2852    We test to make sure that the x/y min/max data is set correctly. 
     2853        sage: p = contour_plot(f, (3, 6), (3, 6)) 
     2854        sage: p.xmin() 
     2855        3.0 
     2856        sage: p.ymin() 
     2857        3.0 
    28542858    """ 
    28552859    def __call__(self, f, xrange, yrange, **kwds): 
    28562860        options = dict(self.options) 
     
    28622866        xy_data_array = [[g(x, y) for x in \ 
    28632867                          sage.misc.misc.xsrange(xrange[0], xrange[1], xstep)] 
    28642868                          for y in sage.misc.misc.xsrange(yrange[0], yrange[1], ystep)] 
    2865         return self._from_xdata_ydata(xy_data_array, xrange, yrange, options=options) 
     2869 
     2870        g = Graphics(xmin=float(xrange[0]), xmax=float(xrange[1]), ymin=float(yrange[0]), ymax=float(yrange[1])) 
     2871        g._contour_plot(xy_data_array, xrange, yrange, options) 
     2872        return g         
    28662873 
    28672874    def _reset(self): 
    28682875        self.options={'plot_points':25, 'fill':True, 'cmap':'gray', 'contours':None} 
     
    28762883            type contour_plot? for help and examples 
    28772884        """ 
    28782885        return "type contour_plot? for help and examples" 
    2879           
    2880     def _from_xdata_ydata(self, xy_data_array, xrange, yrange, options): 
    2881         g = Graphics() 
    2882         g._contour_plot(xy_data_array, xrange, yrange, options) 
    2883         return g 
     2886 
    28842887 
    28852888#unique contour_plot instance 
    28862889contour_plot = ContourPlotFactory()  
     
    30743077            100.0 
    30753078            sage: l.xmax() 
    30763079            120.0 
    3077  
    30783080        """ 
    30793081        if coerce: 
    30803082            xdata, ydata = self._coerce(xdata, ydata) 
    30813083         
    3082         g = Graphics(xmin=min(xdata), xmax=max(xdata), ymin=min(ydata), ymax=max(ydata)) 
     3084        g = Graphics(**minmax_data(xdata, ydata, dict=True)) 
    30833085        g._Graphics__objects.append(GraphicPrimitive_Line(xdata, ydata, options)) 
    30843086        return g 
    30853087 
     
    31143116 
    31153117    Another random plot, but over GF(389): 
    31163118        sage: matrix_plot(random_matrix(GF(389), 10), cmap='Oranges') 
     3119 
    31173120    """ 
    31183121    def __call__(self, mat, **kwds): 
    31193122        from sage.matrix.all import is_Matrix  
     
    31303133            xrange = (0, len(mat[0])) 
    31313134            yrange = (0, len(mat)) 
    31323135        xy_data_array = [array(r, dtype=float) for r in mat] 
    3133         return self._from_xdata_ydata(xy_data_array, xrange, yrange, options=options) 
     3136 
     3137        g = Graphics() 
     3138        g._matrix_plot(xy_data_array, xrange, yrange, options) 
     3139        return g 
    31343140 
    31353141    def _reset(self): 
    31363142        self.options={'cmap':'gray'} 
     
    31453151        """ 
    31463152        return "type matrix_plot? for help and examples" 
    31473153 
    3148     def _from_xdata_ydata(self, xy_data_array, xrange, yrange, options): 
    3149         g = Graphics() 
    3150         g._matrix_plot(xy_data_array, xrange, yrange, options) 
    3151         return g 
    31523154 
    31533155#unique matrix_plot instance 
    31543156matrix_plot = MatrixPlotFactory() 
     
    31803182 
    31813183 
    31823184    TESTS: 
    3183         sage: plot_vector_field((lambda x,y: .01*x,x+y), (-10,10), (-10,10)) 
     3185        sage: p = plot_vector_field((lambda x,y: .01*x,x+y), (10,20), (10,20)) 
     3186        sage: p.xmin() 
     3187        10.0 
     3188        sage: p.ymin() 
     3189        10.0 
    31843190 
    31853191    """ 
    31863192    def __call__(self, (f, g), xrange, yrange, **kwds): 
     
    31903196        z, xstep, ystep, xrange, yrange = setup_for_eval_on_grid([f,g], xrange, yrange, options['plot_points']) 
    31913197        f,g = z 
    31923198         
    3193         Lpx,Lpy,Lcx,Lcy = [],[],[],[] 
     3199        xpos_array, ypos_array, xvec_array, yvec_array = [],[],[],[] 
    31943200        for x in sage.misc.misc.xsrange(xrange[0], xrange[1], xstep): 
    31953201            for y in sage.misc.misc.xsrange(yrange[0], yrange[1], ystep): 
    3196                 Lpx.append(x) 
    3197                 Lpy.append(y) 
    3198                 Lcx.append(f(x,y)) 
    3199                 Lcy.append(g(x,y)) 
    3200         return self._from_xdata_ydata(Lpx, Lpy, Lcx, Lcy, xrange, yrange, options=options) 
    3201  
    3202     def _reset(self): 
    3203         self.options={'plot_points':20, 'cmap':'gray'} 
    3204      
    3205     def _repr_(self): 
    3206         return "type plot_vector_field? for help and examples" 
    3207  
    3208     def _from_xdata_ydata(self, xpos_array, ypos_array, xvec_array, yvec_array, xrange, yrange, options): 
     3202                xpos_array.append(x) 
     3203                ypos_array.append(y) 
     3204                xvec_array.append(f(x,y)) 
     3205                yvec_array.append(g(x,y)) 
     3206 
    32093207        import numpy 
    32103208        xvec_array = numpy.array(xvec_array, dtype=float) 
    32113209        yvec_array = numpy.array(yvec_array, dtype=float) 
    3212         g = Graphics() 
     3210        g = Graphics(xmin=xrange[0], xmax=xrange[1], ymin=yrange[0],  ymax=yrange[1]) 
    32133211        g._plot_field(xpos_array, ypos_array, xvec_array, yvec_array, xrange, yrange, options) 
    32143212        return g 
     3213 
     3214    def _reset(self): 
     3215        self.options={'plot_points':20, 'cmap':'gray'} 
     3216     
     3217    def _repr_(self): 
     3218        return "type plot_vector_field? for help and examples" 
    32153219 
    32163220#unique plot_vector_field instance 
    32173221plot_vector_field = PlotFieldFactory()  
     
    32343238        sage: P  = tl+tr+bl+br 
    32353239        sage: P.show(figsize=(4,4),xmin=-2,xmax=2,ymin=-2,ymax=2) 
    32363240 
     3241    TESTS: 
     3242    Check to make sure that the x/y min/max data is correctly set. 
     3243        sage: d = disk((5,5), 1, (pi/2, pi), rgbcolor=(0,0,0)) 
     3244        sage: d.xmin() 
     3245        4.0 
     3246        sage: d.ymin() 
     3247        4.0 
     3248        sage: d.xmax() 
     3249        6.0 
    32373250    """ 
    32383251    def __call__(self, point, radius, angle, **kwds): 
    32393252        options = dict(self.options) 
    32403253        for k, v in kwds.iteritems(): 
    32413254            options[k] = v 
    3242         return self._from_xdata_ydata((float(point[0]), float(point[1])),float(radius),  
    3243                     (float(angle[0]), float(angle[1])), options=options) 
     3255     
     3256        r = float(radius) 
     3257        point = (float(point[0]), float(point[1])) 
     3258        angle = (float(angle[0]), float(angle[1])) 
     3259 
     3260        xmin = point[0] - r 
     3261        xmax = point[0] + r 
     3262        ymin = point[1] - r 
     3263        ymax = point[1] + r 
     3264        g = Graphics(xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax) 
     3265        g._disk(point, r, angle, options) 
     3266        return g 
    32443267 
    32453268    def _reset(self): 
    32463269        self.options={'alpha':1,'fill':True,'rgbcolor':(0,0,1),'thickness':0} 
     
    32543277            type disk? for help and examples 
    32553278        """ 
    32563279        return "type disk? for help and examples" 
    3257  
    3258     def _from_xdata_ydata(self, point, r, angle, options): 
    3259         g = Graphics() 
    3260         g._disk(point, r, angle, options) 
    3261         return g 
    32623280 
    32633281#an unique disk instance 
    32643282disk = DiskFactory() 
     
    32773295        Here are some random larger red points, given as a list of tuples 
    32783296        sage: point(((0.5, 0.5), (1, 2), (0.5, 0.9), (-1, -1)), rgbcolor=hue(1), pointsize=30) 
    32793297 
     3298    TESTS: 
     3299    We check to make sure that the x/y min/max data is set correctly. 
     3300        sage: p = point((3, 3), rgbcolor=hue(0.75)) 
     3301        sage: p.xmin() 
     3302        3.0 
     3303        sage: p.ymin() 
     3304        3.0 
     3305 
    32803306    """ 
    32813307    def _reset(self): 
    32823308        self.options = {'alpha':1,'pointsize':10,'faceted':False,'rgbcolor':(0,0,1)} 
     
    32943320    def _from_xdata_ydata(self, xdata, ydata, coerce, options): 
    32953321        if coerce: 
    32963322            xdata, ydata = self._coerce(xdata, ydata) 
    3297         g = Graphics(xmin=min(xdata), xmax=max(xdata), ymin=min(ydata), ymax=max(ydata)) 
     3323        g = Graphics(**minmax_data(xdata, ydata, dict=True)) 
    32983324        g._Graphics__objects.append(GraphicPrimitive_Point(xdata, ydata, options)) 
    32993325        return g 
    33003326 
     
    33603386        sage: L = [[sin(pi*i/100)+sin(pi*i/50),-(1+cos(pi*i/100)+cos(pi*i/50))] for i in range(-100,100)] 
    33613387        sage: polygon(L, rgbcolor=(1,1/4,1/2)) 
    33623388 
     3389    TESTS: 
     3390    We check to make sure that the x/y min/max data is set correctly. 
     3391        sage: p = polygon([[1,2], [5,6], [5,0]], rgbcolor=(1,0,1)) 
     3392        sage: p.ymin() 
     3393        0.0 
     3394        sage: p.xmin() 
     3395        1.0 
     3396 
     3397 
    33633398    AUTHORS: 
    33643399        -- David Joyner (2006-04-14): the long list of examples above. 
    33653400     
     
    33803415    def _from_xdata_ydata(self, xdata, ydata, coerce, options): 
    33813416        if coerce: 
    33823417            xdata, ydata = self._coerce(xdata, ydata) 
    3383         g = Graphics() 
     3418        g = Graphics(**minmax_data(xdata, ydata, dict=True)) 
    33843419        g._Graphics__objects.append(GraphicPrimitive_Polygon(xdata, ydata, options)) 
    3385         try: 
    3386             g._extend_axes(min(xdata), max(xdata), min(ydata), max(ydata)) 
    3387         except ValueError: 
    3388             pass 
    33893420        return g  
    33903421 
    33913422# unique polygon instance  
     
    36483679                 
    36493680            try: 
    36503681                data[i] = (float(xi), float(f(xi))) 
    3651             except (ZeroDivisionError, TypeError, ValueError,OverflowError), msg: 
     3682            except (ZeroDivisionError, TypeError, ValueError, OverflowError), msg: 
    36523683                sage.misc.misc.verbose("%s\nUnable to compute f(%s)"%(msg, x),1) 
    36533684                exceptions += 1 
    36543685                exception_indices.append(i) 
     3686 
     3687            if str(data[i][1]) in ['nan', 'NaN']: 
     3688                sage.misc.misc.verbose("%s\nUnable to compute f(%s)"%(msg, x),1) 
     3689                exceptions += 1 
     3690                exception_indices.append(i) 
     3691 
    36553692        data = [data[i] for i in range(len(data)) if i not in exception_indices] 
    36563693             
    36573694        # adaptive refinement 
     
    38363873 
    38373874    This gives all the random points joined in a purple line: 
    38383875        sage: list_plot(r, plotjoined=True, rgbcolor=(1,0,1)) 
     3876 
     3877    TESTS: 
     3878    We check to see that the x/y min/max data are set correctly. 
     3879        sage: p = list_plot([(100,100), (120, 120)]) 
     3880        sage: p.xmin() 
     3881        100.0 
     3882        sage: p.ymin() 
     3883        100.0 
     3884 
    38393885    """ 
    38403886    if not isinstance(data[0], (list, tuple)): 
    38413887        data = zip(range(len(data)),data) 
     
    44604506                g.append(fast_float(f, str(xvar), str(yvar))) 
    44614507             
    44624508    return g, xstep, ystep, xrange, yrange 
     4509 
     4510 
     4511def minmax_data(xdata, ydata, dict=False): 
     4512    """ 
     4513    Returns the minimums and maximums of xdata and ydata. 
     4514 
     4515    If dict is False, then minmax_data returns the tuple 
     4516    (xmin, xmax, ymin, ymax); otherwise, it returns a dictionary 
     4517    whose keys are 'xmin', 'xmax', 'ymin', and 'ymax' and whose 
     4518    values are the corresponding values. 
     4519 
     4520    EXAMPLES: 
     4521         sage: from sage.plot.plot import minmax_data 
     4522         sage: minmax_data([], []) 
     4523         (-1, 1, -1, 1) 
     4524         sage: minmax_data([-1, 2], [4, -3]) 
     4525         (-1, 2, -3, 4) 
     4526         sage: d = minmax_data([-1, 2], [4, -3], dict=True) 
     4527         sage: list(sorted(d.items())) 
     4528         [('xmax', 2), ('xmin', -1), ('ymax', 4), ('ymin', -3)] 
     4529 
     4530    """ 
     4531    xmin = min(xdata) if len(xdata) > 0 else -1 
     4532    xmax = max(xdata) if len(xdata) > 0 else 1 
     4533    ymin = min(ydata) if len(ydata) > 0 else -1 
     4534    ymax = max(ydata) if len(ydata) > 0 else 1 
     4535    if dict: 
     4536        return {'xmin':xmin, 'xmax':xmax, 
     4537                'ymin':ymin, 'ymax':ymax} 
     4538    else: 
     4539        return xmin, xmax, ymin, ymax