Python x axis changes in twinx plot - python

I have a dataframe df with a few meteorological parameters in it. The dataframe has DatetimeIndex, so when I plot it, it automatically puts the time on the x axis. Now that is great, because when I plot one parameter, for example:
ax1 = df.plot(y='temp_vaisala' , color='tab:blue')
ax1.set_ylabel('Temerature (C)', color='tab:blue')
ax1.set_xlabel('Month', color='tab:blue')
It gives me the following nice graph as a result:
However, I would like to have a graph with two parameters, so I use the twinx option like this:
fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
ax1.plot(df['temp_vaisala'], 'tab:blue')
ax2.plot(df['rel_humidity_vaisala'], 'b-')
ax1.set_xlabel('Month', color='tab:blue')
ax1.set_ylabel('Temerature (C)', color='tab:blue')
ax2.set_ylabel('RH (-)', color='b')
This function however gives the following graph as a result:
So for some reason, this completely messes up the description under the x axis. I would like this graph with two parameters to have the same x axis as the first graph. Does anyone have a solution for this? Many thanks in advance!

Try this, using pandas plot:
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
df = pd.DataFrame({'temp':np.arange(12),'rhel':np.arange(220,100,-10)},
index=pd.date_range('10-01-2020', periods=12, freq='MS'))
fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
df['temp'].plot(ax = ax1, color='tab:blue')
df['rhel'].plot(ax = ax2, color='b')
ax1.set_xlabel('Month', color='tab:blue')
ax1.set_ylabel('Temerature (C)', color='tab:blue')
ax2.set_ylabel('RH (-)', color='b');
Output:

Related

How to plot sublots when creating plots in a for loop in python?

I'm new to programming and currently stuck on this: I create 4 different plots using a for loop and I want to assign each plot to a different subplot. Basically, I want 4 plots in a 2x2 grid so I can compare my data. Anyone knows how I can achieve this? My approach was to create a list of subplots and then assign every plot to a subplot using a nested plot:
import matplotlib.pyplot as plt
import numpy as np
def load_file(filename):
return np.loadtxt(filename, delimiter=',', usecols=(0, 1), unpack=True, skiprows=1)
fig = plt.figure()
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222)
ax3 = fig.add_subplot(223)
ax4 = fig.add_subplot(224)
ax_list=[ax1, ax2, ax3, ax4]
for i,filename in enumerate(file_list):
for p in ax_list:
x,y = load_file(filename)
plt.plot(x,y,
label=l, #I assign labels from a list beforehand, as well as colors
color=c,
linewidth=0.5,
ls='-',
)
p.plot()
The problem is, all plots are assigned to only one subplot and I don't know how to correct this. I'd appreciate any help!
I guess what you want is to show different data on all 4 plots, hence use a single loop. Make sure to use the axes plotting method, not plt.plot as the latter would always plot in the last subplot.
import matplotlib.pyplot as plt
import numpy as np
def load_file(filename):
return np.loadtxt(filename, delimiter=',', usecols=(0, 1), unpack=True, skiprows=1)
fig, ax_list = plt.subplots(2,2)
for i,(filename,ax) in enumerate(zip(file_list, ax_list.flatten())):
x,y = load_file(filename)
ax.plot(x,y, linewidth=0.5,ls='-' )
plt.show()
You don't need to loop over filenames and plots, only need to select the next plot in the list.
for i, filename in enumerate(file_list):
p = ax_list[i]:
x,y = load_file(filename)
p.plot(x, y,
label=l, #I assign labels from a list beforehand, as well as colors
color=c,
linewidth=0.5,
ls='-')
plt.plot()
You can also replace
fig = plt.figure()
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222)
ax3 = fig.add_subplot(223)
ax4 = fig.add_subplot(224)
ax_list=[ax1, ax2, ax3, ax4]
with just
fig, ax_list = plt.subplots(2, 2)
ax_list = ax_list.flatten()
To get a simple 2x2 grid.

Passing same x axis label to matplotlib subplots of barplots

