figsize in matplotlib is not changing the figure size? [duplicate] - python

This question already has answers here:
How do I change the size of figures drawn with Matplotlib?
(14 answers)
Closed 4 years ago.
As you can see the code produces a barplot that is not as clear and I want to make the figure larger so the values can be seen better. This doesn't do it. What is the correct way?
x is a dataframe and x['user'] is the x axis in the plot and x['number'] is the y.
import matplotlib.pyplot as plt
%matplotlib inline
plt.bar(x['user'], x['number'], color="blue")
plt.figure(figsize=(20,10))
The line with the plt.figure doesn't change the initial dimensions.

One option (as mentioned by #tda), and probably the best/most standard way, is to put the plt.figure before the plt.bar:
import matplotlib.pyplot as plt
plt.figure(figsize=(20,10))
plt.bar(x['user'], x['number'], color="blue")
Another option, if you want to set the figure size after creating the figure, is to use fig.set_size_inches (note I used plt.gcf here to get the current figure):
import matplotlib.pyplot as plt
plt.bar(x['user'], x['number'], color="blue")
plt.gcf().set_size_inches(20, 10)
It is possible to do this all in one line, although its not the cleanest code. First you need to create the figure, then get the current axis (fig.gca), and plot the barplot on there:
import matplotlib.pyplot as plt
plt.figure(figsize=(20, 10)).gca().bar(x['user'], x['number'], color="blue")
Finally, I will note that it is often better to use the matplotlib object-oriented approach, where you save a reference to the current Figure and Axes and call all plotting functions on them directly. It may add more lines of code, but it is usually clearer code (and you can avoid using things like gcf() and gca()). For example:
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(20, 10))
ax = fig.add_subplot(111)
ax.bar(x['user'], x['number'], color="blue")

Try setting up the size of the figure before assigning what to plot, as below:
import matplotlib.pyplot as plt
%matplotlib inline
plt.figure(figsize=(20,10))
plt.bar(x['user'], x['number'], color="blue")

Related

How can I rotate axis tickmark labels if I set axis properties before making my plot?

I'm experimenting with seaborn and have a question about specifying axes properties. In my code below, I've taken two approaches to creating a heatmap of a matrix and placing the results on two sets of axes in a figure.
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
A=np.random.randn(4,4)
labels=['a','b','c','d']
fig, ax = plt.subplots(2)
sns.heatmap(ax =ax[0], data = A)
ax[0].set_xticks(range(len(labels)))
ax[0].set_xticklabels(labels,fontsize=10,rotation=45)
ax[0].set_yticks(range(len(labels)))
ax[0].set_yticklabels(labels,fontsize=10,rotation=45)
ax[1].set_xticks(range(len(labels)))
ax[1].set_xticklabels(labels,fontsize=10,rotation=45)
ax[1].set_yticks(range(len(labels)))
ax[1].set_yticklabels(labels,fontsize=10,rotation=45)
sns.heatmap(ax =ax[1], data = A,xticklabels=labels, yticklabels=labels)
plt.show()
The resulting figure looks like this:
Normally, I would always take the first approach of creating the heatmap and then specifying axis properties. However, when creating an animation (to be embedded on a tkinter canvas), which is what I'm ultimately interested in doing, I found such an ordering in my update function leads to "flickering" of axis labels. The second approach will eliminate this effect, and it also centers the tickmarks within squares along the axes.
However, the second approach does not rotate the y-axis tickmark labels as desired. Is there a simple fix to this?
I'm not sure this is what you're looking for. It looks like you create your figure after you change the yticklabels. so the figure is overwriting your yticklabels.
Below would fix your issue.
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
A=np.random.randn(4,4)
labels=['a','b','c','d']
fig, ax = plt.subplots(2)
sns.heatmap(ax =ax[0], data = A)
ax[0].set_xticks(range(len(labels)))
ax[0].set_xticklabels(labels,fontsize=10,rotation=45)
ax[0].set_yticks(range(len(labels)))
ax[0].set_yticklabels(labels,fontsize=10,rotation=45)
ax[1].set_xticks(range(len(labels)))
ax[1].set_xticklabels(labels,fontsize=10,rotation=45)
ax[1].set_yticks(range(len(labels)))
sns.heatmap(ax =ax[1], data = A,xticklabels=labels, yticklabels=labels)
ax[1].set_yticklabels(labels,fontsize=10,rotation=45)
plt.show()

Change y-axis scale - FacetGrid

I cannot work out how to change the scale of the y-axis. My code is:
grid = sns.catplot(x='Nationality', y='count',
row='Age', col='Gender',
hue='Type',
data=dfNorthumbria2, kind='bar', ci='No')
I wanted to just go up in full numbers rather than in .5
Update
I just now found this tutorial the probably easiest solution will be the following:
grid.set(yticks=list(range(5)))
From the help of grid.set
Help on method set in module seaborn.axisgrid:
set(**kwargs) method of seaborn.axisgrid.FacetGrid instance
Set attributes on each subplot Axes.
Since seaborn is build on top of matplotlib you can use yticks from plt
import matplotlib.pyplot as plt
plt.yticks(range(5))
However this changed only the yticks of the upper row in my mockup example.
For this reason you probably want to change the y ticks based on the axis with ax.set_yticks(). To get the axis from your grid object you can implemented a list comprehension as follows:
[ax[0].set_yticks(range(0,150,5) )for ax in grid.axes]
A full replicable example would look like this (adapted from here)
import seaborn as sns
import matplotlib.pyplot as plt
sns.set(style="ticks")
exercise = sns.load_dataset("exercise")
grid = sns.catplot(x="time", y="pulse", hue="kind",
row="diet", data=exercise)
# plt.yticks(range(0,150,5)) # Changed only one y-axis
# Changed y-ticks to steps of 20
[ax[0].set_yticks(range(0,150,20) )for ax in grid.axes]

