How do I let my matplotlib plot go beyond the axes? - python

I have to translate an image plotting script from matlab to matplotlib/pylab, and I'm trying to achieve the same effect as the matlab image below:
As you can see, the z order of the plots seem to be higher than the z order of the grid, so the markers are not hidden by the axes. However, I can't figure out a way to do the same with my matplotlib image:
I'm wondering if it is possible to get the same display without having to increase the limits of the y axis.

To get the marker to show beyond the axes you can turn the clipping off. This can be done using the keyword argument in the plot command clip_on=False.
For example:
import matplotlib.pyplot as plt
plt.plot(range(5), range(5), 'ro', markersize=20, clip_on=False, zorder=100)
plt.show()

This is a complete example of how to use the zorder kwarg: http://matplotlib.sourceforge.net/examples/pylab_examples/zorder_demo.html
Note that a higher z-order equates to a graph-element being more in the foreground.
For your second question, have a look at the figsize kwarg to instances of the Figure class: http://matplotlib.sourceforge.net/api/figure_api.html?highlight=figsize#matplotlib.figure.Figure
If you run into issues, please post some of your code and we'll be able to give more-detailed recommendations. Best of luck.

If you're plotting the lines one after the other, just change the order of the plotting calls and that would fix the z order.

Related

How do I use matplotlib to create a bar chart of a very large dataset?

The data I am working with is an array 27,000 elements long which is a histogram of a few million data points but what I have is the histogram and I need to plot it in my program, preferably with vertical bars.
I've tried using the 'bar' function in matplotlib but this takes a minute or two to plot whereas using just regular plot (with just points on the chart) is almost immediate but obviously does not achieve the effect I want (i.e. bars). I'm not sure why the bar function is so much slower so I was wondering if there was a more effective way to plot a histogram with vertical bars using matplotlib?
I've looked at the hist function with matplotlib but it's purpose to my understanding is to take data, make a histogram, and then plot it but I already have a histogram so I don't believe it works for my case. I greatly appreciate any help!
Here's a reference to the hist function documentation, maybe I missed something.
https://matplotlib.org/3.2.0/api/_as_gen/matplotlib.pyplot.hist.html
Thanks in advance! Let me know if you would like an example of the code I am working with but it is just your most generic my_axes.plot(my_data) or my_axes.bar(my_data) so I'm not sure how helpful it would be.
I've taken a look at this as well now: https://gist.github.com/pierdom/d639a1d3b8934ee31db8b2ab9997ae92.
This also works but has the same time issue as using bar so I suppose this is just an issue with rendering a lot of vertical bars? (though I still wonder why rendering 27000 points happens so quickly)
Apparently, this is a known and discussed limitation of the bar graph as it is currently implemented. See this issue and this discussion. Though there are questions about it's usefulness, in my particular case I have a toolbar across the top that allows the user to zoom in and move around the data set (which is very practical method for my use case).
However, a great alternative does exist in the form of stairs. Simply use fill and you have an effective bar graph, that is much more performant.
import matplotlib.pyplot as plt
import random
bins = range(27001) # Note that bins needs to be one greater then heights
heights = [random.randint(0, i) for i in range(27000)]
ax = plt.gca()
ax.stairs(heights, bins, fill=True)
plt.show()
matplotlib's bar should be pretty fast to execute so I'm guessing you're passing all the data points to it (although you mention you have "histogram data", so if you can provide more details on the format, that'd help).
bar takes the x positions for the bars and the heights, so if you want the bar function to produce a histogram you need to bin and count.
This will produce something similar to matplotlib's hist:
import matplotlib.pyplot as plt
bins = [0, 1, 2, 3]
heights = [1, 2, 3, 4]
ax = plt.gca()
ax.bar(bins, heights, align='center', width=1)

Matplotlib arrow in loglog plot

I'm trying to draw an arrow into a loglog plot with matplotlib, which looks like this:
I know that it has been suggested to turn off the axis (Matplotlib: Draw a vertical arrow in a log-log plot), but I do need the axes. In addition, the suggestion did not seem to change anything (apart from turning the axes off, as expected):
plt.figure();plt.loglog([1,10,60],[1,0.1,0.005])
plt.axis('off')
plt.arrow(2,0.002,5,0.098,'k',head_length=0.3)
My work around so far has been to create an invisible inset (meaning: axes off) with a linear axes environment and plot the arrow in the inset, which works but is really a bit unpleasant. Is there a simpler way? Or do people recommend to add these type of additional features with eg. inkscape, after the main plot is done?
You can use plt.annotate rather than plt.arrow. This is noted in the documentation for plt.arrow:
The resulting arrow is affected by the axes aspect ratio and limits.
This may produce an arrow whose head is not square with its stem. To
create an arrow whose head is square with its stem, use annotate()
For example:
import matplotlib.pyplot as plt
plt.figure()
plt.loglog([1,10,60],[1,0.1,0.005])
plt.annotate('', xy=(5, 0.098), xytext=(2, 0.002),
arrowprops=dict(facecolor='black', shrink=0.),
)
plt.ylim(0.001, 10)
plt.show()
Note that you may need to adjust the axes limits to fit the arrow into the plot. Here I had to change ylim.

