From: Neil G. <mis...@gm...> - 2015-05-15 15:41:26
|
Okay, I'm going to wait for more feedback. An hour of design can be worth ten hours of implementation :) On Fri, May 15, 2015 at 11:11 AM, Thomas Caswell <tca...@gm...> wrote: > 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 >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>> >>>>>> >>>> >>> |