Here is the instruction:
a string "fig_type", which is one of the two values: "single" or "subplots".
The input argument "fig_type" determines how to draw the plots:
if "fig_type" is "single", you should produce one set of axes, draw all the plots together in the same axes, and differentiate them e.g. by line or marker colour or style.
if "fig_type" is "subplots", you should produce 𝑟
r
different sets of axes (in the same figure), so that each plot is drawn in a different subplot. Choose how to set up your subplots so that all plots are sufficiently large and readable.
Then I write a code like that, I'm not quite sure if that's how it should be written, and I'm not sure what single means in this context.
if fig_type =='single':
fig, ax = plt.plot()
else:
fig, ax = plt.subplots()
Related
I have a function which plots and displays the distribution using the distplot from seaborn. it looks like this
def getPlot(data):
x=sns.distplot(data, hist=False)
plt.show()
return x
every time I call the function I get a plot of the distribution.
I want some help in modifying the function so that at the end of calling the function multiple times I should get an extra plot which is the combination of all the previous plots.
So if my function calls were
getPlot(data1)
getPlot(data2)
getPlot(data3)
I should get the individual plots for the data as I call the function and also at the very end I want the plots for the 3 data to be superimposed on each other.
Just moving plt.show() outside the function will not suffice because I want individual plots of the separate data as well as one figure that contains all the data.
Since you have to keep both a separate plot and a joint one of your data you have to plot each dataset twice. Once in a separate axes and once in a common one.
What I would do is create a figure and an axes into which everything will be plotted together. Then pass that axes object into the function, and make the function plot into the axes as well as into a new figure:
def plot_twice(data, ax_all):
# first plot into the common axes
sns.distplot(data, hist=False, ax=ax_all)
# and create a new figure and axes for a standalone plot
fig,ax = plt.subplots()
x = sns.distplot(data, hist=False, ax=ax)
return x
# create axes for the common plot
fig,ax_all = plt.subplots()
# now plot the things
getPlot(data1, ax_all)
getPlot(data2, ax_all)
getPlot(data3, ax_all)
# only call blocking plt.show() at the end
plt.show()
It doesn't seem feasible to copy plots from one axes to the other with matplotlib (see e.g. this or this), so unless the plotting takes an excessive amount of time or memory I'd just plot the data twice for simplicity.
I am trying to create a similar plot to what is done by seaborn, but in native matplotlib.
I am plotting every Series in a data frame against every other series in a matrix of plots.
So far I've plotted it, marked the outer axes, and set the axes to be shared along columns and row (as this works with the data the best).
The final step I am failing to manage is to make all the plots physically square in dimension. The following code:
#scatter matrix
def plot_scatter_matrix(data):
dim = len(data.columns.values)
fig, axs = newfigure(dim, dim, sharex='col', sharey='row', figsize=(10,10))
fig.tight_layout()
for row, iname in enumerate(data.columns.values):
for col, jname in enumerate(data.columns.values):
axs[row,col].scatter(data[jname], data[iname])
if col == 0:
axs[row,col].set_ylabel(iname)
if row == len(data.columns.values)-1:
axs[row,col].set_xlabel(jname)
return fig, axs
fig, axs = plot_scatter_matrix(ndata)
plt.show()
achieves this (only top half pictured):
I have attempted to use axs[row,col].set_aspect(1.0, adjustable='box', share=True) after the call to scatter() however it simply resulted in this:
As you can see, some managed to become physically square but they are all different sizes.
Having looked extensively through documentation and other questions I am stumped. Doesn't make it easier when other methods for this sort of thing have been deprecated over past versions.
If some axes become square by using set_aspect(1.0) (or the equivalent set_aspect("equal")) that's more or less coincidence and would only happen when the diffence of axis limits is actually equal; e.g. when the data ranges for x and y are the same.
Of course you could share all axes, not just column- or row-wise. That would ensure all axes to be of equal shape - but not necessarily square.
The requirement for square axes is that the aspect is the quotient of the x- and y range.
ax.set_aspect(np.diff(ax.get_xlim())/np.diff(ax.get_ylim()))
Also see: How to make sure that both x and y axes of plot are of equal sizes?
Another option is to restrict the space the subplots have via the subplot parameters as shown in this answer to python interplay between axis('square') and set_xlim.
I'm very new to Python, and I want to plot 13 different figures all in one plot. To do this nicely, I would like to plot the first 12 figures in a 6x2 grid (this works just fine), and then plot the 13th figure below it; either the same size as the other figures and centered, or larger than the rest so that its width is equal to twice the width of the other figures and all the edges are aligned. What would be the best way to specify axes of this kind using subplots? (So far, I've just used nrows=6, ncols=2, but I think something like that won't work with an odd number of figures to plot.) The code I have so far for plotting the first 12 plots looks like this (with simple test data):
fig, axes = plt.subplots(nrows=6, ncols=2, figsize=(45,10))
for ax in axes.flat:
ax.plot([1,2,3,4])
fig.subplots_adjust(right=0.5)
How can I add a 13th figure below the others?
You can use GridSpec (link to documentation) to generate flexible axes layout.
The following code creates the desired layout and puts all Axes objects in a list for easy access.
gs00 = matplotlib.gridspec.GridSpec(7, 2)
fig = plt.figure()
axs = []
for i in range(6):
for j in range(2):
ax = fig.add_subplot(gs00[i,j])
axs.append(ax)
ax = fig.add_subplot(gs00[6,:])
axs.append(ax)
I created a matplotlib plot that has 2 y-axes. The y-axes have different scales, but I want the ticks and grid to be aligned. I am pulling the data from excel files, so there is no way to know the max limits beforehand. I have tried the following code.
# creates double-y axis
ax2 = ax1.twinx()
locs = ax1.yaxis.get_ticklocs()
ax2.set_yticks(locs)
The problem now is that the ticks on ax2 do not have labels anymore. Can anyone give me a good way to align ticks with different scales?
Aligning the tick locations of two different scales would mean to give up on the nice automatic tick locator and set the ticks to the same positions on the secondary axes as on the original one.
The idea is to establish a relation between the two axes scales using a function and set the ticks of the second axes at the positions of those of the first.
import matplotlib.pyplot as plt
import matplotlib.ticker
fig, ax = plt.subplots()
# creates double-y axis
ax2 = ax.twinx()
ax.plot(range(5), [1,2,3,4,5])
ax2.plot(range(6), [13,17,14,13,16,12])
ax.grid()
l = ax.get_ylim()
l2 = ax2.get_ylim()
f = lambda x : l2[0]+(x-l[0])/(l[1]-l[0])*(l2[1]-l2[0])
ticks = f(ax.get_yticks())
ax2.yaxis.set_major_locator(matplotlib.ticker.FixedLocator(ticks))
plt.show()
Note that this is a solution for the general case and it might result in totally unreadable labels depeding on the use case. If you happen to have more a priori information on the axes range, better solutions may be possible.
Also see this question for a case where automatic tick locations of the first axes is sacrificed for an easier setting of the secondary axes tick locations.
To anyone who's wondering (and for my future reference), the lambda function f in ImportanceofBeingErnest's answer maps the input left tick to a corresponding right tick through:
RHS tick = Bottom RHS tick + (% of LHS range traversed * RHS range)
Refer to this question on tick formatting to truncate decimal places:
from matplotlib.ticker import FormatStrFormatter
ax2.yaxis.set_major_formatter(FormatStrFormatter('%.2f')) # ax2 is the RHS y-axis
I have a function that plots a graph. I can call this graph with different variables to alter the graph. I'd like to call this function multiple times and plot the graphs along side each other but not sure how to do so
def plt_graph(x, graph_title, horiz_label):
df[x].plot(kind='barh')
plt.title(graph_title)
plt.ylabel("")
plt.xlabel(horiz_label)
plt_graph('gross','Total value','Gross (in millions)')
In case you know the number of plots you want to produce beforehands, you can first create as many subplots as you need
fig, axes = plt.subplots(nrows=1, ncols=5)
(in this case 5) and then provide the axes to the function
def plt_graph(x, graph_title, horiz_label, ax):
df[x].plot(kind='barh', ax=ax)
Finally, call every plot like this
plt_graph("framekey", "Some title", "some label", axes[4])
(where 4 stands for the fifth and last plot)
I have created a tool to do this really easily. I use it all the time in jupyter notebooks and find it so much neater than a big column of charts. Copy the Gridplot class from this file:
https://github.com/simonm3/analysis/blob/master/analysis/plot.py
Usage:
gridplot = Gridplot()
plt.plot(x)
plt.plot(y)
It shows each new plot in a grid with 4 plots to a row. You can change the size of the charts or the number per row. It works for plt.plot, plt.bar, plt.hist and plt.scatter. However it does require you use matplot directly rather than pandas.
If you want to turn it off:
gridplot.off()
If you want to reset the grid to position 1:
gridplot.on()
Here is a way that you can do it. First you create the figure which will contain the axes object. With those axes you have something like a canvas, which is where every graph will be drawn.
fig, ax = plt.subplots(1,2)
Here I have created one figure with two axes. This is a one row and two columns figure. If you inspect the ax variable you will see two objects. This is what we'll use for all the plotting. Now, going back to the function, let's start with a simple dataset and define the function.
df = pd.DataFrame({"a": np.random.random(10), "b": np.random.random(10)})
def plt_graph(x, graph_title, horiz_label, ax):
df[x].plot(kind = 'barh', ax = ax)
ax.set_xlabel(horiz_label)
ax.set_title(graph_title)
Then, to call the function you will simply do this:
plt_graph("a", "a", "a", ax=ax[0])
plt_graph("b", "b", "b", ax=ax[1])
Note that you pass each graph that you want to create to any of the axes you have. In this case, as you have two, you pass the first to the first axes and so on. Note that if you include seaborn in your import (import seaborn as sns), automatically the seaborn style will be applied to your graphs.
This is how your graphs will look like.
When you are creating plotting functions, you want to look at matplotlib's object oriented interface.