I'm trying to create subplots of barplots. matplotlib is funny with labeling the x axis of barplots so you need to pass an index then use the xticks function to pass the labels. I want to create 2 subplots that each have the same x axis labels but with the code below I can only pass the labels onto the last bar plot. My question is how can I pass the labels to both bar plots?
fig, axes = plt.subplots(nrows=2, ncols=1, figsize=(18,15))
r1 = axes[0].bar(idx, data1, align='center')
axes[0].set_title('title1')
r2 = axes[1].bar(idx, data2, align='center')
axes[1].set_title('title2')
plt.xticks(idx, idx_labels, rotation=45)
plt.xticks as all other pyplot commands relate to the currently active axes. Having produced several axes at once via plt.subplots(), the last of them is the current axes, and thus the axes for which plt.xticks would set the ticks.
You may set the current axes using plt.sca(axes):
import matplotlib.pyplot as plt
idx, data1, data2, idx_labels = [1,2,3], [3,4,2], [2,5,4], list("ABC")
fig, axes = plt.subplots(nrows=2, ncols=1)
r1 = axes[0].bar(idx, data1, align='center')
axes[0].set_title('title1')
plt.sca(axes[0])
plt.xticks(idx, idx_labels, rotation=45)
r2 = axes[1].bar(idx, data2, align='center')
axes[1].set_title('title2')
plt.sca(axes[1])
plt.xticks(idx, idx_labels, rotation=45)
plt.show()
However, when working with subplots, it is often easier to use the object-oriented API of matplotlib instead of the pyplot statemachine. In that case you'd use ax.set_xticks and ax.set_xticklabels, where ax is the axes for which you want to set some property. This is more intuitive, since it is easily seen from the code which axes it being worked on.
import matplotlib.pyplot as plt
idx, data1, data2, idx_labels = [1,2,3], [3,4,2], [2,5,4], list("ABC")
fig, axes = plt.subplots(nrows=2, ncols=1)
r1 = axes[0].bar(idx, data1, align='center')
axes[0].set_title('title1')
r2 = axes[1].bar(idx, data2, align='center')
axes[1].set_title('title2')
for ax in axes:
ax.set_xticks(idx)
ax.set_xticklabels(idx_labels, rotation=45)
plt.show()

Two Y axis Bar plot: custom xticks

I am trying to add custom xticks to a relatively complicated bar graph plot and I am stuck.
I am plotting from two data frames, merged_90 and merged_15:
merged_15
Volume y_err_x Area_2D y_err_y
TripDate
2015-09-22 1663.016032 199.507503 1581.591701 163.473202
merged_90
Volume y_err_x Area_2D y_err_y
TripDate
1990-06-10 1096.530711 197.377497 1531.651913 205.197493
I want to create a bar graph with two axes (i.e. Area_2D and Volume) where the Area_2D and Volume bars are grouped based on their respective data frame. An example script would look like:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import scipy
fig = plt.figure()
ax1 = fig.add_subplot(111)
merged_90.Volume.plot(ax=ax1, color='orange', kind='bar',position=2.5, yerr=merged_90['y_err_x'] ,use_index=False , width=0.1)
merged_15.Volume.plot(ax=ax1, color='red', kind='bar',position=0.9, yerr=merged_15['y_err_x'] ,use_index=False, width=0.1)
ax2 = ax1.twinx()
merged_90.Area_2D.plot(ax=ax2,color='green', kind='bar',position=3.5, yerr=merged_90['y_err_y'],use_index=False, width=0.1)
merged_15.Area_2D.plot(ax=ax2,color='blue', kind='bar',position=0, yerr=merged_15['y_err_y'],use_index=False, width=0.1)
ax1.set_xlim(-0.5,0.2)
x = scipy.arange(1)
ax2.set_xticks(x)
ax2.set_xticklabels(['2015'])
plt.tight_layout()
plt.show()
The resulting plot is:
One would think I could change:
x = scipy.arange(1)
ax2.set_xticks(x)
ax2.set_xticklabels(['2015'])
to
x = scipy.arange(2)
ax2.set_xticks(x)
ax2.set_xticklabels(['1990','2015'])
but that results in:
I would like to see the ticks ordered in chronological order (i.e. 1990,2015)
Thanks!
Have you considered dropping the second axis and plotting them as follows:
ind = np.array([0,0.3])
width = 0.1
fig, ax = plt.subplots()
Rects1 = ax.bar(ind, [merged_90.Volume.values, merged_15.Volume.values], color=['orange', 'red'] ,width=width)
Rects2 = ax.bar(ind + width, [merged_90.Area_2D.values, merged_15.Area_2D.values], color=['green', 'blue'] ,width=width)
ax.set_xticks([.1,.4])
ax.set_xticklabels(('1990','2015'))
This produces:
I omitted the error and colors but you can easily add them. That would produce a readable graph given your test data. As you mentioned in comments you would still rather have two axes, presumably for different data with proper scales. To do this you could do:
fig = plt.figure()
ax1 = fig.add_subplot(111)
merged_90.Volume.plot(ax=ax, color='orange', kind='bar',position=2.5, use_index=False , width=0.1)
merged_15.Volume.plot(ax=ax, color='red', kind='bar',position=1.0, use_index=False, width=0.1)
ax2 = ax1.twinx()
merged_90.Area_2D.plot(ax=ax,color='green', kind='bar',position=3.5,use_index=False, width=0.1)
merged_15.Area_2D.plot(ax=ax,color='blue', kind='bar',position=0,use_index=False, width=0.1)
ax1.set_xlim([-.45, .2])
ax2.set_xlim(-.45, .2])
ax1.set_xticks([-.35, 0])
ax1.set_xticklabels([1990, 2015])
This produces:
Your problem was with resetting just one axis limit and not the other, they are created as twins but do not necessarily follow the changes made to one another.

