Why I get additional empty plot in matplotlib? - python

I have the following code in my IPython notebook:
import matplotlib.pyplot as plt
plt.setp(plt.xticks()[1], rotation=45)
plt.figure(figsize=(17, 10)) # <--- This is the problematic line!!!!!!!!!!!!!
plt.plot_date(df['date'],df['x'], color='black', linestyle='-')
plt.plot_date(df['date'],df['y'], color='red', linestyle='-')
plt.plot_date(df['date'],df['z'], color='green', linestyle='-')
In the above example df is pandas data frame.
Without the marked line (containig figsize) the plot is too small. With the mentioned line I have an increased image as I want but before it I have an additional empty plot.
Does anybody know why it happens an how this problem can be resolved?

Try reversing the first two lines after the import. plt.setp is opening a figure.

here's how I would do this:
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(17, 10))
plt.setp(plt.xticks()[1], rotation=45)
ax.plot_date(df['date'],df['x'], color='black', linestyle='-')
ax.plot_date(df['date'],df['y'], color='red', linestyle='-')
ax.plot_date(df['date'],df['z'], color='green', linestyle='-')
It's a good practice to explicitly create and operate on your your Figure and Axes objects.

Related

How to overlay plots in python with matplotlib

I'm using two related packages that generate plots I want to overlay for comparison. I call a method called plot_spectro from each package which plots to plt. Then I must do plt.legend() and plt.show() to see them. What happens is two plots with the same data ranges appear, but I would like to overlay (superimpose) them.
import matplotlib.pyplot as plt
s.plot_spectro(xaxis=x, yaxis=y)
plt.xlim(-6,2)
plt.ylim(-2.5,2.5)
o1.plot_spectro(xaxis=x, yaxis=y, color='b')
plt.xlim(-6,2)
plt.ylim(-2.5,2.5)
plt.legend()
plt.show()
Create an axis instance and pass it to both the plots as shown below
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
s.plot_spectro(xaxis=x, yaxis=y, ax=ax) # <--- pass ax=ax here
o1.plot_spectro(xaxis=x, yaxis=y, color='b', ax=ax) # <--- pass ax=ax here
plt.xlim(-6,2)
plt.ylim(-2.5,2.5)
plt.legend()
plt.show()

Combine Bar and Line subplots in pandas

I have 5 time series that I want to graph in a subplot. Essentially I've been using subplotting:
fig, axes = plt.subplots(nrows=5, ncols=1, figsize=(16,10), sharex=True)
xlim = (start, end)
ax1=df.hr.plot(ax=axes[0], color='green', xlim=xlim)
ax2=df.act.plot(ax=axes[1], color='orange', xlim=xlim)
ax3=df.rr.plot(ax=axes[2], color='blue', xlim=xlim)
ax4=df2.set_index('timestamp').rmssd.plot(color='purple', ax=axes[3], xlim=xlim)
ax5=ma_df.tz_convert('US/Eastern')['any_act'].resample('10Min', how='count').plot(kind='line',ax=axes[4])
Which produces
Due to the nature of the data, I want to visualize the last subplot as bar chart. So naturally, I changed the last line to:
ax5=ma_df.tz_convert('US/Eastern')['any_act'].resample('10Min', how='count').plot(kind='bar',ax=axes[4])
Which then creates the following figure:
Which, produces what I expect in the last subplot, but makes the other plots useless. Needless to say, it's not what I want.
How can I combine the 4 line time series with one bar chart in the same plot, but different subplots, all sharing the same x-axis?
Meaning I would want the first 4 subplotplots like in the first image, and the last subplot like in the second image.
Update
I made a simple example, which unfortunately works as expected, and does not replicate my problem, which is even more baffling. Code is below
import pandas as pd
from matplotlib import pyplot as plt
%matplotlib inline
df = pd.read_csv('https://s3.amazonaws.com/temp-leonsas-qsaeamu0sl5v4b/df.csv')
bar_df = pd.read_csv('https://s3.amazonaws.com/temp-leonsas-qsaeamu0sl5v4b/bar_df.csv')
fig, axes = plt.subplots(nrows=4, ncols=1, figsize=(16,10), sharex=True)
ax1=df.hr.plot(ax=axes[0], color='green', kind='line')
ax2=df.act.plot(ax=axes[1], color='orange', kind='line')
ax3=df.rr.plot(ax=axes[2], color='blue', kind='line')
ax4=bar_df.occ_count.plot(ax=axes[3], kind='bar')
Whereas the code in my codebase which replicates the problem is
fig, axes = plt.subplots(nrows=4, ncols=1, figsize=(16,10), sharex=True)
ax1=df.hr.plot(ax=axes[0], color='green', kind='line')
ax2=df.act.plot(ax=axes[1], color='orange', kind='line')
ax3=df.rr.plot(ax=axes[2], color='blue', kind='line')
ax4=bar_df.occ_count.plot(ax=axes[3], kind='bar')
The main difference is that in my codebase the DataFrames are being generated and not just loaded up from s3. Is there an implicit config inside a DataFrame that can somehow make this happen? I just used df.to_csv to dump those 2 dataframes into S3.
I think you just need to explicitly pass kind='line' to the first three plots, here's a simpler example:
import matplotlib.pyplot as plt
import pandas as pd
%matplotlib inline
s = pd.Series([1,2,3,2,1])
fig, axes = plt.subplots(nrows=2, ncols=1, figsize=(16,10), sharex=True)
s.plot(ax=axes[0], color='green', kind='line')
s.plot(ax=axes[1], color='red', kind='bar')

errorbar, but not line, as marker symbol in python matplotlib legend

