Matplotlib savefig pdf doesn't display some polygons - python

I'm making a relatively simple plot that seemed to work fine. I have a number of line segments, and each defines an area. I'm using polygons for the filled areas using plot.Polygon and ax.add_patch.
When I save to .png, everything works fine. So, I turn to pdf for the final image. I manually set things like fontsize, figsize and dpi, so there should be no problem.
Sadly, 2 out of the four Polygons in the current picture are not displayed in the pdf. Which is strange; the previous two images (other datasets) did act correctly. I've played around a bit with zorder and alpha on the Polygons but to no avail.
My google search did not turn up anything; it mentioned the dpi being different if you haven't set it manually, but this is no problem. Beyond that, I could find no clear reasons.
My sincere thanks,
Daimonie

Okay, so I've found the problem.
Let's first denote the method I use to add the polygons, just for clarity. The points $(x,y)$ that define the vertices are called vertices. The polygon is made as:
first_polygon = plt.Polygon(vertices, zorder=.1, facecolor=colours[colour_index], alpha=fill_opacity)
Next, I add it to the figure:
ax.add_patch(first_polygon)
So why didn't it display some polygons? I cannot be sure of the reason, but the issue resolved when I redefined the polygons. The two polygons that didn't display were bound by three lines. The first polygon was bound by y0, y1, y2 and the 'frame' of the figure. Because I was still scaling the figure, I had put the point that bound it by the 'frame' as $(100, -100)$. When I changed that to $(min_x, min_y)$ it suddenly displayed properly.

Related

How to make a plot that connect its points to its closest neighbors?

I am working on a code to project a given object onto a plane.
The code works fine (at least it seems like it) in achieving that purpose, the only issue I'm having is in plotting my results.
In the image below, for instance, I'm plotting the projection of a parallelepiped (its edges, to be more precise) in a plane of my choice.
I would like to make a plot where each point is connected to its closest neighbor. I'm not very confident that this approach would get the job done, but I think it would be worth the shot.
Different ideas to get there are also welcome!
Any thoughts?
Thanks in advance.
Note: I also tried using a solid line style when plotting as opposed to the pixel marker style, but the result I got was not quite what I expected to say the least:
When telling matplotlib to plot a sequence of points and join them with a line, it creates a straight line between two adjacent points in your input data. To create several lines, it's often easier to split your plot command into several ones. An alternative is to arrange your points such that they form the edges you want, but that would be much more complicated in your case.
As discussed in the comments, separating each edge into its own separate plot command worked for your case.

Bokeh, Python: Dashed line becomes solid when zooming in

I'm plotting two lines, one solid, one dashed. At the initial zoom the lines appear as defined. However, when zooming into the plot the dashed line becomes solid. The pictures below illustrate the problem. Here is the code that defines the lines:
turbidity_stn3_plot1 = f.line(x='Datetime',y='Turbidity', y_range_name='default', color='olive',line_color='black', line_dash=[1,10], line_width=1, source=turbidity_stn_03_plot_01_source)
turbidity_stn1_plot1 = f.line(x='Datetime',y='Turbidity', y_range_name='default', color='olive',line_color='black', line_dash='solid', source=turbidity_stn_01_plot_01_source)
I already tried different 'line_dash' values, like 'dashed' and 'dotted' with the same result.
I noticed that, when increasing the distance between dashes (e.g. 'line_dash=[1,20]'), the closer I can zoom in before the line turns solid.
Does anybody know why this is and how to avoid it?
Should I report this as a bug on Bokeh Github?
This is a result of browser-dependent behavior of HTML canvas implementations. There is nothing that the Bokeh project can do about it (which is why the GH issue was eventually closed). If you are working in regimes where this issue shows up, the only alternative is to use other visual properties, e.g. width or color, instead of dashing.

matplotlib shows different figure than saves from the show() window

