0

I'm trying to make a plot with two y-axes, both of them logarithmic; Y1 is the left-hand y-axis and Y2 is the right-hand y-axis. Here the values of Y1 are calculated by dividing Y2 values by some_number to be defined in the snippet. The figure does not look ok due to decimal numbers picked for Y2 axis:

import numpy as np
from numpy import *
import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib import rcParams, cm
from matplotlib.ticker import MaxNLocator

#Plotting Decorations
xtick_label_size, ytick_label_size, axes_label_size, font_size, tick_width, lw, alpha = 18, 18, 20, 30, 2, 0.5, 0.5
plt.rcParams['mathtext.fontset'] = 'stix'
plt.rcParams['font.family'] = 'STIXGeneral'
mpl.rcParams['xtick.labelsize'], mpl.rcParams['ytick.labelsize'], mpl.rcParams['axes.labelsize'] = xtick_label_size, ytick_label_size, axes_label_size

some_number = mean(array([0.01614, 0.01381, 0.02411, 0.007436, 0.03223]))
f, (ax) = plt.subplots(1, 1, figsize=(10,100))

ax.set_xlim([1e8, 3e12])
ax.set_ylim([3e-1, 3e3])
ax.yaxis.set_major_locator(MaxNLocator(prune='upper')) 
ax.set_ylabel('Y1', fontsize=12)
ax.set_xlabel('X', fontsize=12)
ax.set_xscale("log", nonposx='clip')
ax.set_yscale("log", nonposy='clip')
ax.xaxis.set_tick_params(width=tick_width)
ax.yaxis.set_tick_params(width=tick_width)
ax.get_xaxis().tick_bottom()  
ax.get_yaxis().tick_left()
number = np.array([1e-4,1e-3,1e-2,1e-1,1,1e1,1e2,1e3])
numberticks = [i*some_number for i in number]
axsecond = ax.twinx()
axsecond.set_ylabel('Y2', fontsize=12)
axsecond.set_yscale("log", nonposy='clip')
axsecond.yaxis.set_tick_params(width=tick_width)
axsecond.set_yticks(number)
axsecond.set_yticklabels(['{:g}'.format(i) for i in numberticks])

f.subplots_adjust(top=0.98,bottom=0.14,left=0.14,right=0.98)
plt.setp([a.get_xticklabels() for a in f.axes[:-1]], visible=True)
f.tight_layout()
plt.show()

After getting help for defining correct labels for Y2, I want to represent these labels as powers of 10 similar to Y1. Do you know how to do that?

enter image description here

Rebel
  • 472
  • 8
  • 25
  • What is `some_number`? See [mcve]. – ImportanceOfBeingErnest Jul 29 '18 at 00:07
  • You are setting the yticks to strange positions yourself. I.e. the number 1 is positionned at 53.34699. – ImportanceOfBeingErnest Jul 29 '18 at 10:38
  • This is the relation that I want to implement: Y1=Y2/some_number. The position and the labels of Y2 are correct. How to change these values that you are talking about? – Rebel Jul 29 '18 at 18:23
  • In other words, the problem is with minor ticks and not major ones. – Rebel Jul 29 '18 at 18:41
  • The minor ticks are correct. The major labels are just set to some pretty arbitrary positions, hence they do not match the correct minor ticks. – ImportanceOfBeingErnest Jul 29 '18 at 20:47
  • commenting out this line would remove the parasites. axsecond.set_yticks(numberticks). From the value of *some_number*, the map between two axes changes. For example with increase this number, higher values on Y2 would correspond to the same values on Y1. But in the absence of this line, that one-to-one map is no longer correct. This is why I am wondering why I am receiving the same labels and positions regardless of any change in *some_number*. Is that clear? – Rebel Jul 30 '18 at 01:45
  • 1
    You have a ruler with some major and minor ticks on it. `set_yticks` sets the major ticks at some other place. But the ruler's length and the minor ticks stay the same. And it will still measure the same units, regardless on how you label it. – ImportanceOfBeingErnest Jul 30 '18 at 09:25
  • Possibly [this example](https://matplotlib.org/examples/subplots_axes_and_figures/fahrenheit_celsius_scales.html) helps understanding the issue. – ImportanceOfBeingErnest Jul 30 '18 at 09:34
  • I see what you're saying. I fixed that by (1) replacing " / " with " * " in the definition of *number* and (2) replacing *number* and *numberticks* between *yticks* and *yticklabels*. Now the correspondence between Y1 and Y2 matches. However, the way my labels look like for Y2 is ugly. In stead of powers of 10 I am having long float/decimal numbers. Is there a way to represent this ruler also in unit of powers of 10? – Rebel Jul 30 '18 at 17:55
  • Just added the modified code and plot. – Rebel Jul 30 '18 at 18:00
  • 1
    18.7452 is 10^1.2729, is that what you want to show? – ImportanceOfBeingErnest Jul 30 '18 at 18:12
  • Yes, that seems the only way to do it without changing the ruler I guess. – Rebel Jul 30 '18 at 18:50
  • But I was more interested in making another rules to the right just for this purpose all in integer powers of 10 if possible. – Rebel Jul 30 '18 at 18:51
  • Yeah, so I think the problem is really that I do not fully understand the purpose of this. Is Y2 in any way related to Y1? Is Y2 supposed to be logarithmic or is it supposed to follow what Y1 is showing? – ImportanceOfBeingErnest Jul 30 '18 at 20:22
  • Yes, Y1=Y2/some_number and they both need to be logarithmic. I slightly modified the text in the question to reflect that clearly at the beginning. Thanks again, – Rebel Aug 02 '18 at 00:37

1 Answers1

1

The idea would be to synchronize the axes limits. I.e. if the y limits of the first axes are [a,b], those for the second axes would need to be [a*factor, b*factor].

import matplotlib.pyplot as plt
import numpy as np

factor = 0.5

fig, ax = plt.subplots()
ax2 = ax.twinx()

ax.set_ylim([.1, 1e3])
ax2.set_ylim(np.array(ax.get_ylim())*factor)

ax.set_yscale("log")
ax2.set_yscale("log")


ax.plot([0,1],[1,100])
ax2.plot([0,1],np.array([1,100])*factor)

plt.show()

enter image description here

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712