holoviews/bokeh gridline issue - python

I am attempting to make a heat map with holoviews (currently using the bokeh backend). I have a data frame ('dep_df') with 3 columns: X, Y, type. X and Y are the dimension labels, and type is a categorical variables b/n 0 and n (where n is an integer). Here's my code:
dep_hm = hv.HeatMap(dep_df[["X", "Y", "type"]], label="DEP population")
TOOLS = ['hover']
colors = palettes.d3['Category20b'][5]
%%opts HeatMap [width=300, height=300, xaxis=None, yaxis=None, show_grid=True]
grid_style = {'grid_line_color': 'white', 'grid_line_width': 1.5}
dep_hm.options(cmap=ListedColormap(colors), gridstyle=grid_style, tools=TOOLS, invert_axes=True)
The plot looks correct in Jupiter notebook except that the ygrid lines don't show (only xgrid), and its showing all tools instead of just 'hover' as I specified. Even with the grid lines that do show, there's always a missing gridline exactly in the middle (have had that issue even in straight bokeh implementations of this heatmap.
Another issue is that I've tried saving the file to HTML using both Bokeh.io and renderer.save() and in both cases, all formatting options are not executed (like not showing the axes, inverting the axes, and not showing full toolbar options). it seems to just save the plot with default options.
Thanks for your help.

renderer.save() doesn't read the notebook magic i.e. %%opts HeatMap [width=300, height=300, xaxis=None, yaxis=None, show_grid=True]
You have to use your_variable.options(width=300, height=300, xaxis=None, yaxis=None, show_grid=True) to make it stick. See http://holoviews.org/user_guide/Customizing_Plots.html Simplified format
Not sure about your other issue though.

Related

Matplotlib not showing histogram correctly when saving figure

Using matplotlib, I am plotting 2 histograms in one figure. The goal is to add them to a Latex document later. I am interested in the difference between the two, so I use a low transparency and plot them on top of each other. In Spyder, when I plot inline, the image looks fine. See wanted plot
When I export the image as a PNG using plt.savefig(), the image looks like this. However, this does not work well in Latex documents as the scaling gets ruined. When I try to export it as a PDF file, the bars of the histogram seem to overlap, making it seem like it has edges, like in ugly plot.
I think the cause of the problem is due to the vector format, when zooming in and out of the PDF, the overlap changes. When zoomed in completely, it looks identical to the PNG, when zoomed out the overlap becomes much larger. I would be very grateful if anyone knew the solution to this.
Things I have tried already:
changing linewidth/edgecolor
changing the matplotlibrc file
changing the distance of the bins using rwidth
Code I am using:
binwidth = (np.max(prediction) - np.min(prediction)) / (2*I**(1/3))
kwargs = dict(alpha=0.5, bins=np.arange(min(prediction), max(prediction) + binwidth, binwidth))
fig_path = '***.pdf'
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.hist(prediction.flatten(), **kwargs, label = 'NN')
ax.hist(hedging_error, **kwargs, label = 'BS')
ax.set_xlim((-3,3))
ax.set_xlabel('Hedging error')
ax.set_ylabel('Count')
ax.legend()
fig.savefig(fig_path)
To remove the bin edges use plt.hist(..., histtype='stepfilled')
https://matplotlib.org/stable/gallery/statistics/histogram_histtypes.html

How to read saved image and locate it in coordinates without any distortins?

I can't overcome maybe very simple obstacle. First, I am doing some spatial operations with shape files, plot the results and save the image:
# read different shape-files, overlaying them, sjoining them`
...
# plotting results:
fig, ax = plt.subplots(figsize=[10, 10])
ax.set_xlim(left=9686238.14, right=9727068.02)
ax.set_ylim(bottom=7070076.66, top=7152463.12)
# various potting like objects.plot(ax=ax, column = 'NAME', cmap='Pastel2', k=6, legend=False) and many others
plt.axis('equal')
plt.savefig('back11.png', dpi=300)
plt.close()
Thus I got such a nice picture back11.png:
Second, I am reading that picture and (in the same cordinates) want to see absolutlely identical one map11.png:
fig, ax = plt.subplots(figsize=[10, 10])
ax.set_xlim(left=9686238.14, right=9727068.02)
ax.set_ylim(bottom=7070076.66, top=7152463.12)
back = plt.imread('back11.png')
ax.imshow(back, extent=[9686238.14, 9727068.02, 7070076.66, 7152463.12])
plt.axis('equal')
plt.savefig('map11.png', dpi=300)
plt.close()
But really I got something else (map11.png):
What is the origin of such a strange mismatch?
When matplotlib is showing an image using plt.imshow, it automatically adds axis and white space around it (regardless of the image content). While your image is accidentally another plot, which contains axis and white space itself. To solve that problem, use
plt.subplots_adjust(0, 0, 1, 1)
plt.axis('off')
which should output nothing but the image.
But on the other hand, you have to specify plt.figure(figsize=xxx, dpi=xxx) correctly in order to get THE stored image (correct size, no interpolation or re-sampling). If you simply want to see the image using python (and you are in jupyter notebook), you can use Pillow. If you convert the image to a PIL.Image object, it is by itself displayable by jupyter REPL.
If you are not inside jupyter, you might also directly open the image using os image viewer. It is at least more convenient than matplotlib to display the "exact" image.
BTW, when displaying the image, the same parameters do not apply any more (since its an image and all parameters are hidden inside the content of it). Therefore, there's no need (and it's wrong) to write all those magic numbers. Also if you want to save the image without white border and axis, use the code above before calling plt.savefig

