From: Thomas C. <tca...@gm...> - 2015-05-15 15:11:56
|
I would advocate for calling yours something different. path.Path is really a container for a Bezier curve and is probably best left as simple as possible. There is probably an interesting discussion about right is-a and has-a relations between Path, FancyPath (don't use that name!), and FancyArrow (which I do not have a clear view of yet). Tom On Fri, May 15, 2015 at 11:04 AM Neil Girdhar <mis...@gm...> wrote: > On Fri, May 15, 2015 at 10:53 AM, Thomas Caswell <tca...@gm...> > wrote: > >> A few very quick comments (just skimmed the docstrings) >> >> We already have a mpl.path.Path class, please don't shadow that. >> > > I read the Path class and based mine on that. The problem is that I want > to be able to place nodes along the path (like labels) and so I need to ask > it questions. Maybe we should just extend the existing Path class? Or > else we should call my Path something different? > > >> Is your `Path` going to be an `Artist` that is responsible for drawing >> it's self or does in serve a role like the existing `Path` in that it is >> used by other artists as part of their `draw`? >> >> This feels very similar to the `FancyArrow` (with classes being passed in >> to control how the arrow is styled), would this make sense as an extension >> to that code? This does seem more general, maybe it makes sense to start >> from scratch and implement `FancyArrow` in terms of this code. >> > > Yes! Didn't know about that. I think modifying and extending that code > might be a good way forward. > > > >> >> Tom >> >> On Fri, May 15, 2015 at 10:40 AM Neil Girdhar <mis...@gm...> >> wrote: >> >>> I have a draft proposal of the long term goal for what an interface >>> could look like for drawing arrows between coordinates or nodes. I based >>> the design on the tikz manual (http://pgf.sourceforge.net/pgf_CVS.pdf), >>> so it might help to flip through that to get an idea for the basis of this >>> design. I tried to separate the creating of Path objects with the drawing >>> of paths since it's often really useful when compositing layouts to be able >>> to do math with with the positions of things before drawing anything. For >>> example, when automatically positioning nodes. >>> >>> I'm not committed to this design; it's just an outline to get feedback. >>> >>> Best, >>> >>> Neil >>> >>> class Axes_(_AxesBase): >>> def path(self, path, draw=True, fill=False): >>> """ >>> If draw is not falsy, draws along the path using the draw >>> specification. >>> If fill is not falsy, fills the closed path using the fill >>> specification. >>> >>> Parameters >>> ---------- >>> path is a Path object or path commands with which to create one. >>> >>> draw is a draw specification: >>> either the value True, which indicates some defaults, or else >>> False, or else a dictionary with the following keys: >>> color >>> opacity >>> line_width >>> line_join >>> begin_tip is a Tip object >>> tip or end_tip is a Tip object >>> dashed is a dash specification >>> >>> a dash specification >>> either dictionary containing: >>> dash_pattern >>> an iterable of numbers specifying the length of the >>> dashes >>> and gaps in points. E.g., [2, 3, 4, 3] means on for >>> 2 >>> points, off for 3, on for 4, off for 3, i.e., >>> dash-dotted. >>> dash_phase >>> Shifts the start of the dash pattern by dash_phase >>> points. >>> or a string, one of: >>> 'solid' >>> 'dotted', 'densely dotted', 'loosely dotted' >>> 'dashed', 'densely dashed', 'loosely dashed' >>> 'dash dot', 'densely dash dot', 'loosely dash dot' >>> 'dash dot dot', 'densely dash dot dot', 'loosely dash >>> dot dot' >>> >>> fill is a fill specification: >>> TODO >>> """ >>> >>> class Path: >>> def __init__(self, path_commands): >>> """ >>> path_commands is either >>> a coordinate (representing a move to in the first position, >>> or a >>> line to in any other position) >>> MoveTo(coordinate) >>> LineTo(coordinate_or_node, draw=None) >>> CurveTo(coordinate_or_node, control_points, draw=None) >>> ClosePolygon() >>> >>> optional draw commands override the draw specification of >>> the whole >>> path within that edge. >>> >>> a coordinate is either an (x, y) pair, or a Coordinate >>> object. >>> a node is a Node object. >>> """ >>> >>> def at_position(self, fraction=0.5): >>> """ >>> Returns a coordinate fraction of the way along the line. >>> fraction can be one of 'at end', 'very near end', 'near end', >>> 'midway', 'near start', 'very near start', 'at start' >>> """ >>> >>> def node_at(node, fraction=0.5, location, ...) >>> """ >>> Sets the node's position so that it sits flush to the path. >>> >>> Parameters >>> ---------- >>> location : >>> Could be 'above', 'below', 'on', or a number, which is the >>> number >>> of points away from the path to place the node. >>> """ >>> >>> def pin_node(node, pin_distance, draw=draw_specification): >>> pass >>> >>> >>> class Coordinate: >>> @property >>> def coordinate(self): >>> return (self.x, self.y) >>> >>> def node_at(self, node, angle): >>> """ >>> Places the node so that it is in the direction angle from the >>> coordinate. E.g., >>> angle=pi/2, or angle='above' places the node so that the >>> coordinate is >>> touching the center-bottom of the node. >>> angle could be 'above', 'below', 'left', 'right', 'above left', >>> etc. >>> """ >>> >>> class Node: >>> """ >>> Available Node objects: >>> Rectangle, Circle >>> """ >>> @property >>> def center(self): >>> return (self.x, self.y) >>> >>> def node_at(self, node, angle): >>> """ >>> Places the node so that it is in the direction angle from the >>> coordinate. The node could be an arrowhead for example. >>> """ >>> >>> def convex_hulls(self): >>> """ >>> Returns a list of convex hulls. The convex hulls are used when >>> position one node or arrowhead flush with another using the >>> separating axis algorithm. >>> """ >>> >>> class Tip: >>> """ >>> Available Tip objects: >>> ButtCap (no tip, the default) >>> RectangleCap, TriangleCap, RoundCap >>> ArcBarb, Bar, Bracket, Hooks, Parenthesis, >>> StraightBarb, TeeBarb >>> Circle, Diamond, Ellipse, Kite, Arrow, >>> Rectangle, Square, Stealth, Triangle, >>> TurnedSquare >>> TipCombination (accepts multiple tips and merges them) >>> """ >>> def __init__(self, draw=None, fill=True, reversed_=False): >>> pass >>> >>> def convex_hulls(self, line_width): >>> """ >>> Returns a list of convex hulls for use with placement >>> whereby the arrow faces right starting at the origin. >>> """ >>> >>> def transmute(self, line_width): >>> """ >>> Returns a pair of lists (draw_path, fill_path). >>> """ >>> >>> @property >>> def draw_specification(self): >>> """ >>> is a draw specification, or None to use the parent line's >>> """ >>> def fill_specification(self): >>> """ >>> Is a fill specification, or True to use defaults based >>> on the parent line's draw color, or False to use an open fill. >>> """ >>> >>> ----- >>> >>> Usage: >>> >>> # draw an arrow from point to point. >>> ax.path([(x, y), (x2, y2)], draw={'tip': Arrow()}) >>> >>> # Create a path. >>> p = Path([(x, y), (x2, y2)]) >>> >>> # Create a node along the path. >>> n = p.node_at(Label("some label")) >>> >>> # Draw the path using an arrow, and the node. >>> ax.path(p, draw={'tip': Arrow()}) >>> ax.node(n) >>> >>> >>> On Wed, May 13, 2015 at 11:27 PM, Thomas Caswell <tca...@gm...> >>> wrote: >>> >>>> Sorry, I may have been being a bit dramatic >>>> >>>> In mpl.patches: Arrow, FancyArrow, YAArrow, FancyArrowPatch, >>>> ConnectionPatch + annotation related artists + some classes in axisartist >>>> which now that I look at them are not really general purpose arrow tools. >>>> I had not been counting quiver (or barbs) or sankey. >>>> >>>> Neil: Those are all great questions! Much of the arrow related code >>>> was written by Joe-Joon Lee who (by having read a good deal of his code) >>>> has a habit of writing very power but very opaque python. >>>> >>>> I believe that the line join style is controlled by `joinstyle` on the >>>> graphics context and it is up to the backends to implement that correctly. >>>> >>>> Tom >>>> >>> On Wed, May 13, 2015 at 10:58 PM Neil Girdhar <mis...@gm...> >>>> wrote: >>>> >>> Okay, I'm looking at this in more detail and there may be some design >>>>> concerns: >>>>> >>>>> The arrow placement is decided without asking the arrow any questions, >>>>> such as its bounding box. Instead, the arrow should return a bounding box >>>>> and then the line should retreat until the bounding box no longer >>>>> intersects the target node. Then the arrow should be placed. This doesn't >>>>> matter so much when you have a simple arrow like this: ---->, but it's a >>>>> big deal when you have an arrow like ----| . In this case, the sides of >>>>> the arrow risk intersecting with the target node. >>>>> >>>>> I'm not keen on implementing every arrow three times: <-, ->, <->. >>>>> This really should be handled by the code placing the arrows for many >>>>> reasons: >>>>> 1. It should also be possible to have a different arrowhead at either >>>>> end of the line. >>>>> 2. It should be possible to stack the arrows, for example having two >>>>> heads one after another (to represent two kinds of relationships). This is >>>>> another reason to be able to ask the arrowhead its length and so on. >>>>> >>>>> I don't understand the "monolithic" keyword. How can the arrow draw >>>>> the line as well when it doesn't know the line style, color and so on? >>>>> >>>>> I think I like the design of the transmute function. I'm curious: >>>>> ultimately, where does the mutation_size come from? Is it a global scale >>>>> applied to the figure, or is it based on the linewidth, or? >>>>> >>>>> When you emit a set of lines, how are they joined? If I draw a line >>>>> having linewidth 0.1 from the origin to (1, 0), and back to (0, 0.5), what >>>>> happens at the tip? Are two rectangles drawn (each having width 0.1, but >>>>> oriented differently)? Is a bevel created? A miter? Or is the tip >>>>> rounded? Can this be controlled? See page 166 of the manual I sent >>>>> earlier (search for tikz/line join). >>>>> >>>>> Best, >>>>> >>>>> Neil >>>>> >>>> On Wed, May 13, 2015 at 10:14 PM, Neil Girdhar <mis...@gm...> >>>>> wrote: >>>>> >>>> Thanks, it works! >>>>>> >>>>>> I needed to add: >>>>>> >>>>>> import matplotlib.patches >>>>>> >>>>>> to one file and >>>>>> >>>>>> plt.show() >>>>>> >>>>>> to the other. >>>>>> >>>>>> Any word on the locations in the code of the seven arrow drawing >>>>>> methods? >>>>>> >>>>>> I've located the arrow drawing code in tikz, and so I can start >>>>>> porting it over. I'm curious, do we know the linewidth of the edge being >>>>>> decorated by the arrow? To make arrows scale nicely, most of the arrow >>>>>> dimensions are given in two pieces: an absolute value (in points for >>>>>> example) and a line width factor. The dimension is the absolute value plus >>>>>> the line width factor times the line width. The TikZ manual explains: >>>>>> "This makes it easy to vary the size of an arrow tip in accordance with the >>>>>> line width – usually a very good idea since thicker lines will need thicker >>>>>> arrow tips." >>>>>> >>>>>> Best, >>>>>> >>>>>> Neil >>>>>> >>>>> On Wed, May 13, 2015 at 10:07 PM, Benjamin Reedlunn < >>>>>> bre...@gm...> wrote: >>>>>> >>>>> Neil, >>>>>>> >>>>>>> I have attached code to draw the arrowhead. >>>>>>> >>>>>>> -Ben >>>>>>> >>>>>>> >>>>>>> On May 13, 2015, at 7:44 PM, Neil Girdhar <mis...@gm...> >>>>>>> wrote: >>>>>>> >>>>>>> Do you have the code that you used to draw the arrowhead? I'm up to >>>>>>> date now on the development workflow ( >>>>>>> http://matplotlib.org/devel/gitwash/development_workflow.html), so >>>>>>> I'm ready to start working. >>>>>>> >>>>>>> Thanks, >>>>>>> >>>>>>> Neil >>>>>>> >>>>>>> On Wed, May 13, 2015 at 9:10 PM, Benjamin Reedlunn < >>>>>>> bre...@gm...> wrote: >>>>>>> >>>>>>> Yes, I fully agree that we need to unify the many different ways to >>>>>>>> draw arrows. >>>>>>>> >>>>>>>> Neil, in case an example would be helpful for you, I have attached >>>>>>>> a module that includes a custom arrowhead class. The arrowhead class works >>>>>>>> with the with the ax.annotate() method. (I like the annotate method >>>>>>>> because it allows me to easily mix and match coordinate systems for arrow >>>>>>>> placement.) As you can see in the attached pdf, the custom arrowhead >>>>>>>> doesn't include fancy Bezier curves, but that could be added. >>>>>>>> >>>>>>>> -Ben >>>>>>>> >>>>>>>> >>>>>>>> On May 13, 2015, at 2:54 PM, Thomas Caswell <tca...@gm...> >>>>>>>> wrote: >>>>>>>> >>>>>>>> The other thing that should be done is to unify the (I think 7?!?) >>>>>>>> unique ways to draw arrows in mpl. >>>>>>>> >>>>>>>> On Wed, May 13, 2015 at 4:52 PM Neil Girdhar <mis...@gm...> >>>>>>>> wrote: >>>>>>>> >>>>>>>> Yes, I just noticed that as well. That's how the tikz pgf code >>>>>>>>> looks (a sequence of line_to and curve_to commands and so on) so it should >>>>>>>>> be easy to port over the various shapes. >>>>>>>>> >>>>>>>>> On Wed, May 13, 2015 at 4:49 PM, Eric Firing <ef...@ha...> >>>>>>>>> wrote: >>>>>>>>> >>>>>>>>>> On 2015/05/13 10:12 AM, Neil Girdhar wrote: >>>>>>>>>> >>>>>>>>>>> If you want to make arrowheads look at all decent, they really >>>>>>>>>>> need to >>>>>>>>>>> be enclosed in Bezier curves. See the diagram here: >>>>>>>>>>> >>>>>>>>>> >>>>>>>>>> Mpl paths support Bezier curves. >>>>>>>>>> http://matplotlib.org/api/path_api.html?highlight=bezier >>>>>>>>>> >>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> http://tex.stackexchange.com/questions/150289/how-do-you-accomplish-stealth-with-the-new-arrows-meta/230965#230965 >>>>>>>>>>> >>>>>>>>>>> The first two look like garbage. The last one is the only one >>>>>>>>>>> that >>>>>>>>>>> looks good imho. >>>>>>>>>>> >>>>>>>>>> >>>>>>>>>> That depends on the application, and the observer. >>>>>>>>> >>>>>>>>> >>>>>>>>> Sure, but I may as well port them all of the tikz arrowheads over >>>>>>>>> since most of the work would be figuring out how to do it. >>>>>>>>> >>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> Eric >>>>>>>>>> >>>>>>>>>> >>>>>>>>>>> Best, >>>>>>>>>>> >>>>>>>>>>> Neil >>>>>>>>>>> >>>>>>>>>>> On Wed, May 13, 2015 at 4:09 PM, Eric Firing <ef...@ha... >>>>>>>>>>> <mailto:ef...@ha...>> wrote: >>>>>>>>>>> >>>>>>>>>>> On 2015/05/13 9:36 AM, Neil Girdhar wrote: >>>>>>>>>>> >>>>>>>>>>> I don't know matplotlib well enough (yet) to know what >>>>>>>>>>> the >>>>>>>>>>> change would >>>>>>>>>>> consist of. >>>>>>>>>>> >>>>>>>>>>> I suggest you take a look at the beautiful tikz manual: >>>>>>>>>>> http://pgf.sourceforge.net/pgf_CVS.pdf >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> Very helpful, thank you. >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> The arrows.meta on page 201–212 are really well-designed >>>>>>>>>>> and >>>>>>>>>>> beautiful. >>>>>>>>>>> >>>>>>>>>>> Compare this with matplotlib's custom arrows: >>>>>>>>>>> >>>>>>>>>>> http://stackoverflow.com/questions/16968007/custom-arrow-style-for-matplotlib-pyplot-annotate >>>>>>>>>>> >>>>>>>>>>> How do I make tikz's arrowheads available for all >>>>>>>>>>> backends? >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> My guess offhand is that this is a matter of using the mpl >>>>>>>>>>> API. I >>>>>>>>>>> don't think we would want to add all of these types and >>>>>>>>>>> options to >>>>>>>>>>> the mpl core; but a toolkit might be ideal for this. The >>>>>>>>>>> mpl API, >>>>>>>>>>> which generates the same results for all backends, is quite >>>>>>>>>>> complete >>>>>>>>>>> and flexible. Things like arrowheads are Patch objects, and >>>>>>>>>>> you can >>>>>>>>>>> specify any path you want. The main trick is figuring out >>>>>>>>>>> how to >>>>>>>>>>> handle transforms--what kind of coordinates should the path >>>>>>>>>>> be >>>>>>>>>>> specifying? How should things scale as a figure is reshaped >>>>>>>>>>> and >>>>>>>>>>> resized? >>>>>>>>>>> >>>>>>>>>>> For many of these types you could also use mpl Line2D >>>>>>>>>>> objects, for >>>>>>>>>>> which several properties including cap style can be >>>>>>>>>>> specified. Not >>>>>>>>>>> all of the TikZ options would be available, but perhaps >>>>>>>>>>> enough. >>>>>>>>>>> >>>>>>>>>>> Eric >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>> >>>>>>>>> ------------------------------------------------------------------------------ >>>>>>>>> One dashboard for servers and applications across >>>>>>>>> Physical-Virtual-Cloud >>>>>>>>> Widest out-of-the-box monitoring support with 50+ applications >>>>>>>>> Performance metrics, stats and reports that give you Actionable >>>>>>>>> Insights >>>>>>>>> Deep dive visibility with transaction tracing using APM Insight. >>>>>>>>> >>>>>>>> _______________________________________________ >>>>>>>>> Matplotlib-devel mailing list >>>>>>>>> Mat...@li... >>>>>>>>> https://lists.sourceforge.net/lists/listinfo/matplotlib-devel >>>>>>>>> >>>>>>>> >>>>>>>> ------------------------------------------------------------------------------ >>>>>>>> One dashboard for servers and applications across >>>>>>>> Physical-Virtual-Cloud >>>>>>>> Widest out-of-the-box monitoring support with 50+ applications >>>>>>>> Performance metrics, stats and reports that give you Actionable >>>>>>>> Insights >>>>>>>> Deep dive visibility with transaction tracing using APM Insight. >>>>>>>> >>>>>>>> Matplotlib-devel mailing list >>>>>>>> Mat...@li... >>>>>>>> https://lists.sourceforge.net/lists/listinfo/matplotlib-devel >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>>> >>>>> >>> >> |