creating a chart with high/low and percentile box plus other points

Hi I'd like to recreate the following plot with matplotlib and pandas.
I started to use boxplot but i'm struggling to manipulate the kwargs.
Is there a simple way to use boxplot or do I need to recreate the chart enitrely.
One issue I had was also adding the current data?
Best regards
The boxplot from matplotlib has indeed some limitations. For you to have full control over how the plot looks I would advise using Patches to draw Rectangles for example (code from Rectangles link):
import matplotlib.pyplot as plt
import matplotlib.patches as patches
fig1 = plt.figure()
ax1 = fig1.add_subplot(111, aspect='equal')
ax1.add_patch(
patches.Rectangle(
(0.1, 0.1), # (x,y)
0.5, # width
0.5, # height
)
)
fig1.savefig('rect1.png', dpi=90, bbox_inches='tight')
This is useful because you'll only need this and a normal plot command (for lines) in matplotlib to do a boxplot. This will give you immense control about color and shape and it's fairly easy to build. You also have text there you'll need for which you can use matplotlib text. The last thing are those markers which are very doable with a scatter.
A boxplot is a shape that tells you information such a minimum, maximum, and percentiles (25,50,75). You can calculate this very easily with numpy percentile.
The details of the plot (labels at the bottom, legend, title in box, and so on) can also be achieved but tinkering with labels, manually building a title box and so on.
It will give you some work but these are the commands you need.

Matplotlib offset errorbar bug workaround?

The bug is documented here:
Matplotlib errorbar not centered on marker
and here:
https://github.com/matplotlib/matplotlib/issues/3400
Basically, the markers are plotted off by 1 pixel all the time.. You can even see this on Matplotlib's own tutorial page if you look closely at the second plot: http://matplotlib.org/1.2.1/examples/pylab_examples/errorbar_demo.html
This is very frustrating as I cannot produce publication-quality plots from matplotlib, and I'm very surprised this has not been fixed.
In any case, I have too much time and code invested into matplotlib to switch to a different package. So my question is how would you go about making a workaround? I suppose one solution is to plot the markers 1 pixel to the left/right from the errorbars. I don't know how to do this. I figured out how to get the display coordinates of my plot points, but how can I make an interactive plot that preserves the 1-pixel offset? I can plot them with 1-pixel offsets, but then you can't zoom or manipulate the plot.
It seems like the Matplotlib team have fixed the issue when calling savefig() using .svg or .pdf, but for .png I've found that you can circumvent this issue by using an odd number for the error line thickness. Using the first example on the Matplotlib tutorial, if we use
plt.errorbar(x, y, yerr=0.4, marker='X', markersize=15)
then the bars are offset like this:
However if we use a line width of 3
plt.errorbar(x, y, yerr=0.4, marker='X', markersize=15, elinewidth=3)
then the bars are centred like this:
This isn't a perfect solution, but it does the job if you don't mind having slightly thicker lines.

imshow in subplot with interactive mode

I cannot get matshow() or imshow() to actually display the plot when both of the following conditions are true: (1) interactive mode is on: import matplotlib.pyplot as plot; plot.ion(), and (2) I am trying to use matshow on a specific subplot: fig = plot.figure(); ax = fig.add_subplot(111); ax.matshow([[1,2],[3,0]]).
Using plot.matshow([[1,2],[3,0]]) (note: no explicit axes) works find in interactive mode, but will always create a new figure window with a single axes object. The above code with the subplot also works fine without interactive mode using plot.show(), and will put the image on the correct axes.
More oddly, the above code with the subplot will show the image if I interact with the figure, such as by using the zoom tool and clicking randomly in the figure window (there is no visible axes object, but I just click somewhere in the middle of the figure window).
Any ideas what might be causing this, how I could fix it, or how I could get around it to use matshow or imshow on a specified subplot (the end use case is to have more than 1 subplot in the figure)? This occurs in python (2.7.6) and ipython (1.1.1)
This may have something to do with this documentation:
Display an array as a matrix in a new figure window.
However, you may as well use imshow with suitable arguments:
import matplotlib.pyplot as plt
plt.imshow(mat, interpolation='nearest', origin='upper', aspect='equal')
This should do the same thing while being a bit less odd. This is actually exactly what matshow does internally. It just adds a few tick markers to the image.
Also, by having a look at the source (or closely reading the help string), you may try to do:
plt.matshow(mat, fignum=0)
This should force it use current axis, which it picks by using gca.
In addition to this, there is ax.matshow which you used, as well. Actually plt.matshow is a very thin wrapper around ax.matshow, mostly to create the new image.
If you still have problems with matshow or imshow in subplots, please make a minimal complete example for us to try! Here is something I tried in the interactive shell (IPython):
figure()
ax = subplot(121)
ax2 = subplot(122)
ax.matshow(random.random((20,30)))
ax2.plot(linspace(-1,1,100), linspace(-1,1,100)**2)
draw()
(Could the problem be a missing draw?)
What I got:

Categories

Resources