Closed BreitA closed 3 years ago
Hi @BreitA,
Yes, this is something that I would like to have. Currently, I don't think it's even possible to do this manually outside of calmap after calling it.
An implementation in yearplot
would probably start with something like this:
diff --git a/calmap/__init__.py b/calmap/__init__.py
index 1c53a8c..fddca78 100644
--- a/calmap/__init__.py
+++ b/calmap/__init__.py
@@ -181,7 +181,8 @@ def yearplot(data, year=None, how='sum', vmin=None, vmax=None, cmap='Reds',
# Draw heatmap.
kwargs['linewidth'] = linewidth
kwargs['edgecolors'] = linecolor
- ax.pcolormesh(plot_data, vmin=vmin, vmax=vmax, cmap=cmap, **kwargs)
+ mesh = ax.pcolormesh(plot_data, vmin=vmin, vmax=vmax, cmap=cmap, **kwargs)
+ ax.figure.colorbar(mesh)
# Limit heatmap to our data.
ax.set(xlim=(0, plot_data.shape[1]), ylim=(0, plot_data.shape[0]))
Some quick thoughts:
yearplot
simply works on one axis, which it returns).cbar_kws
argument, and by providing an existing axis).calendarplot
than on yearplot
?Not sure when I'll have time to look into this. Would welcome a PR though :)
I cooked something this evening that works, I will send you what I've done when it's clean.
Okay so it's very "homemade" but does the job. I'm very bad with matplotlib so I'm sure there is a more elegant way to do the stuff but it works wonders for me atm. as you can see I didt it as an external function to call after the calmap plot. The function add another axis cb_ax that is the colorbar to the figure. This is the copy of my notebook EDIT : update 2016-03-10 a little debug going through after testing it at work + most options tested + a little bit of pep8 ISSUES :
def add_colorbar(data, fig, cmap, auto_tick=True,
vmin=None,
vmax=None,
num_label=3,
cb_pos=None,
decimal=0,
yticks=None,
ytick_labels=None,
cbar_width=0.01):
# colorbar position
if cb_pos is None:
axes = fig.get_axes()
if len(axes) > 1:
pos1 = axes[0].get_position()
pos2 = axes[-1].get_position()
cb_pos = [pos1.x1 + 0.05, pos2.y0, cbar_width, pos1.y1 - pos2.y0]
else:
cb_pos = [0.9 + 0.05, 0.4, cbar_width, 0.22] # fine custom pos for the single year plot object
# custom generation of colorbar (seen in http://matplotlib.org/examples/color/colormaps_reference.html)
gradient = np.linspace(0, 255, 256)
gradient = np.vstack((gradient, gradient))
# generate colorbar ax
cb_ax = fig.add_axes(cb_pos)
cb_ax.imshow(gradient.T, aspect='auto', cmap=plt.get_cmap(cmap))
# generate tick and tick label by hand (I'm sure there is a much more efficient thing to do here)
if vmin is None:
vmin = np.min(data)
if vmax is None:
vmax = np.max(data)
vmax = float(vmax)
vmin = float(vmin)
if auto_tick is True:
step = (vmax - vmin) / (num_label - 1)
ytick_labels = np.arange(vmin, vmax, step)
ytick_labels = np.append(ytick_labels, vmax)
ytick_labels = np.round(ytick_labels, decimal)
ytick_labels = [str(v) for v in ytick_labels.tolist()]
yticks = tuple(np.linspace(0, 255, num_label).tolist())
elif yticks is None or ytick_labels is None:
raise TypeError('yticks and ytick_labels required if auto_tick is False')
elif len(yticks) != len(ytick_labels):
raise TypeError('yticks and ytick_labels must be of same length')
else:
# custom ticks
num_label = len(yticks)
yticks = np.asarray(yticks) - vmin
yticks = yticks * 255 / (vmax - vmin)
# edit ytick + remove xticks
cb_ax.set_yticks(yticks)
cb_ax.set_xticks([])
cb_ax.set_yticklabels(ytick_labels)
cb_ax.yaxis.tick_right()
return cb_ax
#few years example
df=pd.DataFrame(data=np.random.randn(900,1)
,index=pd.date_range(start='2014-01-01 00:00:00',freq='1D',periods =900)
,columns=['data'])
cmap='RdYlGn'
fig,ax=calmap.calendarplot(df['data'],
fillcolor='grey', linewidth=0,cmap=cmap,
fig_kws=dict(figsize=(17,8)))
fig.suptitle('Calendar view' ,fontsize=20,y =1.08)
cb_ax=add_colorbar(df['data'],fig,cmap=cmap)
cb_ax.tick_params(axis='y', which='major', labelsize=15)
cb_ax.set_title('rand_data',fontsize=15,y=1.02)
#few years example custom
df=pd.DataFrame(data=np.random.randn(900,1)
,index=pd.date_range(start='2014-01-01 00:00:00',freq='1D',periods =900)
,columns=['data'])
cmap='RdYlGn'
yticks=[-5,1,2,4.5]
ytick_labels=['-5 git','1 git','2 git','4.5 git' ]
fig,ax=calmap.calendarplot(df['data'],
fillcolor='grey', linewidth=0,cmap=cmap,
fig_kws=dict(figsize=(17,8)),vmin=-5,vmax=5)
fig.suptitle('Calendar view' ,fontsize=20,y =1.08)
cb_ax=add_colorbar(df['data'],fig,cmap=cmap,vmin=-5,vmax=5,decimal=1,
yticks=yticks,
ytick_labels=ytick_labels,
auto_tick=False,
cbar_width=0.03)
cb_ax.tick_params(axis='y', which='major', labelsize=15)
cb_ax.set_title('rand_data',fontsize=15,y=1.02)
# lots of years example
df=pd.DataFrame(data=np.random.randn(2000,1)
,index=pd.date_range(start='2014-01-01 00:00:00',freq='1D',periods =2000)
,columns=['data'])
cmap='RdYlGn'
fig,ax=calmap.calendarplot(df['data'],
fillcolor='grey', linewidth=0,cmap=cmap,
fig_kws=dict(figsize=(17,17)))
fig.suptitle('Calendar view' ,fontsize=20,y =1.08)
cb_ax=add_colorbar(df['data'],fig,cmap)
cb_ax.tick_params(axis='y', which='major', labelsize=15)
cb_ax.set_title('rand_data',fontsize=15,y=1.02)
# yearplot test
df=pd.DataFrame(data=np.random.randn(365,1)
,index=pd.date_range(start='2014-01-01 00:00:00',freq='1D',periods =365)
,columns=['data'])
cmap='RdYlGn'
fig=plt.figure(figsize=(17,8))
ax=calmap.yearplot(df['data'],
fillcolor='grey', linewidth=0,cmap=cmap,
)
cb_ax=add_colorbar(df['data'],fig,cmap)
cb_ax.tick_params(axis='y', which='major', labelsize=15)
cb_ax.set_title('rand_data',fontsize=15,y=1.08)
fig.suptitle('Calendar view' ,fontsize=20,y=0.7)
# lots of years example bad scale
df=pd.DataFrame(data=np.random.randn(2000,1)
,index=pd.date_range(start='2014-01-01 00:00:00',freq='1D',periods =2000)
,columns=['data'])
cmap='RdYlGn'
fig,ax=calmap.calendarplot(df['data'],
fillcolor='grey', linewidth=0,cmap=cmap,
fig_kws=dict(figsize=(17,8)))
fig.suptitle('Calendar view' ,fontsize=20,y =1.08)
cb_ax=add_colorbar(df['data'],fig,cmap)
cb_ax.tick_params(axis='y', which='major', labelsize=15)
cb_ax.set_title('rand_data',fontsize=15,y=1.02)
@BreitA Thanks a lot for sharing your code.
I don't have the time to work on it now, but I would like to include something like you're showing here in the future. So I'm leaving this issue open, thanks again :+1:
Hi, I was searching for the same stuff and I didn't think about looking here in the issues!
I answer to a question on stackoverflow python 2.7 - add a colorbar to a calmap plot and I think it's yours, @BreitA .
My solution is to pick the children of the axis returned by yearplot and stick the colorbar to this mappable : after digging in the code, it is the second call to ax.quadmesh . So the code would be:
fig,ax=calmap.calendarplot(df['data'],
fillcolor='grey', linewidth=0,cmap='RdYlGn',
fig_kws=dict(figsize=(17,8)))
fig.colorbar(ax[0].get_children()[1], ax=ax.ravel().tolist())
and even simpler for a single yearplot
(it is encapsulated in an explicit call to figure to declare the size) :
fig = plt.figure(figsize=(20,8))
ax = fig.add_subplot(111)
cax = calmap.yearplot(df, year=2014, ax=ax, cmap='YlGn')
fig.colorbar(cax.get_children()[1], ax=cax, orientation='horizontal')
A good start would be to return the reference to the actual graphic object that contains the data in the yearplot
function
Thanks @kidpixo for commenting here and linking back to the SO thread!
I'm interested in adding this or making it easier to do it yourself, but time limited at the moment.
Thank you for the package, @martijnvermaat !
A solution would be to alter the return of yearplot
, I don't know how this impact back compatibility.
I can also think about an helper function, like yearplotcolorbar
who takes the output of yearplot
and wrap the code I used to generate the plot.
Something more elaborated for calendarplot
should do the trick.
Thanks for the solution provided @kidpixo , will try it when I have the time ! And yes the Stackoverflow was mine and then I ended up asking the question here.
@BreitA you are welcome! Could you please accept my solution on stackoverflow?
Yeah I just did! I tested it and it is exactly what I was looking for and it works great!
Nice to hear :-D if you have time to contribute or to publish some code of your solution will be great!
Honestly at this point your solution is much more elegant and show a better understanding of matplotlib than I have done with my homemade solution.
I will use your solution for my future use of this lib tbh.
Thanks again.
> fig = plt.figure(figsize=(20,8))
> ax = fig.add_subplot(111)
> cax = calmap.yearplot(df, year=2014, ax=ax, cmap='YlGn')
> fig.colorbar(cax.get_children()[1], ax=cax, orientation='horizontal')
> ```
>
This works beautifully!
Hi, if this problem still exists and you'd like to create a PR to fix it please direct it to https://github.com/MarvinT/calmap/ That is the version that gets published to pypi and has received several updates to fix some existing issues.
Thank you for creating the issue. Unfortunately I don't have the time to maintain this project. As per @MarvinT 's comment, please see https://github.com/MarvinT/calmap/ instead.
Hi,
I'm currently heavily relying on your module to plot calendar heatmap. Your module is great but I wonder If you know a simple way to put a colorbar for the whole figure on the left of the calendar heatmap figure. It could also be a neat feature in your next iteration on the module to have an option to put automatically the colorbar when creating the heatmap.