Skip to content

Candlestick shadow is drawn after candlestick body #2546

Closed

Description

@c0indev3l

Hello,

in this example
http://matplotlib.org/examples/pylab_examples/finance_demo.html
there is a little display bug.
Candlestick shadows (vertical segment) should be drawn before candlestick body.
see http://en.wikipedia.org/wiki/Candlestick_chart

Kind regards

Activity

  1. pelson commented on Oct 28, 2013

    @pelson
    Member

    Looks like this could be a pretty accessible change. Are you interested in giving it a go, and I'lll happily review.

    Cheers @c0indev3l!

  2. c0indev3l commented on Oct 28, 2013

    @c0indev3l
    Author

    @pelson that's not as easy as expected...

    I tried to modify _candlestick function
    https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/finance.py

    My first idea was to return patches, lines instead of lines, patches
    but it didn't worked

    so I did a quite dirty fix...
    I decomposed each shadow to 2 vline

    There is probably a better way to do this...

    def _candlestick(ax, quotes, width=0.2, colorup='k', colordown='r',
                        alpha=1.0, ochl=True):
    
        """
        Plot the time, open, high, low, close as a vertical line ranging
        from low to high.  Use a rectangular bar to represent the
        open-close span.  If close >= open, use colorup to color the bar,
        otherwise use colordown
    
        Parameters
        ----------
        ax : `Axes`
            an Axes instance to plot to
        quotes : sequence of quote sequences
            data to plot.  time must be in float date format - see date2num
            (time, open, high, low, close, ...) vs
            (time, open, close, high, low, ...)
            set by `ochl`
        width : float
            fraction of a day for the rectangle width
        colorup : color
            the color of the rectangle where close >= open
        colordown : color
             the color of the rectangle where close <  open
        alpha : float
            the rectangle alpha level
        ochl: bool
            argument to select between ochl and ohlc ordering of quotes
    
        Returns
        -------
        ret : tuple
            returns (lines, patches) where lines is a list of lines
            added and patches is a list of the rectangle patches added
    
        """
    
        OFFSET = width / 2.0
    
        lines = []
        patches = []
        for q in quotes: #[1:-1]:
            if ochl:
                t, open, close, high, low = q[:5]
            else:
                t, open, high, low, close = q[:5]
    
            if close >= open:
                color = colorup
                lower = open
                higher = close
                height = close - open
            else:
                color = colordown
                lower = close
                higher = open
                height = open - close
    
            vline = Line2D(
                xdata=(t, t), ydata=(low, lower),
                color='k',
                linewidth=0.5,
                antialiased=True,
            )
    
            vline2 = Line2D(
                xdata=(t, t), ydata=(higher, high),
                color='k',
                linewidth=0.5,
                antialiased=True,
            )
    
            rect = Rectangle(
                xy=(t - OFFSET, lower),
                width = width,
                height = height,
                facecolor = color,
                edgecolor = color,
            )
            rect.set_alpha(alpha)
    
            patches.append(rect)
            lines.append(vline)
            lines.append(vline2)
            ax.add_patch(rect)
            ax.add_line(vline)
            ax.add_line(vline2)
        ax.autoscale_view()
    
        return lines, patches
    
  3. tacaswell commented on Oct 28, 2013

    @tacaswell
    Member

    That is the hard way to do it. Just change the zorder so that the shadow lines are behind the box.

  4. tacaswell commented on Oct 28, 2013

    @tacaswell
    Member

    Something like https://github.com/tacaswell/matplotlib/tree/fix_candlestick_zorder (which I have not tested, and still needs a unit test)

  5. c0indev3l commented on Nov 3, 2013

    @c0indev3l
    Author

    should, at the same time, make the color shadows modifiable ?

    change

        vline = Line2D(
            xdata=(t, t), ydata=(low, lower),
            color='k',
            linewidth=0.5,
            antialiased=True,
        )
    

    to

        vline = Line2D(
            xdata=(t, t), ydata=(low, lower),
            color=colorshadow,
            linewidth=0.5,
            antialiased=True,
        )
    

    It could be useful to be able to set this when drawing using inverted colors (black background, white foreground)

  6. tacaswell commented on Nov 3, 2013

    @tacaswell
    Member

    @c0indev3l That sounds like a good idea. Could you put together a PR for each of these changes?

  7. c0indev3l commented on Nov 3, 2013

    @c0indev3l
    Author

    PR ? performance rating ?

  8. tacaswell commented on Nov 3, 2013

    @tacaswell
    Member

    Pull request.

  9. c0indev3l commented on Nov 3, 2013

    @c0indev3l
    Author

    ok... but I'm quite busy...

    I also have an other comment about this function (when using a black and white color theme with inverted colors ie black background) it's quite problematic

    we should also pass coloredgeup and coloredgedown parameter

    def _candlestick(ax, quotes, width=0.2, colorup='g', colordown='r',                
                    alpha=1.0, ochl=True, colorshadow='k', coloredgeup=None, coloredgedown=None):                
    
        """                
        Plot the time, open, high, low, close as a vertical line ranging                
        from low to high.  Use a rectangular bar to represent the                
        open-close span.  If close >= open, use colorup to color the bar,                
        otherwise use colordown                
    
        Parameters                
        ----------                
        ax : `Axes`                
            an Axes instance to plot to                
        quotes : sequence of quote sequences                
            data to plot.  time must be in float date format - see date2num                
            (time, open, high, low, close, ...) vs                
            (time, open, close, high, low, ...)                
            set by `ochl`                
        width : float                
            fraction of a day for the rectangle width                
        colorup : color                
            the color of the rectangle where close >= open                
        colordown : color                
             the color of the rectangle where close <  open                
        alpha : float                
            the rectangle alpha level                
        ochl: bool                
            argument to select between ochl and ohlc ordering of quotes                
    
        Returns                
        -------                
        ret : tuple                
            returns (lines, patches) where lines is a list of lines                
            added and patches is a list of the rectangle patches added                
    
        """                
        if coloredgeup is None:                
            coloredgeup = colorup                
    
        if coloredgedown is None:                
            coloredgedown = colordown                
    
        OFFSET = width / 2.0                
    
        lines = []                
        patches = []                
        for q in quotes: #[1:-1]:                
            if ochl:                
                t, open, close, high, low = q[:5]                
            else:                
                t, open, high, low, close = q[:5]                
    
            if close >= open:                
                color = colorup                
                coloredge = coloredgeup                
                lower = open                
                higher = close                
                height = close - open                
            else:                
                color = colordown                
                coloredge = coloredgedown                
                lower = close                
                higher = open                
                height = open - close                
    
            vline = Line2D(                
                xdata=(t, t), ydata=(low, lower),                
                color=colorshadow,                
                linewidth=0.5,                
                antialiased=True,                
            )                
    
            vline2 = Line2D(                
                xdata=(t, t), ydata=(higher, high),                
                color=colorshadow,                
                linewidth=0.5,                
                antialiased=True,                
            )                
    
            rect = Rectangle(                
                xy=(t - OFFSET, lower),                
                width = width,                
                height = height,                
                facecolor = color,                
                edgecolor = coloredge,                
            )                
            rect.set_alpha(alpha)                
    
            patches.append(rect)                
            lines.append(vline)                
            lines.append(vline2)                
            ax.add_patch(rect)                
            ax.add_line(vline)                
            ax.add_line(vline2)                
        #ax.autoscale_view()                
    
        return lines, patches
    
  10. tacaswell commented on Nov 3, 2013

    @tacaswell
    Member

    That also looks like a good idea, but these things are much easier to review from a pull request (fork matplotlib on github, create a new branch with your changes, and you can use the website to create the PR against master from your branch)

  11. c0indev3l commented on Nov 4, 2013

    @c0indev3l
    Author

    Ok I will send a pull request this week. There is also some other problems.
    Default colorup should be green (not black).
    open and close are python command... they should be changed for 'opn' and 'cls' (it works but I don't think it's a good idea to keep open and close as variable

  12. tacaswell commented on Nov 4, 2013

    @tacaswell
    Member

    Changing internal variables is ok, changing the names of kwargs or the default value of anything is an api change and should be done very carefully.

  13. tacaswell commented on Jan 22, 2014

    @tacaswell
    Member

    @c0indev3l Are you still interested in working on this issue?

  14. tacaswell commented on Feb 21, 2014

    @tacaswell
    Member

    pushing to 1.4.x as @c0indev3l has gone silent.

  15. added this to the v1.4.x milestone on Feb 21, 2014
  16. 15 remaining items

  17. tacaswell commented on Sep 29, 2015

    @tacaswell
    Member

    @jdgd1 If you have any time or expertise it will be an improvement.

  18. added a commit that references this issue on Oct 1, 2015
  19. jdgd1 commented on Oct 1, 2015

    @jdgd1

    @tacaswell ok, I will help as much as I can. Let me know where to start.

  20. tacaswell commented on Oct 1, 2015

    @tacaswell
    Member

    @jdgd1 For starters, can you review #5160 ?

    @ssanderson is a dev at Quantopian who has expressed (very very) lose interest in also helping with the finance module, it is probably worth getting in touch with him.

    A survey of what is in the finance module would be good to do. Are the functions we have actually useful to a 'typical' finance type anymore? Are there obvious functions we are missing? A major struggle with that package right now is that none of the core-devs do finance so we lack the domain expertise to answer these questions.

    Related, I don't think we have any prose documentation for the finance module, turning some of the examples in to more proper tutorials might be worth doing.

    There has been some discussion of splitting the finance module out of core mpl (into a mpl-finance repo in the matplotlib gh org). If we did this, then it could pick up a pandas dependency which would definitely help increase the relevance to current finance users. This may be something that the pandas folks would be willing to help with.

    I know this is a daunting list and by no means expect you to tackle all of it, but just trying to make the point that this is a domain where there is significant opportunity to have a major impact.

  21. jdgd1 commented on Oct 1, 2015

    @jdgd1

    @tacaswell wow, you weren't kidding - that is quite the list. Will start with checking out #5160 and then trying to get in touch with @ssanderson. I've actually been spending a good bit of time lately working between Quantopian/zipline, so that could work out well.

    Post those two things will start digging into the finance module and making my own list of what I think can go vs. what's missing.

  22. ssanderson commented on Oct 1, 2015

    @ssanderson
  23. ssanderson commented on Oct 1, 2015

    @ssanderson

    (@tacaswell I just realized I've owed you an email reply for like 3 months...sorry about that)

  24. tacaswell commented on Oct 1, 2015

    @tacaswell
    Member

    @ssanderson Don't worry, that still leaves me way in the red in terms of net-emails-owed.

  25. ssanderson commented on Oct 1, 2015

    @ssanderson

    A couple notes on the discussion here:

    • I/we am/are interested in helping out with mpl.finance, but I'm not sure anyone has the bandwidth to make a sustained contribution right now. Zipline is basically being completely rewritten from the ground up on 2 different fronts right now, so we're stretched a bit thin.
    • I'm probably not any more qualified than the MPL devs to comment on things like how to display candlesticks properly, but I can at least help provide real-world user stories/issues from our user base. I suspect that our forums would also be an interesting place to ask for feedback/comments on this stuff.
    • Most of the interesting work we've done in financial visualization at Quantopian has been building visualizations for analyzing portfolio performance. @twiecki and co have been working on pyfolio, which is built primarily on top of pandas, matplotlib, and seaborn. I'm not sure what the right relationship would be between that project and mpl.finance.
  26. lifetime42 commented on Oct 1, 2015

    @lifetime42

    I only picked up python recently and I just started using matplotlib, but I can tell you these charts are looking quite nice and easy to handle (I used jfreechart before)

    Things the finance modul could use are eg.
    -hollow/filled candlesticks (tc2000 style) adding additional information to one candle
    -easy subchart addition right into the chart itself or below for indicators
    -easy access to daw into the chart itself eg. support/resistance lines etc

    to make @jdgd1 list even longer ;-)

  27. femtotrader commented on Oct 1, 2015

    @femtotrader

    @tacaswell @ssanderson +1 for mpl-finance as a separate repository with Numpy/Pandas as dependency.

  28. femtotrader commented on Oct 3, 2015

    @femtotrader

    Pinging some people from PyData / Pandas-DataReader and others who might be interested in a Matplotlib / Numpy / Pandas / Finance plotting lib @davidastephens @bashtage @hayd @jorisvandenbossche

  29. femtotrader commented on Oct 3, 2015

    @femtotrader

    The scope of such a lib could be (or not) to be able to display "realtime" plot. PyQtGraph is nice for realtime plot so pinging also @campagnola

    See

    http://www.pyqtgraph.org/
    http://stackoverflow.com/questions/24670856/the-fastest-way-to-add-a-new-data-bar-with-pyqtgraph

  30. genliu777 commented on May 20, 2016

    @genliu777

    so far i use hecandlestick2_ohlc, and come across the same shadow line through the real body! this question has been put here almost 3 years and not solved!!

  31. rkahun commented on May 19, 2017

    @rkahun

    @genliu777 There is a quick resolving, use z-order as it had mentioned. It works for me without any side effect.
    (By default lines have 2 and patches have 1 as z_order.
    Of course, color of edges and shadows has not changed)

    shadows, bodies = candlestick2_ohlc(ax, .... )
    shadows.set_zorder(0)  # or 9
    bodies.set_zorder(1)   # or 10 or so
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions