This question already has answers here:
How to highlight specific x-value ranges
(2 answers)
Closed 1 year ago.
I went through the examples in the matplotlib documentation, but it wasn't clear to me how I can make a plot that fills the area between two specific vertical lines.
For example, say I want to create a plot between x=0.2 and x=4 (for the full y range of the plot). Should I use fill_between, fill or fill_betweenx?
Can I use the where condition for this?
It sounds like you want axvspan, rather than one of the fill between functions. The differences is that axvspan (and axhspan) will fill up the entire y (or x) extent of the plot regardless of how you zoom.
For example, let's use axvspan to highlight the x-region between 8 and 14:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot(range(20))
ax.axvspan(8, 14, alpha=0.5, color='red')
plt.show()
You could use fill_betweenx to do this, but the extents (both x and y) of the rectangle would be in data coordinates. With axvspan, the y-extents of the rectangle default to 0 and 1 and are in axes coordinates (in other words, percentages of the height of the plot).
To illustrate this, let's make the rectangle extend from 10% to 90% of the height (instead of taking up the full extent). Try zooming or panning, and notice that the y-extents say fixed in display space, while the x-extents move with the zoom/pan:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot(range(20))
ax.axvspan(8, 14, ymin=0.1, ymax=0.9, alpha=0.5, color='red')
plt.show()
Related
This question already has an answer here:
Inconsistent figsize resizing in matplotlib
(1 answer)
Closed 3 years ago.
I am trying to generate a bar chart with lots of bars. If I keep the figsize at defaults, the data is squeezed together and the plot is unusable.
I have the following code snippet to reproduce my problem:
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(1)
ax = fig.add_subplot(111)
N=100
# Example data
labels = [chr(x) for x in range(N)]
y_pos = np.arange(len(labels))
performance = 3 + 10 * np.random.rand(len(labels))
error = np.random.rand(len(labels))
ax.barh(y_pos, performance, xerr=error, align='center')
ax.set_yticks(y_pos)
ax.set_yticklabels(labels)
ax.set_xlabel('Performance')
ax.set_title('How fast do you want to go today?')
plt.savefig('a.png', bbox_inches='tight')
plt.show()
If I manually set the height of the figure (for example figsize=(8,N*0.2)), the plotted data looks nice, but there is an annoying vertical whitespace before the firs bar and after the last one.
Is there any way to automatically size the plot properly?
One thing I've used is
plt.tight_layout()
it generates less whitespace for subplots, but may work with just 1 plot.
Here's more info:
https://matplotlib.org/users/tight_layout_guide.html
Another thing that may work is aspect auto when showing the plot.
plt.imshow(X, aspect='auto')
Yet another solution is 'scaled' axis
plt.axis('scaled') #this line fits your images to screen
Also if you mean the overall plot size,I generally just pick a generic size that fits, say 15 x 10 on a laptop screen, or 30x20 on a monitor. Guess and test.
I want to draw Grid of Bar graph/Histogram for my data.My Data contains 1 NUMERIC and 3 CATEGORICAL Column
PAIRGraph is not suitable for my purpose as my purpose as I have only 1 Numeric and 3 Categorical Column
Tried to Refer Documentation https://matplotlib.org/api/_as_gen/matplotlib.pyplot.subplots.html
However, I am unable to find exact way to fulfill my requirement.
Using Demo code I am able to draw only LineGraph. However, I am required to draw Bar Graph.
fig, axes = plt.subplots(1, 2, figsize=(10,4))
x = np.linspace(0, 5, 11)
axes[0].plot(x, x**2, x, np.exp(x),x,20*x)
axes[0].set_title("Normal scale")
axes[0].plot
axes[1].plot(x, x**2, x, np.exp(x))
axes[1].set_yscale("log")
axes[1].set_title("Logarithmic scale (y)");
Please feel free to correct my approach or guide me as I have just started learning.
If you specify exactly what you want to use for the bar and hist, I can modify, but generally it is simply changing the plot to the type of chart you need
import matplotlib.pyplot as plt
import numpy as np
fig, axes = plt.subplots(1, 2, figsize=(10,4))
x = np.linspace(0, 5, 11)
axes[0].bar(x,x**2) # bar plot
axes[0].set_title("Normal scale")
axes[0].plot
axes[1].hist(x) # histogram
axes[1].set_yscale("log")
axes[1].set_title("Logarithmic scale (y)");
plt.show()
After going through the API documentation from Matplotlip Subplot Axes, I found ways to draw different graph not just Line graph.
https://matplotlib.org/api/axes_api.html
DEFAULT:-
axes[0].plot by-default draws line graph.
CUSTOM GRAPH:-
axes[0].bar can be used to draw BAR graph in selected Subplot
axes[0].scatter can be used to draw Scatter graph in selected Subplot
axes[0].hist can be used to draw a histogram. in selected Subplot
Like above example more graph can be drawn with below API:-
What I'm trying to achieve: a plot with two axhline horizontal lines, with the area between them shaded.
The best so far:
ax.hline(y1, color=c)
ax.hline(y2, color=c)
ax.fill_between(ax.get_xlim(), y1, y2, color=c, alpha=0.5)
The problem is that this leaves a small amount of blank space to the left and right of the shaded area.
I understand that this is likely due to the plot creating a margin around the used/data area of the plot. So, how do I get the fill_between to actually cover the entire plot without matplotlib rescaling the x-axis after drawing? Is there an alternative to get_xlim that would give me appropriate limits of the plot, or an alternative to fill_between?
This is the current result:
Note that this is part of a larger grid layout with several plots, but they all leave a similar margin around these shaded areas.
Not strictly speaking an answer to the question of getting the outer limits, but it does solve the problem. Instead of using fill_between, I should have used:
ax.axhspan(y1, y2, facecolor=c, alpha=0.5)
Result:
ax.get_xlim() does return the limits of the axis, not that of the data:
Axes.get_xlim()
Returns the current x-axis limits as the tuple (left, right).
But Matplotlib simply rescales the x-axis after drawing the fill_between:
import matplotlib.pylab as pl
import numpy as np
pl.figure()
ax=pl.subplot(111)
pl.plot(np.random.random(10))
print(ax.get_xlim())
pl.fill_between(ax.get_xlim(), 0.5, 1)
print(ax.get_xlim())
This results in:
(-0.45000000000000001, 9.4499999999999993)
(-0.94499999999999995, 9.9449999999999985)
If you don't want to manually set the x-limits, you could use something like:
import matplotlib.pylab as pl
import numpy as np
pl.figure()
ax=pl.subplot(111)
pl.plot(np.random.random(10))
xlim = ax.get_xlim()
pl.fill_between(xlim, 0.5, 1)
ax.set_xlim(xlim)
What I would like to achive are plots with equal scale aspect ratio, and fixed width, but a dynamically chosen height.
To make this more concrete, consider the following plotting example:
import matplotlib as mpl
import matplotlib.pyplot as plt
def example_figure(slope):
# Create a new figure
fig = plt.figure()
ax = fig.add_subplot(111)
# Set axes to equal aspect ratio
ax.set_aspect('equal')
# Plot a line with a given slope,
# starting from the origin
ax.plot([x * slope for x in range(5)])
# Output the result
return fig
This example code will result in figures of different widths, depending on the data:
example_figure(1).show()
example_figure(2).show()
Matplotlib seems to fit the plots into a certain height, and then chooses the width to accomodate the aspect ratio. The ideal outcome for me would be the opposite -- the two plots above would have the same width, but the second plot would be twice as tall as the first.
Bonus — Difficulty level: Gridspec
In the long run, I would like to create a grid in which one of the plots has a fixed aspect ratio, and I would again like to align the graphs exactly.
# Create a 2x1 grid
import matplotlib.gridspec as gridspec
gs = gridspec.GridSpec(2, 1)
# Create the overall graphic, containing
# the top and bottom figures
fig = plt.figure()
ax1 = fig.add_subplot(gs[0, :], aspect='equal')
ax2 = fig.add_subplot(gs[1, :])
# Plot the lines as before
ax1.plot(range(5))
ax2.plot(range(5))
# Show the figure
fig.show()
The result is this:
So again, my question is: How does one create graphs that vary flexibly in height depending on the data, while having a fixed width?
Two points to avoid potential misunderstandings:
In the above example, both graphs have the same x-axis. This cannot be
taken for granted.
I am aware of the height_ratios option in the gridspec. I can compute
the dimensions of the data, and set the ratios, but this unfortunately
does not control the graphs directly, but rather their bounding boxes,
so (depending on the axis labels), graphs of different widths still occur.
Ideally, the plots' canvas would be aligned exactly.
Another unsolved question is similar, but slightly more convoluted.
Any ideas and suggestions are very welcome, and I'm happy to specify the question further, if required. Thank you very much for considering this!
Have you tried to fix the width with fig.set_figwidth()?
I'm drawing the bloxplot shown below using python and matplotlib. Is there any way I can reduce the distance between the two boxplots on the X axis?
This is the code that I'm using to get the figure above:
import matplotlib.pyplot as plt
from matplotlib import rcParams
rcParams['ytick.direction'] = 'out'
rcParams['xtick.direction'] = 'out'
fig = plt.figure()
xlabels = ["CG", "EG"]
ax = fig.add_subplot(111)
ax.boxplot([values_cg, values_eg])
ax.set_xticks(np.arange(len(xlabels))+1)
ax.set_xticklabels(xlabels, rotation=45, ha='right')
fig.subplots_adjust(bottom=0.3)
ylabels = yticks = np.linspace(0, 20, 5)
ax.set_yticks(yticks)
ax.set_yticklabels(ylabels)
ax.tick_params(axis='x', pad=10)
ax.tick_params(axis='y', pad=10)
plt.savefig(os.path.join(output_dir, "output.pdf"))
And this is an example closer to what I'd like to get visually (although I wouldn't mind if the boxplots were even a bit closer to each other):
You can either change the aspect ratio of plot or use the widths kwarg (doc) as such:
ax.boxplot([values_cg, values_eg], widths=1)
to make the boxes wider.
Try changing the aspect ratio using
ax.set_aspect(1.5) # or some other float
The larger then number, the narrower (and taller) the plot should be:
a circle will be stretched such that the height is num times the width. aspect=1 is the same as aspect=’equal’.
http://matplotlib.org/api/axes_api.html#matplotlib.axes.Axes.set_aspect
When your code writes:
ax.set_xticks(np.arange(len(xlabels))+1)
You're putting the first box plot on 0 and the second one on 1 (event though you change the tick labels afterwards), just like in the second, "wanted" example you gave they are set on 1,2,3.
So i think an alternative solution would be to play with the xticks position and the xlim of the plot.
for example using
ax.set_xlim(-1.5,2.5)
would place them closer.
positions : array-like, optional
Sets the positions of the boxes. The ticks and limits are automatically set to match the positions. Defaults to range(1, N+1) where N is the number of boxes to be drawn.
https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.pyplot.boxplot.html
This should do the job!
As #Stevie mentioned, you can use the positions kwarg (doc) to manually set the x-coordinates of the boxes:
ax.boxplot([values_cg, values_eg], positions=[1, 1.3])