How to change axis labels in matplotlib? [duplicate]

This question already has answers here:
Modify tick label text
(13 answers)
Closed 3 years ago.
I have the following piece of code which creates a simple plot with matplotlib (python 3.6.9, matplotlib 3.1.2, Mac Mojave):
import numpy as np
import matplotlib.pyplot as plt
plt.imshow(np.random.random((50,50)))
plt.show()
The created plot is as expected:
Now, in order to relabel the xtick/ytick labels I am using the following code
import numpy as np
import matplotlib.pyplot as plt
plt.imshow(np.random.random((50,50)));
ticks, labels = plt.xticks()
labels[1] = '22'
plt.xticks(ticks, labels)
plt.show()
where I expect the second label to be replaced by '22', but everything else stays the same. However, I get the following plot instead:
There is some unexpected white area in the left part of the plot
All the other labels have vanished.
How to do it correctly?
Just as a reminder: I want to get the exact same result as the original image (first plot), ONLY with one of the lables changed.
This question has been asked before, one example is here. But the answer does not seem to work. Here is the code
import numpy as np
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
plt.imshow(np.random.random((50,50)))
labels = [item.get_text() for item in ax.get_xticklabels()]
labels[1] = 'Test'
ax.set_xticklabels(labels)
plt.show()
which creates an image as follows:
which does not show the white area anymore, but still the other labels are not shown.
Create axes using subplots, so that you can have set_xticklabels method, so you can update the labels.
You need to use, canvas.draw() to get the values.
import numpy as np
import matplotlib.pyplot as plt
fig,ax = plt.subplots()
ax.imshow(np.random.random((50,50)));
fig.canvas.draw()
#labels = ['-10','0','22','20','30','40'] or
labels[2]=22
ax.set_xticklabels(labels)
plt.show()
Output:
Hope this is what you need!

Matplotlib logarithmic scale displayed as integers workaround does not work with a specified scale [duplicate]

This question already has answers here:
How to set the ticks of log scale for x&y axis?
(2 answers)
Closed 4 years ago.
Matplotlib inherently sets logarithmic scales to use scientific notation. If you want to avoid this you have to use a workaround such as the following minimal example:
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
x=np.arange(100,110)
y=np.arange(10)
fig, axes = plt.subplots(1, 2, sharey=True, squeeze=False)
axes = axes[0]
axes[0].plot(x,y)
axes[1].plot(x,y)
for ax in axes:
ax.set_yscale('log')
ax.yaxis.set_major_formatter(mpl.ticker.ScalarFormatter())
plt.show()
This works fine under all cases and has been shown as a solution as under many questions such as Example 1 Example 2
I have used this solution fine before. However there is another issue that I have not seen discussed. If you want to set a ax.ylim(...) this work around stops working
Consider the following example (note the new line ax.set_ylim(0,10)):
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
x=np.arange(100,110)
y=np.arange(10)
fig, axes = plt.subplots(1, 2, sharey=True, squeeze=False)
axes = axes[0]
axes[0].plot(x,y)
axes[1].plot(x,y)
for ax in axes:
ax.set_ylim(0, 10)
ax.set_yscale('log')
ax.yaxis.set_major_formatter(mpl.ticker.ScalarFormatter())
plt.show()
This is no longer the desired output.
Is there anyway to avoid this weird interaction?
The problem is that you are currently using only major_formatter which only applies to the major ticks on your log scale. You need to additionally use minor_formatter in your second case because what you see as 2 x10^0, 3 x 10^0 etc are the minor tick-labels the formatting of which has to be treated separately.
for ax in axes:
ax.set_ylim(0, 10)
ax.set_yscale('log')
ax.yaxis.set_major_formatter(mpl.ticker.ScalarFormatter())
ax.yaxis.set_minor_formatter(mpl.ticker.ScalarFormatter()) # <---- Added

Save figure with clip box from another figure

Normally if you plot two different figures using the default settings in pyplot, they will be exactly the same size, and if saved can be neatly aligned in PowerPoint or the like. I'd like to generate one figure, however, which has a legend outside of the figure. The script I'm using is shown below.
import numpy as np
import matplotlib.pyplot as plt
x=np.linspace(0,1,201)
y1=x**2
y2=np.sin(x)
fig1=plt.figure(1)
plt.plot(x,y1,label='y1')
handles1,labels1=plt.gca().get_legend_handles_labels()
lgd1=plt.gca().legend(handles1,labels1,bbox_to_anchor=(1.27,1),borderaxespad=0.)
fig2=plt.figure(2)
plt.plot(x,y2)
fig1.savefig('fig1',bbox_extra_artists=(lgd1,),bbox_inches='tight')
fig2.savefig('fig2')
plt.show()
The problem is that in PowerPoint, I can no longer align the two figures left and have their axes aligned. Due to the use of the 'extra artists' and 'bbox_inches=tight' arguments for the first figure, the width of its margins becomes different from the second figure.
Is there any way to 'transfer' the clip box from the first figure to the second figure, such that they can be aligned by 'align left' in PowerPoint?
I think an easier way to achieve what you want is to just construct one figure with two subplots, and let matplotlib align everything for you.
Do you think doing something like this is a good idea?
import matplotlib.pyplot as plt
import numpy as np
x=np.linspace(0,1,201)
y1=x**2
y2=np.sin(x)
fig = plt.figure()
a = fig.add_subplot(211)
a.plot(x,y1, label='y1')
lgd1 = a.legend(bbox_to_anchor = (1.27,1), borderaxespad=0.)
a = fig.add_subplot(212)
a.plot(x,y2)
fig.savefig('fig',bbox_extra_artists=(lgd1,),bbox_inches='tight')

Categories