I have a errorbar plot with only one data point (i.e. one errorbar) per data set. Therefore I would like to have a single errorbar symbol in the legend as well.
The single one can be achieved by legend(numpoints=1). Using this in the following code:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.errorbar(x=[0.3], y=[0.7], xerr=[0.2], marker='+', markersize=10, label='horizontal marker line')
ax.errorbar(x=[0.7], y=[0.3], yerr=[0.2], marker='+', markersize=10, label='is too long')
ax.set_xlim([0,1])
ax.set_ylim([0,1])
ax.legend(numpoints=1) # I want only one symbol
plt.show()
results in these symbols in the legend:
As you see, the errorbars are mixed up with horizontal lines, that make sense when there are more than one error bars to be connected (using legend(numpoints=2) or higher), but look ugly in my case.
How can I get rid of the lines in the legend markers without loosing the errorbars?
This is due to the default settings in matplotlib. At the start of your code you can change them by changing the settings using rcParams:
import matplotlib as mpl
import matplotlib.pyplot as plt
mpl.rcParams['legend.handlelength'] = 0
mpl.rcParams['legend.markerscale'] = 0
fig, ax = plt.subplots()
ax.errorbar(x=[0.3], y=[0.7], xerr=[0.2], marker='+', markersize=10, label='horizontal marker')
ax.errorbar(x=[0.7], y=[0.3], yerr=[0.2], marker='+', markersize=10, label='is gone')
ax.set_xlim([0,1])
ax.set_ylim([0,1])
ax.legend(numpoints=1)
plt.show()
Note: This changes the settings for all the graphs that will be plotted in the code.

Saving plot from ipython notebook produces a cut image

I am plotting a plot with 2 ylabels using ipython notebook and the image looks good when visualized inside the notebook.
Here is how I do it:
import matplotlib.pyplot as plt
fig, ax1 = plt.subplots()
plt.title('TITLE')
plt.xlabel('X')
plt.plot(x, y1, '-', color='blue', label='SNR')
ax1.set_ylabel('y1', color='blue')
for tl in ax1.get_yticklabels():
tl.set_color('blue')
ax2 = ax1.twinx()
plt.plot(x, y2, '--', color='red', label='Ngal')
ax2.set_ylabel('y2', color='red')
for tl in ax2.get_yticklabels():
tl.set_color('red')
The problem is that when I try to save it with the command
plt.savefig('output.png', dpi=300)
since the output will be an image which is cut on the right side: basically I don't see the right ylabel if the right numbers are large.
By default, matplotlib leaves very little room for x and y axis labels and tick labels, therefore you need to adjust the figure to include more padding. Fortunately this could not be easier to do. Before you call savefig, you can call call
fig.tight_layout()
plt.savefig('output.png', dpi=300)
Alternatively, you can pass bbox_inches='tight' to savefig which will also adjust the figure to include all of the x and y labels
plt.savefig('output.png', dpi=300, bbox_inches='tight')

Creating sparklines using matplotlib in python

I am working on matplotlib and created some graphs like bar chart, bubble chart and others.
Can some one please explain with an example what is difference between line graph and sparkline graph and how to draw spark line graphs in python using matplotlib ?
for example with the following code
import matplotlib.pyplot as plt
import numpy as np
x=[1,2,3,4,5]
y=[5,7,2,6,2]
plt.plot(x, y)
plt.show()
the line graph generated is the following:
But I couldn't get what is the difference between a line chart and a spark lien chart for the same data. Please help me understand
A sparkline is the same as a line plot but without axes or coordinates. They can be used to show the "shape" of the data in a compact way.
You can cram several line plots in the same figure just by using subplots and changing properties of the resulting Axes for each subplot:
data = np.cumsum(np.random.rand(1000)-0.5)
data = data - np.mean(data)
fig = plt.figure()
ax1 = fig.add_subplot(411) # nrows, ncols, plot_number, top sparkline
ax1.plot(data, 'b-')
ax1.axhline(c='grey', alpha=0.5)
ax2 = fig.add_subplot(412, sharex=ax1)
ax2.plot(data, 'g-')
ax2.axhline(c='grey', alpha=0.5)
ax3 = fig.add_subplot(413, sharex=ax1)
ax3.plot(data, 'y-')
ax3.axhline(c='grey', alpha=0.5)
ax4 = fig.add_subplot(414, sharex=ax1) # bottom sparkline
ax4.plot(data, 'r-')
ax4.axhline(c='grey', alpha=0.5)
for axes in [ax1, ax2, ax3, ax4]: # remove all borders
plt.setp(axes.get_xticklabels(), visible=False)
plt.setp(axes.get_yticklabels(), visible=False)
plt.setp(axes.get_xticklines(), visible=False)
plt.setp(axes.get_yticklines(), visible=False)
plt.setp(axes.spines.values(), visible=False)
# bottom sparkline
plt.setp(ax4.get_xticklabels(), visible=True)
plt.setp(ax4.get_xticklines(), visible=True)
ax4.xaxis.tick_bottom() # but onlyt the lower x ticks not x ticks at the top
plt.tight_layout()
plt.show()
A sparkline graph is just a regular plot with all the axis removed. quite simple to do with matplotlib:
import matplotlib.pyplot as plt
import numpy as np
# create some random data
x = np.cumsum(np.random.rand(1000)-0.5)
# plot it
fig, ax = plt.subplots(1,1,figsize=(10,3))
plt.plot(x, color='k')
plt.plot(len(x)-1, x[-1], color='r', marker='o')
# remove all the axes
for k,v in ax.spines.items():
v.set_visible(False)
ax.set_xticks([])
ax.set_yticks([])
#show it
plt.show()

Categories

Resources