3

I struggled a lot with matplotlib > candlestick_ohlc and I probably found a solution for some problems that I have encountered. I want to share my solution with you. This is not code which I actually use, but there are some dummy-values and -functions ("sma" would normally be generated by a function) so that you can test this code easily as I hope.

from matplotlib.finance import candlestick_ohlc
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
from matplotlib.dates import num2date, date2num
import numpy as np
import matplotlib.dates
import pandas


dates = [732797.0, 732828.0, 732858.0, 732889.0, 732920.0, 732950.0, 732981.0, 733011.0, 733042.0, 733073.0, 733102.0, 733133.0, 733163.0, 733194.0, 733224.0, 733255.0, 733286.0, 733316.0, 733347.0, 733377.0, 733408.0, 733439.0, 733467.0, 733498.0, 733528.0, 733559.0, 733589.0, 733620.0, 733651.0, 733681.0, 733712.0, 733742.0, 733773.0, 733804.0, 733832.0, 733863.0, 733893.0, 733924.0, 733954.0, 733985.0, 734016.0, 734046.0, 734077.0, 734107.0, 734138.0, 734169.0, 734197.0, 734228.0, 734258.0, 734289.0, 734319.0, 734350.0, 734381.0, 734411.0, 734442.0, 734472.0, 734503.0, 734534.0, 734563.0, 734594.0, 734624.0, 734655.0, 734685.0, 734716.0, 734747.0, 734777.0, 734808.0, 734838.0, 734869.0, 734900.0, 734928.0, 734959.0, 734989.0, 735020.0, 735050.0, 735081.0, 735112.0, 735142.0, 735173.0, 735203.0, 735234.0, 735265.0, 735293.0, 735324.0, 735354.0, 735385.0, 735415.0, 735446.0, 735477.0, 735507.0, 735538.0, 735568.0, 735599.0, 735630.0, 735658.0, 735689.0, 735719.0, 735750.0, 735780.0, 735811.0, 735842.0, 735872.0, 735903.0, 735933.0, 735964.0, 735995.0, 736024.0, 736055.0, 736085.0, 736116.0, 736146.0, 736177.0, 736208.0, 736238.0, 736269.0, 736299.0, 736330.0, 736361.0, 736389.0, 736420.0, 736450.0]
kurse_o = [60.0, 68.15, 68.08, 65.01, 66.1, 70.59, 75.69, 69.12, 66.25, 53.15, 54.61, 54.12, 50.81, 49.0, 39.09, 36.5, 39.6, 35.75, 27.56, 24.22, 27.3, 21.83, 17.74, 19.0, 27.57, 26.62, 25.78, 32.4, 31.92, 34.5, 32.7, 34.1, 37.24, 33.0, 31.15, 35.08, 38.31, 40.75, 41.46, 41.14, 38.5, 46.32, 48.1, 50.51, 50.9, 54.0, 51.56, 50.31, 52.3, 49.2, 51.9, 51.52, 37.76, 32.2, 35.52, 33.48, 33.92, 42.42, 44.8, 45.76, 42.6, 37.3, 35.4, 40.44, 38.87, 37.82, 36.05, 38.1, 42.03, 42.9, 45.67, 42.55, 41.83, 48.9, 46.5, 52.77, 52.92, 57.64, 60.46, 61.14, 63.21, 62.13, 65.49, 68.97, 67.02, 70.0, 68.58, 61.51, 62.2, 60.39, 62.0, 67.2, 68.26, 80.66, 86.79, 89.7, 87.07, 86.2, 83.5, 81.25, 70.36, 66.14, 78.08, 85.1, 75.26, 64.23, 62.89, 66.9, 61.15, 61.36, 53.93, 61.4, 62.29, 62.85, 65.26, 62.4, 70.18, 70.25, 69.2, 69.55, 68.51]
kurse_h = [68.49, 69.66, 71.0, 67.2, 71.14, 78.85, 76.64, 71.6, 66.61, 57.81, 56.07, 55.94, 53.2, 49.0, 43.8, 44.44, 43.45, 35.75, 28.3, 26.74, 28.4, 25.98, 23.1, 28.2, 29.03, 28.51, 32.84, 33.99, 34.7, 37.9, 36.37, 37.9, 37.67, 34.95, 35.52, 39.9, 41.92, 44.8, 44.7, 42.75, 47.59, 50.05, 52.63, 55.05, 59.09, 57.22, 52.48, 53.69, 53.03, 51.93, 53.95, 51.81, 37.88, 39.85, 36.95, 35.09, 43.79, 48.9, 48.95, 46.46, 42.8, 37.36, 40.9, 42.44, 40.57, 39.82, 38.23, 42.01, 44.31, 46.06, 47.27, 43.42, 50.37, 49.82, 53.95, 56.1, 59.56, 60.96, 61.36, 63.19, 66.85, 67.81, 69.59, 71.27, 70.0, 70.8, 70.65, 63.62, 65.75, 62.38, 67.8, 70.2, 81.3, 86.51, 96.07, 92.7, 91.0, 87.63, 86.59, 85.12, 76.72, 79.89, 84.73, 85.5, 75.26, 65.86, 68.52, 66.95, 62.1, 61.41, 62.49, 63.8, 64.59, 66.5, 66.36, 71.4, 73.23, 70.94, 73.0, 69.68, 69.29]
kurse_l = [57.91, 63.53, 63.28, 57.75, 63.55, 70.43, 63.2, 63.88, 46.65, 49.52, 50.51, 48.05, 48.46, 38.65, 35.3, 36.05, 33.7, 17.92, 19.61, 22.15, 20.35, 17.69, 17.2, 18.6, 23.98, 24.03, 23.52, 30.21, 30.1, 32.2, 31.35, 34.0, 32.32, 29.92, 30.74, 34.79, 35.3, 39.47, 39.95, 37.02, 38.3, 43.59, 47.22, 50.09, 50.75, 49.64, 43.56, 48.36, 47.0, 45.7, 49.1, 33.27, 30.92, 30.52, 29.02, 31.1, 33.92, 42.34, 43.11, 39.4, 36.7, 32.86, 34.9, 38.34, 37.36, 35.85, 35.14, 37.74, 41.7, 41.82, 42.1, 38.14, 41.65, 43.16, 45.96, 50.95, 51.89, 56.96, 57.57, 58.05, 60.34, 58.78, 62.65, 63.94, 64.19, 67.46, 61.57, 57.1, 59.34, 55.1, 60.23, 64.13, 65.57, 79.78, 84.65, 84.65, 83.0, 79.03, 77.25, 65.4, 62.06, 62.91, 75.1, 72.48, 62.73, 57.01, 62.36, 58.9, 56.19, 52.0, 50.83, 58.01, 60.14, 62.7, 60.02, 61.61, 68.44, 66.13, 68.91, 64.96, 67.05]
kurse_c = [68.15, 68.59, 66.89, 65.18, 70.64, 75.95, 69.55, 66.5, 52.19, 55.79, 54.15, 50.15, 48.92, 39.28, 37.33, 39.9, 35.4, 26.81, 24.66, 26.7, 22.0, 18.01, 19.08, 27.14, 25.85, 25.78, 32.47, 31.53, 34.4, 33.08, 33.72, 37.23, 33.42, 30.66, 34.86, 38.82, 41.0, 41.92, 41.38, 38.36, 46.46, 47.43, 49.87, 51.32, 53.42, 51.05, 49.85, 52.19, 49.1, 51.9, 50.66, 37.67, 33.63, 37.0, 33.61, 33.92, 42.24, 45.4, 45.21, 41.76, 37.43, 35.34, 40.71, 39.0, 37.66, 36.02, 37.98, 41.32, 42.88, 45.66, 42.44, 42.02, 49.41, 46.48, 52.22, 51.92, 57.62, 60.44, 61.0, 62.9, 62.13, 67.52, 68.59, 66.73, 69.7, 68.4, 61.88, 62.24, 60.73, 62.03, 67.8, 68.97, 80.48, 86.51, 89.73, 86.33, 85.28, 81.64, 81.39, 71.66, 64.85, 78.97, 84.73, 77.58, 64.16, 63.1, 67.37, 60.69, 61.39, 53.52, 60.82, 62.08, 62.71, 64.91, 62.76, 70.72, 69.35, 68.64, 69.2, 68.4, 69.07]


