Making plot less crowded in Matplotlib - python

I have made a error-bar plot using matplotlib but it is too crowded to see everything without zooming in. I can of course do this but when I save the plot I can only save the zoomed in bit and lose the rest of the data.
Is there a way to get a scrollable plot with matplotlib so that when I save it as a png everything is included or any other format such that no data is lost? Essentially I would like the length of the plot to be much greater than the width.
The code I used to plot is:
plot1_dataerr = get_plot_data_errbars(processed_answers[0][plot_low:]) #the data to be plotted, the zeroth element of this is the labels, the first is the means and the second is the errorbar size
fig, axs = plt.subplots()
fig.subplots_adjust(left=0.2)
axs.set_xlim([1,5])
axs.grid()
axs.errorbar(plot1_dataerr[1],range(len(plot1_dataerr[1])),xerr = plot1_dataerr[2], fmt = 'k o')
axs.yaxis.set_ticks(np.arange(len(plot1_dataerr[1])))
axs.set_yticklabels(plot1_dataerr[0])
And here is the plot I am getting, as you can see it is very crowded and unclear:

You may increase the size of the plot
plt.subplots(figsize=(18,10))
This of course has a limitation for showing the plot on the screen. So you may as well or additionally, decrease the dots per inch,
plt.subplots(figsize=(36,20), dpi=50)
Then saving the plot in a vector format like pdf will allow you not to loose any details in the saved figure.
You may also keep the dpi, increase the figuresize and finally show your plot in a window with scrollbars. This is shown e.g. in the question Scrollbar on Matplotlib showing page

You can specify a bigger figure size in the subplots() constructor.
fig, axs = plt.subplots(figsize=(w, h))
Where w and h are the width and height in inches.

Related

How do I reduce chart size so that long axis text can be totally seen?

See how the x axis text falls out of the image? I could reduce the size of the labels, but I'd rather reduce the size of the chart. How do I do that?
I've tried adjusting x and y for fig, ax = plt.subplots(figsize=(x,y)), and also tried plt.figure(figsize(x,y))
but all they seem to do is change the window size that pops up when I run the script. When I maximize out the window I get the same problem.
I've played with plt.margins(x) but that changes the margins inside of the chart when I want to change the chart itself.
Figured it out.
I needed to add
plt.tight_layout()
and then adjust x and y in
fig=plt.figuresize(x,y)

Problem updating imshow in loop and colormap after loop