Matplotlib/Latex issues when using \odot as marker

I'm trying to use the latex symbol \odot as a marker in a scatter plot but I also need latex style ticks, but for some reason these two are not playing well together. I can successfully use marker=$\\odot$ with usetex=False, like this, but when I set it equal to true (to get the tick font right), I get ! LaTeX Error: File 'type1cm.sty' not found. I've already gone through to make sure I have the sty file installed and in the correct directory and that I have all the dependencies installed (as suggested here). Plus, I can still have usetex=True and use any of the normal pyplot markers, just not anything involving math font, but can I can have \odot in the label for the legend. Ive also already tried appending the rc params with amsmath but still keep getting the type1cm error. I've also tried using the raw string literal to no avail.
So basically when usetex=True, I can use math symbols in the label for the legend, just not as the actual marker. Has anyone experienced this issue before?
My current work around involves just plotting a large unfilled circle and overplotting a small filled circle (basically simulating the odot). Then I run into an issue with the legend so I basically have to create a transparent legend showing the large unfilled circles and then plot the smaller filled circles behind it by hand like this which ends up wonky, but this has the axes tick font I need. This becomes very frustrating if I have to change axes limits though, because I have to repeat the process of figuring out where to plot the small filled circles all over again.
Does anyone know if there is a better work around than this? Would it be possible to use the overplotting scheme like I have been, but then create a custom proxy artist to display the \odot symbol (in the different colors/sizes) in the legend?
Mac OSX, matplotlib 1.4.2, python 2.7, matplotlib is using pdfTeX thru TeX Live 2017/Mac Ports 2017
Edit: Here is my code
plt.rc('text', usetex=True)
plt.rc('font', family='serif')
f, ax1 = plt.subplots(1,1)
x = np.arange(20)
y = x
ax1.scatter(x, y, marker='$\\odot$', edgecolors='b', s=200, label = 'Test') #used with usetex=False
#ax1.scatter(x, y, marker='o', edgecolors='b', s=200, label = 'Test') #used with usetex=True
ax1.tick_params(labelsize=24)
leg = ax1.legend(scatterpoints=1, loc='lower right', borderaxespad=0., handletextpad=0.)#, fontsize=18) # borderpad=0.,)
I'm not sure how much I can help without seeing your code, but this worked for me:
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
x1 = [1,2]; x2 = [1,2]
y1 = [1,1]; y2 = [2,2]
mpl.rc('text', usetex = True)
fig, ax = plt.subplots(1,1)
ax.scatter(x1,y1, label='A1', marker=r'$\odot$',s=150, c='b')
ax.scatter(x2,y2, label='A2', marker=r'$\odot$',s=50, c='b')
ax.set_xlim(0,3)
ax.set_ylim(0,3)
ax.legend()
fig.show()
If this doesn't help let me know!

Change Spyder and Matplotlib figure size for saved plots only