quotes = [tuple([dates[i],
                 kurse_o[i],
                 kurse_h[i],
                 kurse_l[i],
                 kurse_c[i]]) for i in range(len(dates))] #_1

fig, ax = plt.subplots()

candlestick_ohlc(ax, quotes, width=0.6)

# ---------------------------------------------------------

sma = [[kurse_c[i] * 0.8] for i in range(len(dates))]
data = pandas.DataFrame(sma, index=dates, columns=["sma"]) #_2
# data = data.astype(float)
data["sma"].plot(ax=ax)

# ---------------------------------------------------------

fig.autofmt_xdate()
fig.tight_layout()

ax.xaxis.set_major_formatter(matplotlib.dates.DateFormatter('%Y-%m-%d'))
ax.grid(True)

plt.savefig('Test.png')

plt.show()

#_1 First of all candlestick_ohlc expects tuples and not separated lists. It took me a time and several stackoverflow answers to understand this. I have seen examples where a pandas dataframe is given instead of tuples to the function.

#_2 I battled at this point very long :( I found, that it needed "index=dates" to get a chart. Otherwise the index of the data will be 0, 1, 2 and so on and matplotlib won't be able to plot the data to the axes and raise a Value-Error instead. I found this post helpful (answer from Paul H). It helped me to solve the "DateFormatter found a value of x=0"-problem ("Value Error - DateFormatter found a value of x=0, which is an illegal date").

