plotnine
plotnine copied to clipboard
Secondary and Multiple x and y axis
Hello,
searched repository and documentation for secondary x & y axis, @has2k1 you mentioned in #63 , "When Matplotlib ships the constraint layout manager, I'll look into adding secondary axes functionality."
Do you have any idea what the approx timeframe for this is, months or quarters away?
For the finance guys having not only secondary but multiple x & y axes is extremely handy, which is something that users of bloomberg and reuters eikon are familiar with, and has been a major problem for excel users as they still haven't managed to even introduce a tertiary, or let alone even more levels in axes options, people have to index data if they need to compare more than 2 different time series still even in excel 2016 as we all know, which is a time consuming pain.
e.g.
(ggplot(df, aes(x1="", x2="", x3="", ... , y1="" y2="", y3="", ... ))
+ scale_x1_datetime(breaks=date_breaks('1 year'),
+ scale_x2_datetime(breaks=date_breaks('1 quarter'),
+ scale_x3_datetime(breaks=date_breaks('1 month'),
+ geom_line(aes(y1='US'), color='#00355F', size=1)
+ geom_line(aes(y2='Turkey'), color='#2494EA', size=1)
+ geom_line(aes(y3='Australia'), color='#0222FF', size=1)
+ labs(x1="", x2="", x3="", y1="" y2="", y3="")
matplot example code: multiple_yaxis_with_spines.py https://matplotlib.org/gallery/ticks_and_spines/multiple_yaxis_with_spines.html
Kind Regards,
There is no time frame.
is there a method to force plotnine to use a defined axis? for example if you create a plotnine figure 1
and return the axis, can you create another plotnine figure 2
and force it to output on the plotnine figure 1
axis?
It is an internal API, but if you do not care for such see how the figure and axes are reused when creating animations.
I can take a look, do you have a link to the example?
Added the link.
ok I downloaded the latest development version of plotnine
and tried to implement it like so:
g = (pn.ggplot(df, pn.aes(col, color='factor(other_col)')) + pn.geom_density())
figure, plot = g.draw(return_ggplot=True)
axs = plot.axs
and it outputs the first figure correctly. Then I try to reuse the axis like so:
from copy import copy
g2 = (pn.ggplot(df, pn.aes(col)) + pn.geom_density())
g2 = copy(g2) # tried both with and without this line I get same error
g2._draw_using_figure(figure, axs)
and it outputs the following traceback error:
---------------------------------------------------------------------------
NotImplementedError Traceback (most recent call last)
~/anaconda3/envs/pymc3/lib/python3.6/copy.py in deepcopy(x, memo, _nil)
179 else:
--> 180 y = _reconstruct(x, memo, *rv)
181
~/anaconda3/envs/pymc3/lib/python3.6/copy.py in _reconstruct(x, memo, func, args, state, listiter, dictiter, deepcopy)
279 if deep:
--> 280 state = deepcopy(state, memo)
281 if hasattr(y, '__setstate__'):
~/anaconda3/envs/pymc3/lib/python3.6/copy.py in deepcopy(x, memo, _nil)
149 if copier:
--> 150 y = copier(x, memo)
151 else:
~/anaconda3/envs/pymc3/lib/python3.6/copy.py in _deepcopy_dict(x, memo, deepcopy)
239 for key, value in x.items():
--> 240 y[deepcopy(key, memo)] = deepcopy(value, memo)
241 return y
~/anaconda3/envs/pymc3/lib/python3.6/copy.py in deepcopy(x, memo, _nil)
179 else:
--> 180 y = _reconstruct(x, memo, *rv)
181
~/anaconda3/envs/pymc3/lib/python3.6/copy.py in _reconstruct(x, memo, func, args, state, listiter, dictiter, deepcopy)
279 if deep:
--> 280 state = deepcopy(state, memo)
281 if hasattr(y, '__setstate__'):
~/anaconda3/envs/pymc3/lib/python3.6/copy.py in deepcopy(x, memo, _nil)
149 if copier:
--> 150 y = copier(x, memo)
151 else:
~/anaconda3/envs/pymc3/lib/python3.6/copy.py in _deepcopy_dict(x, memo, deepcopy)
239 for key, value in x.items():
--> 240 y[deepcopy(key, memo)] = deepcopy(value, memo)
241 return y
~/anaconda3/envs/pymc3/lib/python3.6/copy.py in deepcopy(x, memo, _nil)
160 if copier:
--> 161 y = copier(memo)
162 else:
~/anaconda3/envs/pymc3/lib/python3.6/site-packages/matplotlib/transforms.py in __copy__(self, *args)
120 "TransformNode instances can not be copied. " +
--> 121 "Consider using frozen() instead.")
122 __deepcopy__ = __copy__
NotImplementedError: TransformNode instances can not be copied. Consider using frozen() instead.
The above exception was the direct cause of the following exception:
SystemError Traceback (most recent call last)
~/anaconda3/envs/pymc3/lib/python3.6/site-packages/IPython/core/formatters.py in __call__(self, obj)
691 type_pprinters=self.type_printers,
692 deferred_pprinters=self.deferred_printers)
--> 693 printer.pretty(obj)
694 printer.flush()
695 return stream.getvalue()
~/anaconda3/envs/pymc3/lib/python3.6/site-packages/IPython/lib/pretty.py in pretty(self, obj)
378 if callable(meth):
379 return meth(obj, self, cycle)
--> 380 return _default_pprint(obj, self, cycle)
381 finally:
382 self.end_group()
~/anaconda3/envs/pymc3/lib/python3.6/site-packages/IPython/lib/pretty.py in _default_pprint(obj, p, cycle)
493 if _safe_getattr(klass, '__repr__', None) is not object.__repr__:
494 # A user-provided repr. Find newlines and replace them with p.break_()
--> 495 _repr_pprint(obj, p, cycle)
496 return
497 p.begin_group(1, '<')
~/anaconda3/envs/pymc3/lib/python3.6/site-packages/IPython/lib/pretty.py in _repr_pprint(obj, p, cycle)
691 """A pprint that just redirects to the normal repr function."""
692 # Find newlines and replace them with p.break_()
--> 693 output = repr(obj)
694 for idx,output_line in enumerate(output.splitlines()):
695 if idx:
~/anaconda3/envs/pymc3/lib/python3.6/site-packages/plotnine/ggplot.py in __repr__(self)
84 Print/show the plot
85 """
---> 86 self.draw()
87 plt.show()
88 return '<ggplot: (%d)>' % self.__hash__()
~/anaconda3/envs/pymc3/lib/python3.6/site-packages/plotnine/ggplot.py in draw(self, return_ggplot)
176 # ggplot object. Do the copy here as we may/may not
177 # assign a default theme
--> 178 self = deepcopy(self)
179 self._build()
180
~/anaconda3/envs/pymc3/lib/python3.6/copy.py in deepcopy(x, memo, _nil)
159 copier = getattr(x, "__deepcopy__", None)
160 if copier:
--> 161 y = copier(memo)
162 else:
163 reductor = dispatch_table.get(cls)
~/anaconda3/envs/pymc3/lib/python3.6/site-packages/plotnine/ggplot.py in __deepcopy__(self, memo)
105 memo[id(new[key])] = new[key]
106 else:
--> 107 new[key] = deepcopy(old[key], memo)
108
109 return result
~/anaconda3/envs/pymc3/lib/python3.6/copy.py in deepcopy(x, memo, _nil)
159 copier = getattr(x, "__deepcopy__", None)
160 if copier:
--> 161 y = copier(memo)
162 else:
163 reductor = dispatch_table.get(cls)
~/anaconda3/envs/pymc3/lib/python3.6/site-packages/plotnine/facets/facet.py in __deepcopy__(self, memo)
296 memo[id(new[key])] = new[key]
297 else:
--> 298 new[key] = deepcopy(old[key], memo)
299
300 return result
~/anaconda3/envs/pymc3/lib/python3.6/copy.py in deepcopy(x, memo, _nil)
178 y = x
179 else:
--> 180 y = _reconstruct(x, memo, *rv)
181
182 # If is its own copy, don't memoize.
~/anaconda3/envs/pymc3/lib/python3.6/copy.py in _reconstruct(x, memo, func, args, state, listiter, dictiter, deepcopy)
278 if state is not None:
279 if deep:
--> 280 state = deepcopy(state, memo)
281 if hasattr(y, '__setstate__'):
282 y.__setstate__(state)
~/anaconda3/envs/pymc3/lib/python3.6/copy.py in deepcopy(x, memo, _nil)
148 copier = _deepcopy_dispatch.get(cls)
149 if copier:
--> 150 y = copier(x, memo)
151 else:
152 try:
~/anaconda3/envs/pymc3/lib/python3.6/copy.py in _deepcopy_dict(x, memo, deepcopy)
238 memo[id(x)] = y
239 for key, value in x.items():
--> 240 y[deepcopy(key, memo)] = deepcopy(value, memo)
241 return y
242 d[dict] = _deepcopy_dict
~/anaconda3/envs/pymc3/lib/python3.6/copy.py in deepcopy(x, memo, _nil)
159 copier = getattr(x, "__deepcopy__", None)
160 if copier:
--> 161 y = copier(memo)
162 else:
163 reductor = dispatch_table.get(cls)
SystemError: <built-in method __deepcopy__ of numpy.ndarray object at 0x7f03376a42b0> returned a result with an error set
g = (pn.ggplot(df, pn.aes(col, color='factor(other_col)')) + pn.geom_density())
figure, plot = g.draw(return_ggplot=True)
axs = plot.axs
g2 = (pn.ggplot(df, pn.aes(col)) + pn.geom_density())
g2._draw_using_figure(figure, axs)
print(1)
that worked thanks.
Looking forward to the Secondary y axis in the coming version. Now I have to use the pyplot.twinx()
after the ggplot
command, but clearly not a good solution for Secondary y axis . Really Wish to have the scale_y_continuous(sec.axis = sec_axis(~./200))
as same as the R-ggplot2.
This feature would be hugely helpful. Thank you for this great package.
hi, big fan of plotnine, novice user of github. I wanted to ask how to do such a plot now that the feature has been implemented?
I tried this as a workaround for the scale_y_continous but it seems that the second plot g2 hides the first g... and I only see the geom_point the geom_box is gone...
Any news on the scale_y_continous availability?
thanks!!
g = (pn.ggplot(df_grouped, pn.aes(x='factor(Day)', y='Cell size')) +
geom_boxplot(varwidth=True,width=1) +
facet_grid('. ~ Sample') +
#scale_y_continuous(name = "Primary axis", sec.axis = sec_axis(~.*100, name = "Secondary")) +
theme(strip_background_y = element_text(color = '#969dff' , width = 0.2),figure_size=(18, 7))
)
figure, plot = g.draw(return_ggplot=True)
axs = plot.axs
g2 = (pn.ggplot(df_volumes, aes(x='factor(Day)', y='Total_Cells')) +
geom_point(color='red', size=5) +
facet_grid('. ~ Sample'))
g2._draw_using_figure(figure, axs)
print(1)