I would like to view matplotlib plots inside Spyders IPython console in one size and save figures to a multipage PDF in a different size.
Currently I set the figure size as follows:
plt.rc('axes', grid=True)
plt.rc('figure', figsize=(12, 8))
plt.rc('legend', fancybox=True, framealpha=1)
Then I plot some figures and save them to a list for saving a PDF later on. This works just fine when used alone. The plots are approriately sized for viewing in Spyder IPython console.
At the end of my script I have a loop to go through each of the figures I want to save. In here I want to set the layout and figure size exactly for better printing on an A3 paper.
with PdfPages('multi.pdf') as pdf:
for fig in figs:
fig.tight_layout()
fig.set_size_inches(420/25.4, 297/25.4)
pdf.savefig(figure=fig)
The output PDF is just like I want it to be, but the problem is with the plots shown inside Spyder. Changing the figure size while saving also affects the plots viewed inside Spyder. And using the size of an A3 makes the plots way too big.
So the question is: How do I change the size of saved PDF figures without changing the size of figures shown inside Spyder?
As suggested by #ImportanceOfBeingErnest, changing the figure size back after saving should work and may probably solved you problem.
But, depending on your specific problem, it is possible that you are going to face scaling issues since the size of the figures saved in the pdf is much bigger than the size of those displayed in the IPython console. If you scale everything to look great on the pdf, then it is possible that everything is going to look too big in IPython as shown in the example below:
If you don't need the plot to be interactive in IPython, a solution may be to generate your figures to look good for the pdf and display a scaled bitmap version of them in the IPython console as shown in the code below:
import matplotlib.pyplot as plt
from matplotlib.backends.backend_pdf import PdfPages
import numpy as np
from IPython.display import Image, display
try: # Python 2
from cStringIO import StringIO as BytesIO
except ImportError: # Python 3
from io import BytesIO
# Generate a matplotlib figures that looks good on A3 format :
fig, ax = plt.subplots()
ax.plot(np.random.rand(150), np.random.rand(150), 'o', color='0.35', ms=25,
alpha=0.85)
ax.set_ylabel('ylabel', fontsize=46, labelpad=25)
ax.set_xlabel('xlabel', fontsize=46, labelpad=25)
ax.tick_params(axis='both', which='major', labelsize=30, pad=15,
direction='out', top=False, right=False, width=3, length=10)
for loc in ax.spines:
ax.spines[loc].set_linewidth(3)
# Save figure to pdf in A3 format:
w, h = 420/25.4, 297/25.4
with PdfPages('multi.pdf') as pdf:
fig.set_size_inches(w, h)
fig.tight_layout()
pdf.savefig(figure=fig)
plt.close(fig)
# Display in Ipython a sclaled bitmap using a buffer to save the png :
buf = BytesIO()
fig.savefig(buf, format='png', dpi=90)
display(Image(data=buf.getvalue(), format='png', width=450, height=450*h/w,
unconfined=True))
which shows in the IPython console as:
Thank you #ImportanceOfBeingErnest for pointing out the solution.
I went with a solution that allows me to set plt.rc in the beginning to my taste and then revert to the set values after exporting the figures to a PDF.
First I set the values I use:
plt.rc('axes', grid=True)
plt.rc('figure', figsize=(12, 8))
plt.rc('legend', fancybox=True, framealpha=1)
With these I can plot what I need with just the default values. Then I create the PDF with:
with PdfPages('multi.pdf') as pdf:
for fig in figs:
fig.set_size_inches(420/25.4, 297/25.4)
pdf.savefig(figure=fig, bbox_inches='tight')
fig.set_size_inches(plt.rcParams.get('figure.figsize'))
With this I can get the fig.tight_layout() only on the exported figure and restore the figure size to the default value set earlier.

How to save plot after the plot is zoomed

Last few days I have been facing a problem in saving the matplotlib figure, three days before the code was working fine and saves the plot with changes made through the code, but now the changes (zoomed plot) is not saving rather it saves as it is when the plot is shown any changes made after does not reflects using the save command, don't know why?
ax = pd.rolling_mean(dataToPlot_plot[startTime:endTime][['plotValue']],mar).plot(linestyle='-', linewidth=3, markersize=9, color='#FECB00')
ax.legend().set_visible(False)
plt.show()#showing the plot
fig = ax.get_figure()
fig.set_size_inches(12, 6)#setting the size of the plot, to fix in the PDF file
fig.savefig('graph1.jpg')#saving the plot
even if I call a function, the new changed plot is not saved...
def callmeto_plot()
ax = pd.rolling_mean(dataToPlot_plot[startTime:endTime][['plotValue']],mar).plot(linestyle='-', linewidth=3, markersize=9, color='#FECB00')
ax.legend().set_visible(False)
plt.show()#showing the plot
fig = ax.get_figure()
return fig
fig = callmeto_plot()
fig.set_size_inches(12, 6)
fig.savefig('graph1.jpg')
How do I save the plot (zoomed one with changes) through code? Note: I have noticed that the plot window appearance is also changed, 1 Plot window appearance before 2 Plot window appearance now all the plot window configuration buttons are shifted from bottom to top, does this change affects only in the plot or affects the coding as well?. Please help me to fix this... Thanks in advance.
You could move all the plot changing code above the plt.show() and then save the figure manually from the pop-up window. The right most icon at the bottom left saves the current figure as is currently displayed
Even better you could use plt.axis([xStart, xFinish, yBottom, yTop]) or ax.set_xlim(), ax.set_ylim

Categories