Last but not least my questions:

1.) Can I improve the chart someway? Any suggestions? I would like the y axis to start at zero for example.

2.) How can I change the description at x axis so that the description ends at the end of the axis without a gap (left chart with a gap at the right end of the x axis, "2nd"/right chart without a gap).

chart with and without sma

I hope this post is usefull for some...

M14
  • 444
  • 6
  • 8
  • *How can I change the description at x axis...?* Do you mean the ticks? – Paul H Jul 25 '17 at 22:39
  • At the right side it ends with 2017-06-20, but left ist ends with 2016-02-06 :( I want that it ends left with 2017-06-20 but at least without a gap a this axis. I'm not very used with matplotlib... (BTW: Great work, your answer was very helping to me!) – M14 Jul 25 '17 at 22:43
  • If you code works and a question to how to improve is probably destined to [codereview](https://codereview.stackexchange.com/). However you included a question on **#1**, so no worries on that. I don't get what is that second question, are you trying to plot two subplots one with the line plot and the other without it? And want them with the same x ticks limits? Because your code only plots one graphic. – Vinícius Figueiredo Jul 25 '17 at 22:58
  • you've go two axes, so you should make them both in your call to `pyplot.subplots` and say `sharex=True` – Paul H Jul 25 '17 at 23:03
  • or use e.g., `ax.set_xlim()`. Tons of resources on SO and http://matplotlib.org/ on manipulating the extent of axes – Paul H Jul 25 '17 at 23:04

1 Answers1

2

1.) I would like the y axis to start at zero for example.

It's not that hard, you can simply do ax.set_ylim(0,100).

2.) How can I change the description at x axis so that the description ends at the end of the axis without a gap (left chart with a gap at the right end of the x axis, "2nd"/right chart without a gap).

Let's say you want you plot 2 subplots, sharing the y axis, which seems to be what you really want, you should first make them with fig, (ax,ax2) = plt.subplots(1,2, sharey=True). Then, if you want them to have the same xlim you just need to force one the axs' xlim and make the other ax to have the same. Full code as below generates the following image:

from matplotlib.finance import candlestick_ohlc
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
from matplotlib.dates import num2date, date2num
import numpy as np
import matplotlib.dates
import pandas