I plot rather complex data with matplotlib's imshow(), so I prefer to first visually inspect if it is all right, before saving. So I usually call plt.show(), see if it is fine, and then manually save it with a GUI dialog in the show() window. And everything was always fine, but recently I started getting a weird thing. When I save the figure I get a very wrong picture, though it looks perfectly fine in the matplotlib's interactive window.
If I zoom to a specific location and then save what I see, I get a fine figure.
So, this is the correct one (a small area of the picture, saved with zooming first):
And this one is a zoom into approximately the same area of the figure, after I saved it all:
For some reason pixels in the second one are much bigger! That is vary bad for me - as you can see, it looses a lot of details in there.
Unfortunately, my code is quite complicated and I wasn't able to reproduce it with some randomly generated data. This problem appeared after I started to plot two triangles of the picture separately: I read my two huge data files with np.loadtxt(), get np.triu(data1) and np.tril(data2), mask zeroes, NAs, -inf and +inf and then plot them on the same axes with plt.imshow(data, interpolation='none', origin='lower', extent=extent). I do lot's of other different things to make it nicer, but I guess it doesn't matter, because it all worked like a charm before.
Please, let me know, if you need to know anything else specific from my code, that could be relevant to this problem.
When you save a figure in png/jpg you are forced to rasterize it, convert it to a finite number of pixels. If you want to keep the full resolution, you have a few options:
Use a very high dpi parameter, like 900. Saving the plot will be slow, and many image viewers will take some time to open it, but the information is there and you can always crop it.
Save the image data, the exact numbers you used to make the plot. Whenever you need to inspect it, load it in Matplotlib in interactive mode, navigate to your desired corner, and save it.
Use SVG: it is a vector graphics format, so you are not limited to pixels.
Here is how to use SVG:
import matplotlib
matplotlib.use('SVG')
import matplotlib.pyplot as plt
# Generate the image
plt.imshow(image, interpolation='none')
plt.savefig('output_image')
Edit:
To save a true SVG you need to use the SVG backend from the beginning, which is unfortunately, incompatible with interactive mode. Some backends, like GTKCairo seem to allow both, but the result is still rasterized, not a true SVG.
This may be a bug in matplotlib, at least, to the best of my knowledge, it is not documented.

Need to add a "legend" to an arrow/contour plot

I am plotting some scalar data as a contour plot with matplotlib.contourf. On top of it, I am plotting some vector data with matplotlib.arrow. The basic plot has come along OK, but now I need to put a box on the plot with a default-size arrow plus the data value to which it corresponds, so the viewer will know what kind of scale he is looking at. For instance, I need a box with a horizontal arrow of some length and, below that, some text like "10 cm/sec".
First, if anyone can give me a simple approach to this, I would be grateful.
Second, the approach I have tried is to do the contour plot, then plot the arrows, then add a rectangle to the plot like so:
rect=pl.Rectangle((300,70),15,15,fc='white')
pl.gca().add_patch(rect)
and then, finally, put my scale arrow and text on top of this rectangle.
This isn't working because the rectangle patch covers up the contour, but it doesn't cover up the arrows in the plot. Is there a way to move the patch completely "to the front" of everything else?
Got it. Using pylab.quiver and pylab.quiverkey functions. quiver produces a nice vector field with just a few lines of code, and quiverkey makes it easy to produce a scaling vector with text. And, for some reason, the arrows plotted with quiver are indeed covered by my rectangle, so it is easy to make the scaling arrow very visible. There are still some mysteries in all of this for me. If anyone wants to try to clear them up, would be much obliged. But I have a way now to do what I need in this instance.

On adjusting margins in matplotlib

I am trying to minimize margins around a 1X2 figure, a figure which are two stacked subplots. I searched a lot and came up with commands like:
self.figure.subplots_adjust(left=0.01, bottom=0.01, top=0.99, right=0.99)
Which leaves a large gap on top and between the subplots. Playing with these parameters, much less understanding them was tough (things like ValueError: bottom cannot be >= top)
My questions :
What is the command to completely minimize the margins?
What do these numbers mean, and what coordinate system does this follow (the non-standard percent thing and origin point of this coordinate system)? What are the special rules on top of this coordinate system?
Where is the exact point this command needs to be called? From experiment, I figured out it works after you create subplots. What if you need to call it repeatedly after you resize a window and need to resize the figure to fit inside?
What are the other methods of adjusting layouts, especially for a single subplot?
They're in figure coordinates: http://matplotlib.sourceforge.net/users/transforms_tutorial.html
To remove gaps between subplots, use the wspace and hspace keywords to subplots_adjust.
If you want to have things adjusted automatically, have a look at tight_layout
Gridspec: http://matplotlib.sourceforge.net/users/gridspec.html

Categories