wrong y axis range using matplotlib subplots and seaborn

I'm playing with seaborn for the first time, trying to plot different columns of a pandas dataframe on different plots using matplotlib subplots. The simple code below produces the expected figure but the last plot does not have a proper y range (it seems linked to the full range of values in the dataframe).
Does anyone have an idea why this happens and how to prevent it? Thanks.
import matplotlib.pyplot as plt
import numpy as np
import pandas as pds
import seaborn as sns
X = np.arange(0,10)
df = pds.DataFrame({'X': X, 'Y1': 4*X, 'Y2': X/2., 'Y3': X+3, 'Y4': X-7})
fig, axes = plt.subplots(ncols=2, nrows=2)
ax1, ax2, ax3, ax4 = axes.ravel()
sns.set(style="ticks")
sns.despine(fig=fig)
sns.regplot(x='X', y='Y1', data=df, fit_reg=False, ax=ax1)
sns.regplot(x='X', y='Y2', data=df, fit_reg=False, ax=ax2)
sns.regplot(x='X', y='Y3', data=df, fit_reg=False, ax=ax3)
sns.regplot(x='X', y='Y4', data=df, fit_reg=False, ax=ax4)
plt.show()
Update: I modified the above code with:
fig, axes = plt.subplots(ncols=2, nrows=3)
ax1, ax2, ax3, ax4, ax5, ax6 = axes.ravel()
If I plot data on any axis but the last one I obtain what I'm looking for:
Of course I don't want the empty frames. All plots present the data with a similar visual aspect.
When data is plotted on the last axis, it gets a y range that is too wide like in the first example. Only the last axis seems to have this problem. Any clue?
If you want the scales to be the same on all axes you could create subplots with this command:
fig, axes = plt.subplots(ncols=2, nrows=2, sharey=True, sharex=True)
Which will make all plots to share relevant axis:
If you want manually to change the limits of that particular ax, you could add this line at the end of plotting commands:
ax4.set_ylim(top=5)
# or for both limits like this:
# ax4.set_ylim([-2, 5])
Which will give something like this:

python: scatter plot logarithmic scale

In my code, I take the logarithm of two data series and plot them. I would like to change each tick value of the x-axis by raising it to the power of e (anti-log of natural logarithm).
In other words. I want to graph the logarithms of both series but have x-axis in levels.
Here is the code that I'm using.
from pylab import scatter
import pylab
import matplotlib.pyplot as plt
import pandas as pd
from pandas import Series, DataFrame
import numpy as np
file_name = '/Users/joedanger/Desktop/Python/scatter_python.csv'
data = DataFrame(pd.read_csv(file_name))
y = np.log(data['o_value'], dtype='float64')
x = np.log(data['time_diff_day'], dtype='float64')
fig = plt.figure()
plt.scatter(x, y, c='blue', alpha=0.05, edgecolors='none')
fig.suptitle('test title', fontsize=20)
plt.xlabel('time_diff_day', fontsize=18)
plt.ylabel('o_value', fontsize=16)
plt.xticks([-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4])
plt.grid(True)
pylab.show()
let matplotlib take the log for you:
fig = plt.figure()
ax = plt.gca()
ax.scatter(data['o_value'] ,data['time_diff_day'] , c='blue', alpha=0.05, edgecolors='none')
ax.set_yscale('log')
ax.set_xscale('log')
If you are using all the same size and color markers, it is faster to use plot
fig = plt.figure()
ax = plt.gca()
ax.plot(data['o_value'] ,data['time_diff_day'], 'o', c='blue', alpha=0.05, markeredgecolor='none')
ax.set_yscale('log')
ax.set_xscale('log')
The accepted answer is a bit out of date. At least pandas 0.25 natively supports log axes:
# logarithmic X
df.plot.scatter(..., logx=True)
# logarithmic Y
df.plot.scatter(..., logy=True)
# both
df.plot.scatter(..., loglog=True)

Categories