dates = [732797.0, 732828.0, 732858.0, 732889.0, 732920.0, 732950.0, 732981.0, 733011.0, 733042.0, 733073.0, 733102.0, 733133.0, 733163.0, 733194.0, 733224.0, 733255.0, 733286.0, 733316.0, 733347.0, 733377.0, 733408.0, 733439.0, 733467.0, 733498.0, 733528.0, 733559.0, 733589.0, 733620.0, 733651.0, 733681.0, 733712.0, 733742.0, 733773.0, 733804.0, 733832.0, 733863.0, 733893.0, 733924.0, 733954.0, 733985.0, 734016.0, 734046.0, 734077.0, 734107.0, 734138.0, 734169.0, 734197.0, 734228.0, 734258.0, 734289.0, 734319.0, 734350.0, 734381.0, 734411.0, 734442.0, 734472.0, 734503.0, 734534.0, 734563.0, 734594.0, 734624.0, 734655.0, 734685.0, 734716.0, 734747.0, 734777.0, 734808.0, 734838.0, 734869.0, 734900.0, 734928.0, 734959.0, 734989.0, 735020.0, 735050.0, 735081.0, 735112.0, 735142.0, 735173.0, 735203.0, 735234.0, 735265.0, 735293.0, 735324.0, 735354.0, 735385.0, 735415.0, 735446.0, 735477.0, 735507.0, 735538.0, 735568.0, 735599.0, 735630.0, 735658.0, 735689.0, 735719.0, 735750.0, 735780.0, 735811.0, 735842.0, 735872.0, 735903.0, 735933.0, 735964.0, 735995.0, 736024.0, 736055.0, 736085.0, 736116.0, 736146.0, 736177.0, 736208.0, 736238.0, 736269.0, 736299.0, 736330.0, 736361.0, 736389.0, 736420.0, 736450.0]
kurse_o = [60.0, 68.15, 68.08, 65.01, 66.1, 70.59, 75.69, 69.12, 66.25, 53.15, 54.61, 54.12, 50.81, 49.0, 39.09, 36.5, 39.6, 35.75, 27.56, 24.22, 27.3, 21.83, 17.74, 19.0, 27.57, 26.62, 25.78, 32.4, 31.92, 34.5, 32.7, 34.1, 37.24, 33.0, 31.15, 35.08, 38.31, 40.75, 41.46, 41.14, 38.5, 46.32, 48.1, 50.51, 50.9, 54.0, 51.56, 50.31, 52.3, 49.2, 51.9, 51.52, 37.76, 32.2, 35.52, 33.48, 33.92, 42.42, 44.8, 45.76, 42.6, 37.3, 35.4, 40.44, 38.87, 37.82, 36.05, 38.1, 42.03, 42.9, 45.67, 42.55, 41.83, 48.9, 46.5, 52.77, 52.92, 57.64, 60.46, 61.14, 63.21, 62.13, 65.49, 68.97, 67.02, 70.0, 68.58, 61.51, 62.2, 60.39, 62.0, 67.2, 68.26, 80.66, 86.79, 89.7, 87.07, 86.2, 83.5, 81.25, 70.36, 66.14, 78.08, 85.1, 75.26, 64.23, 62.89, 66.9, 61.15, 61.36, 53.93, 61.4, 62.29, 62.85, 65.26, 62.4, 70.18, 70.25, 69.2, 69.55, 68.51]
kurse_h = [68.49, 69.66, 71.0, 67.2, 71.14, 78.85, 76.64, 71.6, 66.61, 57.81, 56.07, 55.94, 53.2, 49.0, 43.8, 44.44, 43.45, 35.75, 28.3, 26.74, 28.4, 25.98, 23.1, 28.2, 29.03, 28.51, 32.84, 33.99, 34.7, 37.9, 36.37, 37.9, 37.67, 34.95, 35.52, 39.9, 41.92, 44.8, 44.7, 42.75, 47.59, 50.05, 52.63, 55.05, 59.09, 57.22, 52.48, 53.69, 53.03, 51.93, 53.95, 51.81, 37.88, 39.85, 36.95, 35.09, 43.79, 48.9, 48.95, 46.46, 42.8, 37.36, 40.9, 42.44, 40.57, 39.82, 38.23, 42.01, 44.31, 46.06, 47.27, 43.42, 50.37, 49.82, 53.95, 56.1, 59.56, 60.96, 61.36, 63.19, 66.85, 67.81, 69.59, 71.27, 70.0, 70.8, 70.65, 63.62, 65.75, 62.38, 67.8, 70.2, 81.3, 86.51, 96.07, 92.7, 91.0, 87.63, 86.59, 85.12, 76.72, 79.89, 84.73, 85.5, 75.26, 65.86, 68.52, 66.95, 62.1, 61.41, 62.49, 63.8, 64.59, 66.5, 66.36, 71.4, 73.23, 70.94, 73.0, 69.68, 69.29]
kurse_l = [57.91, 63.53, 63.28, 57.75, 63.55, 70.43, 63.2, 63.88, 46.65, 49.52, 50.51, 48.05, 48.46, 38.65, 35.3, 36.05, 33.7, 17.92, 19.61, 22.15, 20.35, 17.69, 17.2, 18.6, 23.98, 24.03, 23.52, 30.21, 30.1, 32.2, 31.35, 34.0, 32.32, 29.92, 30.74, 34.79, 35.3, 39.47, 39.95, 37.02, 38.3, 43.59, 47.22, 50.09, 50.75, 49.64, 43.56, 48.36, 47.0, 45.7, 49.1, 33.27, 30.92, 30.52, 29.02, 31.1, 33.92, 42.34, 43.11, 39.4, 36.7, 32.86, 34.9, 38.34, 37.36, 35.85, 35.14, 37.74, 41.7, 41.82, 42.1, 38.14, 41.65, 43.16, 45.96, 50.95, 51.89, 56.96, 57.57, 58.05, 60.34, 58.78, 62.65, 63.94, 64.19, 67.46, 61.57, 57.1, 59.34, 55.1, 60.23, 64.13, 65.57, 79.78, 84.65, 84.65, 83.0, 79.03, 77.25, 65.4, 62.06, 62.91, 75.1, 72.48, 62.73, 57.01, 62.36, 58.9, 56.19, 52.0, 50.83, 58.01, 60.14, 62.7, 60.02, 61.61, 68.44, 66.13, 68.91, 64.96, 67.05]
kurse_c = [68.15, 68.59, 66.89, 65.18, 70.64, 75.95, 69.55, 66.5, 52.19, 55.79, 54.15, 50.15, 48.92, 39.28, 37.33, 39.9, 35.4, 26.81, 24.66, 26.7, 22.0, 18.01, 19.08, 27.14, 25.85, 25.78, 32.47, 31.53, 34.4, 33.08, 33.72, 37.23, 33.42, 30.66, 34.86, 38.82, 41.0, 41.92, 41.38, 38.36, 46.46, 47.43, 49.87, 51.32, 53.42, 51.05, 49.85, 52.19, 49.1, 51.9, 50.66, 37.67, 33.63, 37.0, 33.61, 33.92, 42.24, 45.4, 45.21, 41.76, 37.43, 35.34, 40.71, 39.0, 37.66, 36.02, 37.98, 41.32, 42.88, 45.66, 42.44, 42.02, 49.41, 46.48, 52.22, 51.92, 57.62, 60.44, 61.0, 62.9, 62.13, 67.52, 68.59, 66.73, 69.7, 68.4, 61.88, 62.24, 60.73, 62.03, 67.8, 68.97, 80.48, 86.51, 89.73, 86.33, 85.28, 81.64, 81.39, 71.66, 64.85, 78.97, 84.73, 77.58, 64.16, 63.1, 67.37, 60.69, 61.39, 53.52, 60.82, 62.08, 62.71, 64.91, 62.76, 70.72, 69.35, 68.64, 69.2, 68.4, 69.07]

