From: Neil G. <mis...@gm...> - 2015-05-15 15:04:27
|
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 >>>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>>> >>>>>> >>>>>> >>>>> >>>> >> > |