I have two imshow() problems that I suspect are closely related.
First, I can't figure out how to use set_data() to update an image I've created with imshow().
Second, I can't figure out why the colorbar I add to the imshow() plot after I'm done updating the plot doesn't match the colorbar I add to an imshow() plot of the same data that I create from scratch after I'm done taking data. The colorbar of the second plot appears to be correct.
Background.
I'm collecting measurement data in two nested loops, with each loop controlling one of the measurement conditions. I'm using pyplot.imshow() to plot my results, and I'm updating the imshow() plot every time I take data in the inner loop.
What I have works in terms of updating the imshow() plot but it seems to be getting increasingly slower as I add more loop iterations, so it's not scaling well. (The program I've included in with this post creates a plot that is eight rows high and six columns wide. A "real" plot might be 10x or 20x this size, in both dimensions.)
I think what I want to do is use the image's set_data() method but I can't figure out how. What I've tried either throws an error or doesn't appear to have any effect on the imshow() plot.
Once I'm done with the "take the data" loops, I add a colorbar to the imshow() plot I've been updating. However, the colorbar scale is obviously bogus.
In contrast, if I take create an entirely new imshow() plot, using the data I took in the loops, and then add a colorbar, the colorbar appears to be correct.
My hunch is the problem is with the vmin and vmax values associated with the imshow() plot I'm updating in the loops but I can't figure out how to fix it.
I've already looked at several related StackOverflow posts. For example:
update a figure made with imshow(), contour() and quiver()
Update matplotlib image in a function
How to update matplotlib's imshow() window interactively?
These have helped, in that they've pointed me to set_data() and given me solutions to some other
problems I had, but I still have the two problems I mentioned at the start.
Here's a simplified version of my code. Note that there are repeated zero values on the X and Y axes. This is on purpose.
I'm running Python 3.5.1, matplotlib 1.5.1, and numpy 1.10.4. (Yes, some of these are quite old. Corporate IT reasons.)
import numpy as np
import matplotlib.pyplot as plt
import random
import time
import warnings
warnings.filterwarnings("ignore", ".*GUI is implemented.*") # Filter out bogus matplotlib warning.
# Create the simulated data for plotting
v_max = 120
v_step_size = 40
h_max = 50
h_step_size = 25
scale = 8
v_points = np.arange(-1*abs(v_max), 0, abs(v_step_size))
v_points = np.append(v_points, [-0.0])
reversed_v_points = -1 * v_points[::-1] # Not just reverse order, but reversed sign
v_points = np.append(v_points, reversed_v_points)
h_points = np.arange(-1*abs(h_max), 0, abs(h_step_size))
h_points = np.append(h_points, [-0.0])
reversed_h_points = -1 * h_points[::-1] # Not just reverse order, but reversed sign
h_points = np.append(h_points, reversed_h_points)
h = 0 # Initialize
v = 0 # Initialize
plt.ion() # Turn on interactive mode.
fig, ax = plt.subplots() # So I have access to the figure and the axes of the plot.
# Initialize the data_points
data_points = np.zeros((v_points.size, h_points.size))
im = ax.imshow(data_points, cmap='hot', interpolation='nearest') # Specify the color map and interpolation
ax.set_title('Dummy title for initial plot')
# Set up the X-axis ticks and label them
ax.set_xticks(np.arange(len(h_points)))
ax.set_xticklabels(h_points)
ax.set_xlabel('Horizontal axis measurement values')
# Set up the Y-axis ticks and label them
ax.set_yticks(np.arange(len(v_points)))
ax.set_yticklabels(v_points)
ax.set_ylabel('Vertical axis measurement values')
plt.pause(0.0001) # In interactive mode, need a small delay to get the plot to appear
plt.show()
for v, v_value in enumerate(v_points):
for h, h_value in enumerate(h_points):
# Measurement goes here.
time.sleep(0.1) # Simulate the measurement delay.
measured_value = scale * random.uniform(0.0, 1.0) # Create simulated data
data_points[v][h] = measured_value # Update data_points with the simulated data
# Update the heat map with the latest point.
# - I *think* I want to use im.set_data() here, not ax.imshow(), but how?
ax.imshow(data_points, cmap='hot', interpolation='nearest') # Specify the color map and interpolation
plt.pause(0.0001) # In interactive mode, need a small delay to get the plot to appear
plt.draw()
# Create a colorbar
# - Except the colorbar here is wrong. It goes from -0.10 to +0.10 instead
# of matching the colorbar in the second imshow() plot, which goes from
# 0.0 to "scale". Why?
cbar = ax.figure.colorbar(im, ax=ax)
cbar.ax.set_ylabel('Default heatmap colorbar label')
plt.pause(0.0001) # In interactive mode, need a small delay to get the colorbar to appear
plt.show()
fig2, ax2 = plt.subplots() # So I have access to the figure and the axes of the plot.
im = ax2.imshow(data_points, cmap='hot', interpolation='nearest') # Specify the color map and interpolation
ax2.set_title('Dummy title for plot with pseudo-data')
# Set up the X-axis ticks and label them
ax2.set_xticks(np.arange(len(h_points)))
ax2.set_xticklabels(h_points)
ax2.set_xlabel('Horizontal axis measurement values')
# Set up the Y-axis ticks and label them
ax2.set_yticks(np.arange(len(v_points)))
ax2.set_yticklabels(v_points)
ax2.set_ylabel('Vertical axis measurement values')
# Create a colorbar
cbar = ax2.figure.colorbar(im, ax=ax2)
cbar.ax.set_ylabel('Default heatmap colorbar label')
plt.pause(0.0001) # In interactive mode, need a small delay to get the plot to appear
plt.show()
dummy = input("In interactive mode, press the Enter key when you're done with the plots.")
OK, I Googled some more. More importantly, I Googled smarter and figured out my own answer.
To update my plot inside my nested loops, I was using the command:
ax.imshow(data_points, cmap='hot', interpolation='nearest') # Specify the color map and interpolation
What I tried using to update my plot more efficiently was:
im.set_data(data_points)
What I should have used was:
im.set_data(data_points)
im.autoscale()
This updates the pixel scaling, which fixed both my "plot doesn't update" problem and my "colorbar has the wrong scale" problem.