quotes = [tuple([dates[i],
                 kurse_o[i],
                 kurse_h[i],
                 kurse_l[i],
                 kurse_c[i]]) for i in range(len(dates))] #_1

fig, (ax,ax2) = plt.subplots(1,2, sharey=True)

candlestick_ohlc(ax, quotes, width=0.6)
candlestick_ohlc(ax2, quotes, width=0.6)

# ---------------------------------------------------------

sma = [[kurse_c[i] * 0.8] for i in range(len(dates))]
data = pandas.DataFrame(sma, index=dates, columns=["sma"]) #_2
# data = data.astype(float)

data["sma"].plot(ax=ax)

# ---------------------------------------------------------

fig.autofmt_xdate()
fig.tight_layout()

ax.set_ylim(0,100)
ax2.set_ylim(0,100)

axlim = ax.get_xlim()
ax.set_xlim(axlim)
ax2.set_xlim(axlim)

ax.xaxis.set_major_formatter(matplotlib.dates.DateFormatter('%Y-%m-%d'))
ax.grid(True)

ax2.xaxis.set_major_formatter(matplotlib.dates.DateFormatter('%Y-%m-%d'))
ax2.grid(True)

plt.savefig('Test.png')

plt.show()

enter image description here

Vinícius Figueiredo
  • 6,300
  • 3
  • 25
  • 44