Respect,
Here is a user from China. I met a problem when I updated to latest version of mapfinance. I can't show Chinese characters anymore even the matplotlib can work with Chinese characters well.
Thank you very much
What method do you use that works with matplotlib but not with mplfinance?
Can you please post and example of code and data that previously worked to display Chinese characters in an older version of mplfinance, but now does not work with the new version?
To display Chinese fonts correctly with matplotlib, usually the font.family needs to be modified. For example:
plt.rcParams["font.family"]='Noto Sans CJK SC'
The official documentation on this issue: https://matplotlib.org/3.1.0/tutorials/text/text_props.html#text-with-non-latin-glyphs
Somehow the mplfinance modifies the font.family before plotting, which can be confirmed with the following codes before and after some mpl.plot:
plt.rcParams['font.family']
@oirontro
Thank you very much for contributing to this discussion. It is now clear to me why this doesn't work.
(Although it is not clear to me how this ever worked as claimed here that it stopped working with the latest version, which is why I would like to see actual code that supposedly worked with an early version of mplfinance.)
At any rate, when mplfinance applies its styles, it first appies a matplotlib style and these matplotlib styles modify rcParams.
The way to make this work would be to include the desired font.family in the style. For example, suppose you wanted to use style 'yahoo' , but with Chinese characters. You should be able to do so like this:
rcpdict = { 'font.family' : 'Noto Sans CJK SC' }
s = mpf.make_mpf_style(base_mpf_style='yahoo',rc=rcpdict)
mpf.plot(data,...,style=s)
Please let me know if that works for you.
Thank you. All the best. --Daniel
@DanielGoldfarb
Thanks a lot for your effort on mplfinance. It's very handy. And the solution you provided works like a charm.
As for the style application, I wonder whether the following line is absolutely necessary when _apply_mpfstyle:
It seems this line of code would remove any customization on the style of matplotlib.
It's only my humble opinion that maybe mplfinance could only update style settings specified in https://github.com/matplotlib/mplfinance/tree/master/src/mplfinance/_styledata by default.
Thanks again.
@oirontro ,
Thank you. The application of styles is definitely worth discussing. I will assume for this discussion that you have read through all of https://github.com/matplotlib/mplfinance/blob/master/examples/styles.ipynb; if not, you should do that now.
As you know, an mplfinance stye is a superset of a matplotlib style. That is, each mplfinance style includes a matplotlib style within it. They are not separate things. And just as every matplotlib plot always has a matplotlib style applied to it, similarly every mplfinance plot always has an mplfinance style applied to it.
Since mpflnance styles include matplotlib styles in them, _the philosphy has been that any matplotlib style customizations should be included in the mplfinance style_. That's why we can specify a "base_mpl_style" when creating an mplfinance style. This base_mpl_style itself can be a custom style. Further customization via rcParams is done via the rc= kwarg to mpf.make_mpf_style(). Think of the mplfinance plot style as a single unit.
This unity between the mplfinance style and the matplotlib style is not just how the code is written, but has practical applications. For example, dark candles will not look good on dark Axes face, just as very light ohlc bars will not look good in a similarly light Axes face. In general, _there needs to be a compatibility and complementarity between style elements that derive from mplfinance (for example, "market colors") and style elements that derive from matplotlib_.
Now ... the reason _apply_mpfstyle() applies matplotlib style 'default' first, before doing any other styling, is to ensure each style has a consistent appearance. Without this, it is possible for the same style to have a different appearance on different plots, depending on what style the user applied previously within the same program. (Such inconsistent appearance of the same style could be construed as a bug).
Now here's where (I think) the discussion gets interesting. I am currently developing the ability for users to pass their own Axes instances into mpf.plot() and mpf.make_addplot(). The problem is that many style elements get applied at the time a Figure or Axes is instantiated. This creates a problem:
When a user passes their own matplotlib created Axes into mpf.plot(), some of the mplfinance style elements get lost (namely those that get applied at the times of Figure and Axes instantiation). I've gotten around this problem by providing mpf wrappers for the most common matplotlib methods for instantiating subplots and Axes.
These wrappers take an additional kwarg style= allowing the caller to specify an mplfinance style. Other than that, the wrapper is identical to the matplotlib version. These wrappers include mpf.figure(), mpf.add_subplot(), mpf.add_axes(), mpf.subplot(), and mpf.subplots().
With these methods, it is possible to create a single Figure with varying style subplots, like this:

Here's the thing. I'm thinking maybe I should not allow users to pass in Axes that were _not_ created with one of the mpf wrappers. This will maintain a consistent interface for styling in mplfinance.
I'm also thinking about maybe not imposing such a restriction. This would set a precident. It would mean that when passing external Axes directly from matplotlib into mplfinance, then the "unity" of the mplfinance style is broken. There would no longer be a single, consistent interface for dealing with styling in mplfinace. Effectively only the "market_colors" portion of the mplfinance style would be applied; (possibly some other elements as well, to the extent that they are applied after Axes instantiation, thus opening the door for additional confusion).
In this case it would become the caller's responsibilty to ensure that all style elements are compatible, through using two different interfaces. Maybe that's OK for anyone who wants to instantiate their own matplotlib Axes, since they are already deep into matplotlib and not using mplfinance on its simplest levels. But the wrapper functions do all the same thing, they simply allow the complete application of the mplfinance style.
Your thoughts?
@DanielGoldfarb
Thank you very much for the time spent on the project.
It is important that each style has a consistent appearance. And maybe it is equally important to maintain the composability of mplfinace.
I think you have already figured out a very handy and versatile design. The ability for users to pass their own Axes instances into mpf.plot() and mpf.make_addplot() is very handy. The idea of style wrappers is awesome. Thanks again for those efforts.
For the default mpf.plot, maybe we could only override style settings absolutely necessary for the consistent appearance. As for the font issue mentioned in this thread, maybe the font.family does not interfere with the appearance?
Maybe we drop the following line
and only override style settings necessary?
If you are still worried about the consistent appearance, maybe an additional argument, such as keep_style, could be added to the mpf.plot so that users could ask to preserve some style settings, such as 'font.family'? We get the settings specified in keep_style and re-apply them after the
and only override style settings necessary?
The point is, this line plt.style.use('default') is necessary to keep a consistent style.
maybe an additional argument, such as
keep_style, could be added to ...mpf.plot()... to preserve some style settings ...
I will think about this. Maybe.
Presently, any and all style settings can be preserved using the rc= kwarg of make_mpf_style().
It is even possible to pass all of rcParams in:
import mplfinance as mpf
import matplotlib.pyplot as plt
s = mpf.make_mpf_style(rc=plt.rcParams) # This is equivalent to the proposed `keep_style=True`
mpf.plot(df,style=s)
Or alternatively, in a single line of code:
mpf.plot(df,style=mpf.make_mpf_style(rc=plt.rcParams)) # This is equivalent to the proposed `keep_style=True`
Please give this a try and let me know if it works for you.
Most helpful comment
@oirontro
Thank you very much for contributing to this discussion. It is now clear to me why this doesn't work.
(Although it is not clear to me how this ever worked as claimed here that it stopped working with the latest version, which is why I would like to see actual code that supposedly worked with an early version of mplfinance.)
At any rate, when mplfinance applies its styles, it first appies a matplotlib style and these matplotlib styles modify rcParams.
The way to make this work would be to include the desired font.family in the style. For example, suppose you wanted to use style
'yahoo', but with Chinese characters. You should be able to do so like this:Please let me know if that works for you.
Thank you. All the best. --Daniel