How do I position the axis frame inside a figure without changing the size of the figure? [Python, matplotlib]

I'm trying to create a video of many figures, so I need the axis to remain steady across multiple, independent figures. However, the y-axis changes scale, so the framing of the axis keeps moving as the ticklabels change. I'm trying to manually tell matplotlib exactly what size the whole figure should be and tell it exactly the position of the axis within the figure, but it's not working properly.
Here's what a base figure looks like:
import matplotlib.pyplot as plt
fig=plt.figure(figsize=(8,4),facecolor=(0.5,0.5,0.5))
ax=fig.add_subplot()
ax.plot([5,10],[800,900])
plt.show()
Here is one way for how I'm trying to change it if I want the axis frame to start at left=0.5, bottom=0.5, width=0.2, and height=0.2. I've tried many different ways, and all have failed, so this is illustrative of what I'm trying to do:
fig=plt.figure(figsize=(8,4),facecolor=(0.5,0.5,0.5))
ax=fig.add_axes((0.5,0.5,0.2,0.2))
ax.plot([5,10],[800,900])
plt.show()
Now, I want it to look more like this so that the black box of the axis frame will be in the exact same position for every figure, and each figure will be the exact same size. That way, when I make it an animation, the black frame won't be jerking around. (Obviously, I wouldn't make the buffer that big in the real video.)
You need to use ax.set_position.
If your ax box initially occupies the full figure, you can create a new size relatively to the old one, for example:
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(8, 4), facecolor=(0.5, 0.5, 0.5))
ax = fig.add_subplot(111)
bbox = ax.get_position()
new_bbox = (bbox.x0+0.40, bbox.y0+0.40, bbox.width*0.5, bbox.height*0.5)
ax.set_position(new_bbox)
ax.plot([5, 10], [800, 900])
plt.show()

Changing canvas size dynamically

I want to plot multiple time-series (each time-series in its own plot) using the plot()-method of matplotlib.
X-Axis: Time
Y-Axis: Parameter-Value
As the time-series have different lengths, I want to resize the canvas along the X-Axis dynamically, so that the time-series do not get stretched/compressed dependent on their total length. The size of the whole figure should stay the same, independent of the time-series-length. I know how to modify the figure size using
rcParams['figure.figsize'] = width, height
but I do only want to modify the canvas size (the part of the figure where the time-series is actually plotted in). Is there a similar way of just changing the figure's canvas?
I think you want to change the dimensions of the axes that your time-series is being plotted in, rather than the dimensions of the figure canvas (which as far as I'm aware can't be altered without changing the overall figure size).
You can do this using ax.set_position(), which takes a tuple of (left, bottom, width, height) values in normalized canvas coordinates between 0 and 1.
from pylab import *
nr = 4
nc = 1
fig,axes = subplots(nr,nc,sharex=True)
The sharex keyword tells the subplots to keep their x limits the same. Replace plot in your application with axes[ith index].plot, etc.

Matplotlib: make x-axis longer

In Matplotlib I need to draw a graph with points on the x-axis on each integer between 1 and 5000 and on the y-axis only in a very limited range.
Matplotlib automatically compacts everything to let all the data fit on a (landscape) page. In my case I would like the x-axis to be as large as possible so that all points are clearly visible. Right now there's just a thick coloured line as opposed to scattered points.
How can I do this?
(I'm saving to pdf, if that helps)
You can always try to specify the dimensions (in inches) of the figure you are creating. Something along the following line might help:
fig = plt.figure(figsize=(20, 2))
ax = fig.add_subplot(111)
ax.plot(x, y)
The figsize takes a tuple of width, height in inches.

Categories