Matplotlib — twiny: how to align values of two x-axes in one plot?





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}







1















I'm trying to use twiny() in matplotlib for plotting of a curve with two x-axes from an XML file consisting of these data blocks:



<data>
<meas>
<utc>2018-11-10T22:27:06.500003</utc>
<ra_j2000>23.9722686269</ra_j2000>
<dec_j2000>-1.23845121893</dec_j2000>
<mag>9.96074403533</mag>
</meas>

<meas>
<utc>2018-11-10T22:27:54.500002</utc>
<ra_j2000>23.9930913364</ra_j2000>
<dec_j2000>-1.03788334773</dec_j2000>
<mag>11.356437889</mag>
</meas>

<meas>
<utc>2018-11-10T22:38:36.500002</utc>
<ra_j2000>0.267638646848</ra_j2000>
<dec_j2000>1.56055091433</dec_j2000>
<mag>11.1642458641</mag>
</meas>

<meas>
<utc>2018-11-10T22:46:18.500000</utc>
<ra_j2000>0.462353662364</ra_j2000>
<dec_j2000>3.34334963425</dec_j2000>
<mag>11.1082534741</mag>
</meas>

<meas>
<utc>2018-11-10T22:57:18.500001</utc>
<ra_j2000>0.740393528722</ra_j2000>
<dec_j2000>5.78641590694</dec_j2000>
<mag>11.0688955214</mag>
</meas>

<meas>
<utc>2018-11-10T23:03:06.499995</utc>
<ra_j2000>0.888541738338</ra_j2000>
<dec_j2000>7.03265231497</dec_j2000>
<mag>10.2358937709</mag>
</meas>

<meas>
<utc>2018-11-10T23:05:42.500002</utc>
<ra_j2000>0.955591973177</ra_j2000>
<dec_j2000>7.5832430461</dec_j2000>
<mag>10.86206725</mag>
</meas>

<meas>
<utc>2018-11-10T23:06:48.499999</utc>
<ra_j2000>0.984093767077</ra_j2000>
<dec_j2000>7.81466175077</dec_j2000>
<mag>10.3466108708</mag>
</meas>
</data>


My problem is that I get misaligned values on these x-axes. Here is my Python script:



import math
import xml.etree.ElementTree as ET
from astropy.time import Time
from astropy.coordinates import get_sun
from datetime import datetime, timedelta
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
from matplotlib import dates

tree = ET.parse('20181110_10241.xml')
root = tree.getroot()

x_ut =
x_phi =
y_brightness =


def convert_time(obs_time):
obs_time = str(obs_time)
d, t = obs_time.split('T')
year, month, day = map(int, d.split('-'))
hour, minute, second = t.split(':')
return datetime(year, month, day, int(hour), int(minute)) +
timedelta(seconds=float(second))

def get_sun_coords(obs_time):
sun_coords = get_sun(obs_time)
sun_ra = sun_coords.ra.degree
sun_dec = sun_coords.dec.degree
return sun_ra, sun_dec

def get_phase_angle(sun_ra, sun_dec, target_ra, target_dec):
phase_angle = math.degrees(math.acos(-math.sin(math.radians(sun_dec))*math.sin(math.radians(target_dec)) - math.cos(math.radians(sun_dec))*math.cos(math.radians(target_dec))*math.cos(math.radians(sun_ra-target_ra))))
return phase_angle

for meas in root.findall('meas'):
obs_time = Time(meas.find('utc').text, format='isot', scale='utc')
target_ra = float(meas.find('ra_j2000').text)*15
target_dec = float(meas.find('dec_j2000').text)
mag = float(meas.find('mag').text)

sun_ra, sun_dec = get_sun_coords(obs_time)
phase_angle = get_phase_angle(sun_ra, sun_dec, target_ra, target_dec)

obs_time = convert_time(obs_time)
x_ut.append(obs_time)
x_phi.append(phase_angle)
y_brightness.append(mag)

fig, ax1 = plt.subplots()

ax1.plot(x_ut, y_brightness, marker='o', label='apparent brightness')
ax1.set_xlim(x_ut[0],x_ut[-1])
ax1.xaxis.set_major_locator(dates.MinuteLocator(interval=1))
ax1.xaxis.set_major_formatter(dates.DateFormatter('%H:%M'))
ax1.tick_params(axis='x', rotation=45)
ax1.minorticks_on()
ax1.legend()
ax1.grid()
ax1.set_xlabel('time [h:m, UT]')
ax1.set_ylabel('apparent brightness [mag, CR]')

ax2 = ax1.twiny()
ax2.plot(x_phi,y_brightness, marker='^', color='red')
ax2.set_xlim(x_phi[0],x_phi[-1])
ax2.xaxis.set_major_locator(ticker.MultipleLocator(1))
ax2.minorticks_on()
ax2.set_xlabel('phase angle (phi) [deg]')

plt.gca().invert_yaxis()
plt.tight_layout(pad=0)
plt.show()


Which produces the following plot:



enter image description here



I intend to hide the red curve later (by using visibility=False), here I'm plotting it only to see the proper alignment of x-axes values, namely, both curves must(!) overlap in fact, because the phase angle (x_phi) values are dependent on corresponding time-stamp (x_ut) values, but as you can clearly see, only the beginning and the end are aligned properly, but most of the data in-between is misaligned (phase curve shifted to the right).



What am I doing wrong?



Initially, I supposed, that phase angle (x_phi) was changing in time non-linearly, so that set_xlim() of both curves stretched them differently, but this is not true, I've plotted x_phi against x_ut and there is an obvious linear change:



enter image description here



Thank you for any help in advance!



EDIT: The non-linearity has been proven by tel in his answer below. Thus, I slightly change my question.



If I remove set_xlim() from both subplots ax1 and ax2, then:



1) The upper x-axis is automatically inverted, starting with the smallest value, although the list x_phi, which gives the values, starts with the largest value -- how can I avoid this inversion without using invert_axis()? (in different cases I will always have either only increasing or only decreasing values in the x_phi list)



2) There are 3 lists in total: x_ut, x_phi and y_brightness; and I need to actually plot only the curve y_brightness vs. x_ut and additionally to have the values of x_phi (with ticker.MultipleLocator(1)) aligned with corresponding values of moments of time from x_ut -- how can I do that?



My problem is similar to this one:
How do I align gridlines for two y-axis scales using Matplotlib?
But in my case there is no linear spacing between the ticks of the upper x-axis, so that I cannot use that solution.



Also, this question deals with a similar problem:
trouble aligning ticks for matplotlib twinx axes
But I dont know how to express the relation between the two x-axes in my case, because the data type is very different: datetime vs. float. The only relation between them is one-to-one, that is, the first value from x_ut is related to the first value from x_phi, the second to the second, and so forth; and this relation is non-linear.



EDIT 2: The number 1) in my previous EDIT is solved now. And for the rest of the problem, it looks like I have to use register_scale() in order to re-scale the secondary x-axis with respect to the primary x-axis. To do that I would also have to define a subclass of matplotlib.scale.ScaleBase. So far I have found only two complicated (for me) examples of how to do that:



https://matplotlib.org/examples/api/custom_scale_example.html
https://stackoverrun.com/es/q/8578801 (in Spanish, but with English comments inside the code)



I am not sure if I will be able to implement this by myself, so I still seek for any help with that.










share|improve this question

























  • If you want a concrete answer here, you may want to share a Minimal, Complete, and Verifiable example, which people can use.

    – ImportanceOfBeingErnest
    Nov 25 '18 at 0:42











  • @ImportanceOfBeingErnest I have added now a larger example of the underlying XML and have included at the bottom the conclusion regarding the non-linearity. Everything else -- my Python script -- is complete. I still hope to get some help...

    – sergiuspro
    Nov 25 '18 at 8:40











  • If you want to define a custom scale you will need a function that maps the one values to the others. Since you do not know this function, you could interpolate the values, e.g. using numpy.interp.

    – ImportanceOfBeingErnest
    Nov 25 '18 at 21:42


















1















I'm trying to use twiny() in matplotlib for plotting of a curve with two x-axes from an XML file consisting of these data blocks:



<data>
<meas>
<utc>2018-11-10T22:27:06.500003</utc>
<ra_j2000>23.9722686269</ra_j2000>
<dec_j2000>-1.23845121893</dec_j2000>
<mag>9.96074403533</mag>
</meas>

<meas>
<utc>2018-11-10T22:27:54.500002</utc>
<ra_j2000>23.9930913364</ra_j2000>
<dec_j2000>-1.03788334773</dec_j2000>
<mag>11.356437889</mag>
</meas>

<meas>
<utc>2018-11-10T22:38:36.500002</utc>
<ra_j2000>0.267638646848</ra_j2000>
<dec_j2000>1.56055091433</dec_j2000>
<mag>11.1642458641</mag>
</meas>

<meas>
<utc>2018-11-10T22:46:18.500000</utc>
<ra_j2000>0.462353662364</ra_j2000>
<dec_j2000>3.34334963425</dec_j2000>
<mag>11.1082534741</mag>
</meas>

<meas>
<utc>2018-11-10T22:57:18.500001</utc>
<ra_j2000>0.740393528722</ra_j2000>
<dec_j2000>5.78641590694</dec_j2000>
<mag>11.0688955214</mag>
</meas>

<meas>
<utc>2018-11-10T23:03:06.499995</utc>
<ra_j2000>0.888541738338</ra_j2000>
<dec_j2000>7.03265231497</dec_j2000>
<mag>10.2358937709</mag>
</meas>

<meas>
<utc>2018-11-10T23:05:42.500002</utc>
<ra_j2000>0.955591973177</ra_j2000>
<dec_j2000>7.5832430461</dec_j2000>
<mag>10.86206725</mag>
</meas>

<meas>
<utc>2018-11-10T23:06:48.499999</utc>
<ra_j2000>0.984093767077</ra_j2000>
<dec_j2000>7.81466175077</dec_j2000>
<mag>10.3466108708</mag>
</meas>
</data>


My problem is that I get misaligned values on these x-axes. Here is my Python script:



import math
import xml.etree.ElementTree as ET
from astropy.time import Time
from astropy.coordinates import get_sun
from datetime import datetime, timedelta
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
from matplotlib import dates

tree = ET.parse('20181110_10241.xml')
root = tree.getroot()

x_ut =
x_phi =
y_brightness =


def convert_time(obs_time):
obs_time = str(obs_time)
d, t = obs_time.split('T')
year, month, day = map(int, d.split('-'))
hour, minute, second = t.split(':')
return datetime(year, month, day, int(hour), int(minute)) +
timedelta(seconds=float(second))

def get_sun_coords(obs_time):
sun_coords = get_sun(obs_time)
sun_ra = sun_coords.ra.degree
sun_dec = sun_coords.dec.degree
return sun_ra, sun_dec

def get_phase_angle(sun_ra, sun_dec, target_ra, target_dec):
phase_angle = math.degrees(math.acos(-math.sin(math.radians(sun_dec))*math.sin(math.radians(target_dec)) - math.cos(math.radians(sun_dec))*math.cos(math.radians(target_dec))*math.cos(math.radians(sun_ra-target_ra))))
return phase_angle

for meas in root.findall('meas'):
obs_time = Time(meas.find('utc').text, format='isot', scale='utc')
target_ra = float(meas.find('ra_j2000').text)*15
target_dec = float(meas.find('dec_j2000').text)
mag = float(meas.find('mag').text)

sun_ra, sun_dec = get_sun_coords(obs_time)
phase_angle = get_phase_angle(sun_ra, sun_dec, target_ra, target_dec)

obs_time = convert_time(obs_time)
x_ut.append(obs_time)
x_phi.append(phase_angle)
y_brightness.append(mag)

fig, ax1 = plt.subplots()

ax1.plot(x_ut, y_brightness, marker='o', label='apparent brightness')
ax1.set_xlim(x_ut[0],x_ut[-1])
ax1.xaxis.set_major_locator(dates.MinuteLocator(interval=1))
ax1.xaxis.set_major_formatter(dates.DateFormatter('%H:%M'))
ax1.tick_params(axis='x', rotation=45)
ax1.minorticks_on()
ax1.legend()
ax1.grid()
ax1.set_xlabel('time [h:m, UT]')
ax1.set_ylabel('apparent brightness [mag, CR]')

ax2 = ax1.twiny()
ax2.plot(x_phi,y_brightness, marker='^', color='red')
ax2.set_xlim(x_phi[0],x_phi[-1])
ax2.xaxis.set_major_locator(ticker.MultipleLocator(1))
ax2.minorticks_on()
ax2.set_xlabel('phase angle (phi) [deg]')

plt.gca().invert_yaxis()
plt.tight_layout(pad=0)
plt.show()


Which produces the following plot:



enter image description here



I intend to hide the red curve later (by using visibility=False), here I'm plotting it only to see the proper alignment of x-axes values, namely, both curves must(!) overlap in fact, because the phase angle (x_phi) values are dependent on corresponding time-stamp (x_ut) values, but as you can clearly see, only the beginning and the end are aligned properly, but most of the data in-between is misaligned (phase curve shifted to the right).



What am I doing wrong?



Initially, I supposed, that phase angle (x_phi) was changing in time non-linearly, so that set_xlim() of both curves stretched them differently, but this is not true, I've plotted x_phi against x_ut and there is an obvious linear change:



enter image description here



Thank you for any help in advance!



EDIT: The non-linearity has been proven by tel in his answer below. Thus, I slightly change my question.



If I remove set_xlim() from both subplots ax1 and ax2, then:



1) The upper x-axis is automatically inverted, starting with the smallest value, although the list x_phi, which gives the values, starts with the largest value -- how can I avoid this inversion without using invert_axis()? (in different cases I will always have either only increasing or only decreasing values in the x_phi list)



2) There are 3 lists in total: x_ut, x_phi and y_brightness; and I need to actually plot only the curve y_brightness vs. x_ut and additionally to have the values of x_phi (with ticker.MultipleLocator(1)) aligned with corresponding values of moments of time from x_ut -- how can I do that?



My problem is similar to this one:
How do I align gridlines for two y-axis scales using Matplotlib?
But in my case there is no linear spacing between the ticks of the upper x-axis, so that I cannot use that solution.



Also, this question deals with a similar problem:
trouble aligning ticks for matplotlib twinx axes
But I dont know how to express the relation between the two x-axes in my case, because the data type is very different: datetime vs. float. The only relation between them is one-to-one, that is, the first value from x_ut is related to the first value from x_phi, the second to the second, and so forth; and this relation is non-linear.



EDIT 2: The number 1) in my previous EDIT is solved now. And for the rest of the problem, it looks like I have to use register_scale() in order to re-scale the secondary x-axis with respect to the primary x-axis. To do that I would also have to define a subclass of matplotlib.scale.ScaleBase. So far I have found only two complicated (for me) examples of how to do that:



https://matplotlib.org/examples/api/custom_scale_example.html
https://stackoverrun.com/es/q/8578801 (in Spanish, but with English comments inside the code)



I am not sure if I will be able to implement this by myself, so I still seek for any help with that.










share|improve this question

























  • If you want a concrete answer here, you may want to share a Minimal, Complete, and Verifiable example, which people can use.

    – ImportanceOfBeingErnest
    Nov 25 '18 at 0:42











  • @ImportanceOfBeingErnest I have added now a larger example of the underlying XML and have included at the bottom the conclusion regarding the non-linearity. Everything else -- my Python script -- is complete. I still hope to get some help...

    – sergiuspro
    Nov 25 '18 at 8:40











  • If you want to define a custom scale you will need a function that maps the one values to the others. Since you do not know this function, you could interpolate the values, e.g. using numpy.interp.

    – ImportanceOfBeingErnest
    Nov 25 '18 at 21:42














1












1








1








I'm trying to use twiny() in matplotlib for plotting of a curve with two x-axes from an XML file consisting of these data blocks:



<data>
<meas>
<utc>2018-11-10T22:27:06.500003</utc>
<ra_j2000>23.9722686269</ra_j2000>
<dec_j2000>-1.23845121893</dec_j2000>
<mag>9.96074403533</mag>
</meas>

<meas>
<utc>2018-11-10T22:27:54.500002</utc>
<ra_j2000>23.9930913364</ra_j2000>
<dec_j2000>-1.03788334773</dec_j2000>
<mag>11.356437889</mag>
</meas>

<meas>
<utc>2018-11-10T22:38:36.500002</utc>
<ra_j2000>0.267638646848</ra_j2000>
<dec_j2000>1.56055091433</dec_j2000>
<mag>11.1642458641</mag>
</meas>

<meas>
<utc>2018-11-10T22:46:18.500000</utc>
<ra_j2000>0.462353662364</ra_j2000>
<dec_j2000>3.34334963425</dec_j2000>
<mag>11.1082534741</mag>
</meas>

<meas>
<utc>2018-11-10T22:57:18.500001</utc>
<ra_j2000>0.740393528722</ra_j2000>
<dec_j2000>5.78641590694</dec_j2000>
<mag>11.0688955214</mag>
</meas>

<meas>
<utc>2018-11-10T23:03:06.499995</utc>
<ra_j2000>0.888541738338</ra_j2000>
<dec_j2000>7.03265231497</dec_j2000>
<mag>10.2358937709</mag>
</meas>

<meas>
<utc>2018-11-10T23:05:42.500002</utc>
<ra_j2000>0.955591973177</ra_j2000>
<dec_j2000>7.5832430461</dec_j2000>
<mag>10.86206725</mag>
</meas>

<meas>
<utc>2018-11-10T23:06:48.499999</utc>
<ra_j2000>0.984093767077</ra_j2000>
<dec_j2000>7.81466175077</dec_j2000>
<mag>10.3466108708</mag>
</meas>
</data>


My problem is that I get misaligned values on these x-axes. Here is my Python script:



import math
import xml.etree.ElementTree as ET
from astropy.time import Time
from astropy.coordinates import get_sun
from datetime import datetime, timedelta
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
from matplotlib import dates

tree = ET.parse('20181110_10241.xml')
root = tree.getroot()

x_ut =
x_phi =
y_brightness =


def convert_time(obs_time):
obs_time = str(obs_time)
d, t = obs_time.split('T')
year, month, day = map(int, d.split('-'))
hour, minute, second = t.split(':')
return datetime(year, month, day, int(hour), int(minute)) +
timedelta(seconds=float(second))

def get_sun_coords(obs_time):
sun_coords = get_sun(obs_time)
sun_ra = sun_coords.ra.degree
sun_dec = sun_coords.dec.degree
return sun_ra, sun_dec

def get_phase_angle(sun_ra, sun_dec, target_ra, target_dec):
phase_angle = math.degrees(math.acos(-math.sin(math.radians(sun_dec))*math.sin(math.radians(target_dec)) - math.cos(math.radians(sun_dec))*math.cos(math.radians(target_dec))*math.cos(math.radians(sun_ra-target_ra))))
return phase_angle

for meas in root.findall('meas'):
obs_time = Time(meas.find('utc').text, format='isot', scale='utc')
target_ra = float(meas.find('ra_j2000').text)*15
target_dec = float(meas.find('dec_j2000').text)
mag = float(meas.find('mag').text)

sun_ra, sun_dec = get_sun_coords(obs_time)
phase_angle = get_phase_angle(sun_ra, sun_dec, target_ra, target_dec)

obs_time = convert_time(obs_time)
x_ut.append(obs_time)
x_phi.append(phase_angle)
y_brightness.append(mag)

fig, ax1 = plt.subplots()

ax1.plot(x_ut, y_brightness, marker='o', label='apparent brightness')
ax1.set_xlim(x_ut[0],x_ut[-1])
ax1.xaxis.set_major_locator(dates.MinuteLocator(interval=1))
ax1.xaxis.set_major_formatter(dates.DateFormatter('%H:%M'))
ax1.tick_params(axis='x', rotation=45)
ax1.minorticks_on()
ax1.legend()
ax1.grid()
ax1.set_xlabel('time [h:m, UT]')
ax1.set_ylabel('apparent brightness [mag, CR]')

ax2 = ax1.twiny()
ax2.plot(x_phi,y_brightness, marker='^', color='red')
ax2.set_xlim(x_phi[0],x_phi[-1])
ax2.xaxis.set_major_locator(ticker.MultipleLocator(1))
ax2.minorticks_on()
ax2.set_xlabel('phase angle (phi) [deg]')

plt.gca().invert_yaxis()
plt.tight_layout(pad=0)
plt.show()


Which produces the following plot:



enter image description here



I intend to hide the red curve later (by using visibility=False), here I'm plotting it only to see the proper alignment of x-axes values, namely, both curves must(!) overlap in fact, because the phase angle (x_phi) values are dependent on corresponding time-stamp (x_ut) values, but as you can clearly see, only the beginning and the end are aligned properly, but most of the data in-between is misaligned (phase curve shifted to the right).



What am I doing wrong?



Initially, I supposed, that phase angle (x_phi) was changing in time non-linearly, so that set_xlim() of both curves stretched them differently, but this is not true, I've plotted x_phi against x_ut and there is an obvious linear change:



enter image description here



Thank you for any help in advance!



EDIT: The non-linearity has been proven by tel in his answer below. Thus, I slightly change my question.



If I remove set_xlim() from both subplots ax1 and ax2, then:



1) The upper x-axis is automatically inverted, starting with the smallest value, although the list x_phi, which gives the values, starts with the largest value -- how can I avoid this inversion without using invert_axis()? (in different cases I will always have either only increasing or only decreasing values in the x_phi list)



2) There are 3 lists in total: x_ut, x_phi and y_brightness; and I need to actually plot only the curve y_brightness vs. x_ut and additionally to have the values of x_phi (with ticker.MultipleLocator(1)) aligned with corresponding values of moments of time from x_ut -- how can I do that?



My problem is similar to this one:
How do I align gridlines for two y-axis scales using Matplotlib?
But in my case there is no linear spacing between the ticks of the upper x-axis, so that I cannot use that solution.



Also, this question deals with a similar problem:
trouble aligning ticks for matplotlib twinx axes
But I dont know how to express the relation between the two x-axes in my case, because the data type is very different: datetime vs. float. The only relation between them is one-to-one, that is, the first value from x_ut is related to the first value from x_phi, the second to the second, and so forth; and this relation is non-linear.



EDIT 2: The number 1) in my previous EDIT is solved now. And for the rest of the problem, it looks like I have to use register_scale() in order to re-scale the secondary x-axis with respect to the primary x-axis. To do that I would also have to define a subclass of matplotlib.scale.ScaleBase. So far I have found only two complicated (for me) examples of how to do that:



https://matplotlib.org/examples/api/custom_scale_example.html
https://stackoverrun.com/es/q/8578801 (in Spanish, but with English comments inside the code)



I am not sure if I will be able to implement this by myself, so I still seek for any help with that.










share|improve this question
















I'm trying to use twiny() in matplotlib for plotting of a curve with two x-axes from an XML file consisting of these data blocks:



<data>
<meas>
<utc>2018-11-10T22:27:06.500003</utc>
<ra_j2000>23.9722686269</ra_j2000>
<dec_j2000>-1.23845121893</dec_j2000>
<mag>9.96074403533</mag>
</meas>

<meas>
<utc>2018-11-10T22:27:54.500002</utc>
<ra_j2000>23.9930913364</ra_j2000>
<dec_j2000>-1.03788334773</dec_j2000>
<mag>11.356437889</mag>
</meas>

<meas>
<utc>2018-11-10T22:38:36.500002</utc>
<ra_j2000>0.267638646848</ra_j2000>
<dec_j2000>1.56055091433</dec_j2000>
<mag>11.1642458641</mag>
</meas>

<meas>
<utc>2018-11-10T22:46:18.500000</utc>
<ra_j2000>0.462353662364</ra_j2000>
<dec_j2000>3.34334963425</dec_j2000>
<mag>11.1082534741</mag>
</meas>

<meas>
<utc>2018-11-10T22:57:18.500001</utc>
<ra_j2000>0.740393528722</ra_j2000>
<dec_j2000>5.78641590694</dec_j2000>
<mag>11.0688955214</mag>
</meas>

<meas>
<utc>2018-11-10T23:03:06.499995</utc>
<ra_j2000>0.888541738338</ra_j2000>
<dec_j2000>7.03265231497</dec_j2000>
<mag>10.2358937709</mag>
</meas>

<meas>
<utc>2018-11-10T23:05:42.500002</utc>
<ra_j2000>0.955591973177</ra_j2000>
<dec_j2000>7.5832430461</dec_j2000>
<mag>10.86206725</mag>
</meas>

<meas>
<utc>2018-11-10T23:06:48.499999</utc>
<ra_j2000>0.984093767077</ra_j2000>
<dec_j2000>7.81466175077</dec_j2000>
<mag>10.3466108708</mag>
</meas>
</data>


My problem is that I get misaligned values on these x-axes. Here is my Python script:



import math
import xml.etree.ElementTree as ET
from astropy.time import Time
from astropy.coordinates import get_sun
from datetime import datetime, timedelta
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
from matplotlib import dates

tree = ET.parse('20181110_10241.xml')
root = tree.getroot()

x_ut =
x_phi =
y_brightness =


def convert_time(obs_time):
obs_time = str(obs_time)
d, t = obs_time.split('T')
year, month, day = map(int, d.split('-'))
hour, minute, second = t.split(':')
return datetime(year, month, day, int(hour), int(minute)) +
timedelta(seconds=float(second))

def get_sun_coords(obs_time):
sun_coords = get_sun(obs_time)
sun_ra = sun_coords.ra.degree
sun_dec = sun_coords.dec.degree
return sun_ra, sun_dec

def get_phase_angle(sun_ra, sun_dec, target_ra, target_dec):
phase_angle = math.degrees(math.acos(-math.sin(math.radians(sun_dec))*math.sin(math.radians(target_dec)) - math.cos(math.radians(sun_dec))*math.cos(math.radians(target_dec))*math.cos(math.radians(sun_ra-target_ra))))
return phase_angle

for meas in root.findall('meas'):
obs_time = Time(meas.find('utc').text, format='isot', scale='utc')
target_ra = float(meas.find('ra_j2000').text)*15
target_dec = float(meas.find('dec_j2000').text)
mag = float(meas.find('mag').text)

sun_ra, sun_dec = get_sun_coords(obs_time)
phase_angle = get_phase_angle(sun_ra, sun_dec, target_ra, target_dec)

obs_time = convert_time(obs_time)
x_ut.append(obs_time)
x_phi.append(phase_angle)
y_brightness.append(mag)

fig, ax1 = plt.subplots()

ax1.plot(x_ut, y_brightness, marker='o', label='apparent brightness')
ax1.set_xlim(x_ut[0],x_ut[-1])
ax1.xaxis.set_major_locator(dates.MinuteLocator(interval=1))
ax1.xaxis.set_major_formatter(dates.DateFormatter('%H:%M'))
ax1.tick_params(axis='x', rotation=45)
ax1.minorticks_on()
ax1.legend()
ax1.grid()
ax1.set_xlabel('time [h:m, UT]')
ax1.set_ylabel('apparent brightness [mag, CR]')

ax2 = ax1.twiny()
ax2.plot(x_phi,y_brightness, marker='^', color='red')
ax2.set_xlim(x_phi[0],x_phi[-1])
ax2.xaxis.set_major_locator(ticker.MultipleLocator(1))
ax2.minorticks_on()
ax2.set_xlabel('phase angle (phi) [deg]')

plt.gca().invert_yaxis()
plt.tight_layout(pad=0)
plt.show()


Which produces the following plot:



enter image description here



I intend to hide the red curve later (by using visibility=False), here I'm plotting it only to see the proper alignment of x-axes values, namely, both curves must(!) overlap in fact, because the phase angle (x_phi) values are dependent on corresponding time-stamp (x_ut) values, but as you can clearly see, only the beginning and the end are aligned properly, but most of the data in-between is misaligned (phase curve shifted to the right).



What am I doing wrong?



Initially, I supposed, that phase angle (x_phi) was changing in time non-linearly, so that set_xlim() of both curves stretched them differently, but this is not true, I've plotted x_phi against x_ut and there is an obvious linear change:



enter image description here



Thank you for any help in advance!



EDIT: The non-linearity has been proven by tel in his answer below. Thus, I slightly change my question.



If I remove set_xlim() from both subplots ax1 and ax2, then:



1) The upper x-axis is automatically inverted, starting with the smallest value, although the list x_phi, which gives the values, starts with the largest value -- how can I avoid this inversion without using invert_axis()? (in different cases I will always have either only increasing or only decreasing values in the x_phi list)



2) There are 3 lists in total: x_ut, x_phi and y_brightness; and I need to actually plot only the curve y_brightness vs. x_ut and additionally to have the values of x_phi (with ticker.MultipleLocator(1)) aligned with corresponding values of moments of time from x_ut -- how can I do that?



My problem is similar to this one:
How do I align gridlines for two y-axis scales using Matplotlib?
But in my case there is no linear spacing between the ticks of the upper x-axis, so that I cannot use that solution.



Also, this question deals with a similar problem:
trouble aligning ticks for matplotlib twinx axes
But I dont know how to express the relation between the two x-axes in my case, because the data type is very different: datetime vs. float. The only relation between them is one-to-one, that is, the first value from x_ut is related to the first value from x_phi, the second to the second, and so forth; and this relation is non-linear.



EDIT 2: The number 1) in my previous EDIT is solved now. And for the rest of the problem, it looks like I have to use register_scale() in order to re-scale the secondary x-axis with respect to the primary x-axis. To do that I would also have to define a subclass of matplotlib.scale.ScaleBase. So far I have found only two complicated (for me) examples of how to do that:



https://matplotlib.org/examples/api/custom_scale_example.html
https://stackoverrun.com/es/q/8578801 (in Spanish, but with English comments inside the code)



I am not sure if I will be able to implement this by myself, so I still seek for any help with that.







python matplotlib alignment axes






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 25 '18 at 15:22







sergiuspro

















asked Nov 24 '18 at 14:05









sergiusprosergiuspro

205




205













  • If you want a concrete answer here, you may want to share a Minimal, Complete, and Verifiable example, which people can use.

    – ImportanceOfBeingErnest
    Nov 25 '18 at 0:42











  • @ImportanceOfBeingErnest I have added now a larger example of the underlying XML and have included at the bottom the conclusion regarding the non-linearity. Everything else -- my Python script -- is complete. I still hope to get some help...

    – sergiuspro
    Nov 25 '18 at 8:40











  • If you want to define a custom scale you will need a function that maps the one values to the others. Since you do not know this function, you could interpolate the values, e.g. using numpy.interp.

    – ImportanceOfBeingErnest
    Nov 25 '18 at 21:42



















  • If you want a concrete answer here, you may want to share a Minimal, Complete, and Verifiable example, which people can use.

    – ImportanceOfBeingErnest
    Nov 25 '18 at 0:42











  • @ImportanceOfBeingErnest I have added now a larger example of the underlying XML and have included at the bottom the conclusion regarding the non-linearity. Everything else -- my Python script -- is complete. I still hope to get some help...

    – sergiuspro
    Nov 25 '18 at 8:40











  • If you want to define a custom scale you will need a function that maps the one values to the others. Since you do not know this function, you could interpolate the values, e.g. using numpy.interp.

    – ImportanceOfBeingErnest
    Nov 25 '18 at 21:42

















If you want a concrete answer here, you may want to share a Minimal, Complete, and Verifiable example, which people can use.

– ImportanceOfBeingErnest
Nov 25 '18 at 0:42





If you want a concrete answer here, you may want to share a Minimal, Complete, and Verifiable example, which people can use.

– ImportanceOfBeingErnest
Nov 25 '18 at 0:42













@ImportanceOfBeingErnest I have added now a larger example of the underlying XML and have included at the bottom the conclusion regarding the non-linearity. Everything else -- my Python script -- is complete. I still hope to get some help...

– sergiuspro
Nov 25 '18 at 8:40





@ImportanceOfBeingErnest I have added now a larger example of the underlying XML and have included at the bottom the conclusion regarding the non-linearity. Everything else -- my Python script -- is complete. I still hope to get some help...

– sergiuspro
Nov 25 '18 at 8:40













If you want to define a custom scale you will need a function that maps the one values to the others. Since you do not know this function, you could interpolate the values, e.g. using numpy.interp.

– ImportanceOfBeingErnest
Nov 25 '18 at 21:42





If you want to define a custom scale you will need a function that maps the one values to the others. Since you do not know this function, you could interpolate the values, e.g. using numpy.interp.

– ImportanceOfBeingErnest
Nov 25 '18 at 21:42












2 Answers
2






active

oldest

votes


















0














Your plotting routine looks correct. Instead, it looks like the problem is that there is a (very small) deviation from linearity in the relationship between time and phase angle. You can see it by overlaying a straight black line on the time vs angle graph (click below to open in a separate window and zoom in to see it clearly):



enter image description here



Here's a zoom that highlights the deviation:



enter image description here



The only ways to get your two x-axes to line up would be:




  • Manipulate the data.

  • Manipulate the scale of the second x-axis to make it inconsistent. Make it so that the actual distance on the plot between 49 and 48 degrees is different from the actual distance on the plot between 45 and 44 degrees, and so forth.


Both of these are A Bad Idea™️, and you shouldn't do either one. You need to plot your data as is, rather than trying to hide any inconsistencies with clever tricks. Anything less could be considered academic dishonesty.



Your only option is to get to the bottom of why time and angle don't match up like you expect. It could be an issue in your code, maybe in the formula you use in get_phase_angle. Or it could be a problem in your underlying dataset, for example if there's some noise in the degree measurements. Or it could just be that, in reality, time and angle don't have a linear relationship. After all, the earth isn't perfectly round.






share|improve this answer


























  • OK, let's assume there is some non-linearity; then, I guess, I have to slightly change my question into: how can I set up the upper x-axis (phase angle) in such a way, that the phase angle values are properly scaled and aligned with time values? If I just remove the set_xlim(), then a strange thing happens: the upper x-axis is automatically reverted starting with the lowest value of ~30, although it should start with ~49.

    – sergiuspro
    Nov 24 '18 at 14:30











  • @sergiuspro Fundamentally, you'd have to give the second x-axis an inconsistent scale, so that the actual distance on the plot between, for example, 49 and 48 deg would be different from the actual distance between 45 and 44 degrees. Are you sure that's actually what you want?

    – tel
    Nov 24 '18 at 15:32











  • Yes, the ticks of the upper x-axis would be spread at different (gradually increasing or decreasing) distances and that's absolutely fine. With my plot I want to demonstrate two things at once: the brightness at a given moment of time (only this one should actually be plotted) and the same brightness at a given phase angle, while the corresponding phase angle is aligned with the corresponding moment of time.

    – sergiuspro
    Nov 24 '18 at 15:41











  • @sergiuspro Don't do that, it's a terrible idea. I added a note to my answer explaining why.

    – tel
    Nov 24 '18 at 16:10











  • I still dont understand why is it impossible to plot it the way I need. We have a time-series. At every moment of time the object has some brightness and is located at some phase angle. These two things -- brightness and phase angle -- are bound(!) to the time moment. The formula for phase angle calculation is correct. Both brightness and phase angle change with time. It's kind of a 3-element tuple. As you have seen in my Python script, there are 3 lists, so for every x_ut value there is one y_brightness and one x_phi value. How do I plot y_brightness vs. x_ut and only show x_phi at x_ut?

    – sergiuspro
    Nov 24 '18 at 16:21





















0














Yay! I've managed to get the sought result without defining a new scale class! Here are the relevant code parts which have been added/modified in the script from the question (the variable step will be later read from the user command line input, or I might find another way of automated tick frequency setting):



x_ut = 
x_phi =
x_phi_ticks =
x_phi_ticklabels =
y_brightness =

# populate lists for the phase angle ticks and labels

i = 0
step = 15
while i <= (len(x_ut)-step):
x_phi_ticks.append(x_ut[i])
x_phi_ticklabels.append(x_phi[i])
i += step
x_phi_ticks.append(x_ut[-1])
x_phi_ticklabels.append(x_phi[-1])

# plot'em all

fig, ax1 = plt.subplots()

ax1.plot(x_ut, y_brightness, marker='o', label='apparent brightness')
ax1.xaxis.set_major_locator(dates.MinuteLocator(interval=1))
ax1.xaxis.set_major_formatter(dates.DateFormatter('%H:%M'))
ax1.tick_params(axis='x', rotation=45)
ax1.minorticks_on()
ax1.legend()
ax1.grid(which='major', linestyle='-', color='#000000')
ax1.grid(which='minor', linestyle='--')
ax1.set_xlabel('time [h:m, UT]')
ax1.set_ylabel('apparent brightness [mag, CR]')

ax2 = ax1.twiny()
ax2.set_xlim(ax1.get_xlim())
ax2.set_xticks(x_phi_ticks)
ax2.set_xticklabels(x_phi_ticklabels)
ax2.set_xlabel('phase angle (phi) [deg]')

plt.gca().invert_yaxis()
plt.tight_layout(pad=0)
plt.show()


enter image description here






share|improve this answer
























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53458959%2fmatplotlib-twiny-how-to-align-values-of-two-x-axes-in-one-plot%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    0














    Your plotting routine looks correct. Instead, it looks like the problem is that there is a (very small) deviation from linearity in the relationship between time and phase angle. You can see it by overlaying a straight black line on the time vs angle graph (click below to open in a separate window and zoom in to see it clearly):



    enter image description here



    Here's a zoom that highlights the deviation:



    enter image description here



    The only ways to get your two x-axes to line up would be:




    • Manipulate the data.

    • Manipulate the scale of the second x-axis to make it inconsistent. Make it so that the actual distance on the plot between 49 and 48 degrees is different from the actual distance on the plot between 45 and 44 degrees, and so forth.


    Both of these are A Bad Idea™️, and you shouldn't do either one. You need to plot your data as is, rather than trying to hide any inconsistencies with clever tricks. Anything less could be considered academic dishonesty.



    Your only option is to get to the bottom of why time and angle don't match up like you expect. It could be an issue in your code, maybe in the formula you use in get_phase_angle. Or it could be a problem in your underlying dataset, for example if there's some noise in the degree measurements. Or it could just be that, in reality, time and angle don't have a linear relationship. After all, the earth isn't perfectly round.






    share|improve this answer


























    • OK, let's assume there is some non-linearity; then, I guess, I have to slightly change my question into: how can I set up the upper x-axis (phase angle) in such a way, that the phase angle values are properly scaled and aligned with time values? If I just remove the set_xlim(), then a strange thing happens: the upper x-axis is automatically reverted starting with the lowest value of ~30, although it should start with ~49.

      – sergiuspro
      Nov 24 '18 at 14:30











    • @sergiuspro Fundamentally, you'd have to give the second x-axis an inconsistent scale, so that the actual distance on the plot between, for example, 49 and 48 deg would be different from the actual distance between 45 and 44 degrees. Are you sure that's actually what you want?

      – tel
      Nov 24 '18 at 15:32











    • Yes, the ticks of the upper x-axis would be spread at different (gradually increasing or decreasing) distances and that's absolutely fine. With my plot I want to demonstrate two things at once: the brightness at a given moment of time (only this one should actually be plotted) and the same brightness at a given phase angle, while the corresponding phase angle is aligned with the corresponding moment of time.

      – sergiuspro
      Nov 24 '18 at 15:41











    • @sergiuspro Don't do that, it's a terrible idea. I added a note to my answer explaining why.

      – tel
      Nov 24 '18 at 16:10











    • I still dont understand why is it impossible to plot it the way I need. We have a time-series. At every moment of time the object has some brightness and is located at some phase angle. These two things -- brightness and phase angle -- are bound(!) to the time moment. The formula for phase angle calculation is correct. Both brightness and phase angle change with time. It's kind of a 3-element tuple. As you have seen in my Python script, there are 3 lists, so for every x_ut value there is one y_brightness and one x_phi value. How do I plot y_brightness vs. x_ut and only show x_phi at x_ut?

      – sergiuspro
      Nov 24 '18 at 16:21


















    0














    Your plotting routine looks correct. Instead, it looks like the problem is that there is a (very small) deviation from linearity in the relationship between time and phase angle. You can see it by overlaying a straight black line on the time vs angle graph (click below to open in a separate window and zoom in to see it clearly):



    enter image description here



    Here's a zoom that highlights the deviation:



    enter image description here



    The only ways to get your two x-axes to line up would be:




    • Manipulate the data.

    • Manipulate the scale of the second x-axis to make it inconsistent. Make it so that the actual distance on the plot between 49 and 48 degrees is different from the actual distance on the plot between 45 and 44 degrees, and so forth.


    Both of these are A Bad Idea™️, and you shouldn't do either one. You need to plot your data as is, rather than trying to hide any inconsistencies with clever tricks. Anything less could be considered academic dishonesty.



    Your only option is to get to the bottom of why time and angle don't match up like you expect. It could be an issue in your code, maybe in the formula you use in get_phase_angle. Or it could be a problem in your underlying dataset, for example if there's some noise in the degree measurements. Or it could just be that, in reality, time and angle don't have a linear relationship. After all, the earth isn't perfectly round.






    share|improve this answer


























    • OK, let's assume there is some non-linearity; then, I guess, I have to slightly change my question into: how can I set up the upper x-axis (phase angle) in such a way, that the phase angle values are properly scaled and aligned with time values? If I just remove the set_xlim(), then a strange thing happens: the upper x-axis is automatically reverted starting with the lowest value of ~30, although it should start with ~49.

      – sergiuspro
      Nov 24 '18 at 14:30











    • @sergiuspro Fundamentally, you'd have to give the second x-axis an inconsistent scale, so that the actual distance on the plot between, for example, 49 and 48 deg would be different from the actual distance between 45 and 44 degrees. Are you sure that's actually what you want?

      – tel
      Nov 24 '18 at 15:32











    • Yes, the ticks of the upper x-axis would be spread at different (gradually increasing or decreasing) distances and that's absolutely fine. With my plot I want to demonstrate two things at once: the brightness at a given moment of time (only this one should actually be plotted) and the same brightness at a given phase angle, while the corresponding phase angle is aligned with the corresponding moment of time.

      – sergiuspro
      Nov 24 '18 at 15:41











    • @sergiuspro Don't do that, it's a terrible idea. I added a note to my answer explaining why.

      – tel
      Nov 24 '18 at 16:10











    • I still dont understand why is it impossible to plot it the way I need. We have a time-series. At every moment of time the object has some brightness and is located at some phase angle. These two things -- brightness and phase angle -- are bound(!) to the time moment. The formula for phase angle calculation is correct. Both brightness and phase angle change with time. It's kind of a 3-element tuple. As you have seen in my Python script, there are 3 lists, so for every x_ut value there is one y_brightness and one x_phi value. How do I plot y_brightness vs. x_ut and only show x_phi at x_ut?

      – sergiuspro
      Nov 24 '18 at 16:21
















    0












    0








    0







    Your plotting routine looks correct. Instead, it looks like the problem is that there is a (very small) deviation from linearity in the relationship between time and phase angle. You can see it by overlaying a straight black line on the time vs angle graph (click below to open in a separate window and zoom in to see it clearly):



    enter image description here



    Here's a zoom that highlights the deviation:



    enter image description here



    The only ways to get your two x-axes to line up would be:




    • Manipulate the data.

    • Manipulate the scale of the second x-axis to make it inconsistent. Make it so that the actual distance on the plot between 49 and 48 degrees is different from the actual distance on the plot between 45 and 44 degrees, and so forth.


    Both of these are A Bad Idea™️, and you shouldn't do either one. You need to plot your data as is, rather than trying to hide any inconsistencies with clever tricks. Anything less could be considered academic dishonesty.



    Your only option is to get to the bottom of why time and angle don't match up like you expect. It could be an issue in your code, maybe in the formula you use in get_phase_angle. Or it could be a problem in your underlying dataset, for example if there's some noise in the degree measurements. Or it could just be that, in reality, time and angle don't have a linear relationship. After all, the earth isn't perfectly round.






    share|improve this answer















    Your plotting routine looks correct. Instead, it looks like the problem is that there is a (very small) deviation from linearity in the relationship between time and phase angle. You can see it by overlaying a straight black line on the time vs angle graph (click below to open in a separate window and zoom in to see it clearly):



    enter image description here



    Here's a zoom that highlights the deviation:



    enter image description here



    The only ways to get your two x-axes to line up would be:




    • Manipulate the data.

    • Manipulate the scale of the second x-axis to make it inconsistent. Make it so that the actual distance on the plot between 49 and 48 degrees is different from the actual distance on the plot between 45 and 44 degrees, and so forth.


    Both of these are A Bad Idea™️, and you shouldn't do either one. You need to plot your data as is, rather than trying to hide any inconsistencies with clever tricks. Anything less could be considered academic dishonesty.



    Your only option is to get to the bottom of why time and angle don't match up like you expect. It could be an issue in your code, maybe in the formula you use in get_phase_angle. Or it could be a problem in your underlying dataset, for example if there's some noise in the degree measurements. Or it could just be that, in reality, time and angle don't have a linear relationship. After all, the earth isn't perfectly round.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Nov 24 '18 at 16:10

























    answered Nov 24 '18 at 14:22









    teltel

    7,53921433




    7,53921433













    • OK, let's assume there is some non-linearity; then, I guess, I have to slightly change my question into: how can I set up the upper x-axis (phase angle) in such a way, that the phase angle values are properly scaled and aligned with time values? If I just remove the set_xlim(), then a strange thing happens: the upper x-axis is automatically reverted starting with the lowest value of ~30, although it should start with ~49.

      – sergiuspro
      Nov 24 '18 at 14:30











    • @sergiuspro Fundamentally, you'd have to give the second x-axis an inconsistent scale, so that the actual distance on the plot between, for example, 49 and 48 deg would be different from the actual distance between 45 and 44 degrees. Are you sure that's actually what you want?

      – tel
      Nov 24 '18 at 15:32











    • Yes, the ticks of the upper x-axis would be spread at different (gradually increasing or decreasing) distances and that's absolutely fine. With my plot I want to demonstrate two things at once: the brightness at a given moment of time (only this one should actually be plotted) and the same brightness at a given phase angle, while the corresponding phase angle is aligned with the corresponding moment of time.

      – sergiuspro
      Nov 24 '18 at 15:41











    • @sergiuspro Don't do that, it's a terrible idea. I added a note to my answer explaining why.

      – tel
      Nov 24 '18 at 16:10











    • I still dont understand why is it impossible to plot it the way I need. We have a time-series. At every moment of time the object has some brightness and is located at some phase angle. These two things -- brightness and phase angle -- are bound(!) to the time moment. The formula for phase angle calculation is correct. Both brightness and phase angle change with time. It's kind of a 3-element tuple. As you have seen in my Python script, there are 3 lists, so for every x_ut value there is one y_brightness and one x_phi value. How do I plot y_brightness vs. x_ut and only show x_phi at x_ut?

      – sergiuspro
      Nov 24 '18 at 16:21





















    • OK, let's assume there is some non-linearity; then, I guess, I have to slightly change my question into: how can I set up the upper x-axis (phase angle) in such a way, that the phase angle values are properly scaled and aligned with time values? If I just remove the set_xlim(), then a strange thing happens: the upper x-axis is automatically reverted starting with the lowest value of ~30, although it should start with ~49.

      – sergiuspro
      Nov 24 '18 at 14:30











    • @sergiuspro Fundamentally, you'd have to give the second x-axis an inconsistent scale, so that the actual distance on the plot between, for example, 49 and 48 deg would be different from the actual distance between 45 and 44 degrees. Are you sure that's actually what you want?

      – tel
      Nov 24 '18 at 15:32











    • Yes, the ticks of the upper x-axis would be spread at different (gradually increasing or decreasing) distances and that's absolutely fine. With my plot I want to demonstrate two things at once: the brightness at a given moment of time (only this one should actually be plotted) and the same brightness at a given phase angle, while the corresponding phase angle is aligned with the corresponding moment of time.

      – sergiuspro
      Nov 24 '18 at 15:41











    • @sergiuspro Don't do that, it's a terrible idea. I added a note to my answer explaining why.

      – tel
      Nov 24 '18 at 16:10











    • I still dont understand why is it impossible to plot it the way I need. We have a time-series. At every moment of time the object has some brightness and is located at some phase angle. These two things -- brightness and phase angle -- are bound(!) to the time moment. The formula for phase angle calculation is correct. Both brightness and phase angle change with time. It's kind of a 3-element tuple. As you have seen in my Python script, there are 3 lists, so for every x_ut value there is one y_brightness and one x_phi value. How do I plot y_brightness vs. x_ut and only show x_phi at x_ut?

      – sergiuspro
      Nov 24 '18 at 16:21



















    OK, let's assume there is some non-linearity; then, I guess, I have to slightly change my question into: how can I set up the upper x-axis (phase angle) in such a way, that the phase angle values are properly scaled and aligned with time values? If I just remove the set_xlim(), then a strange thing happens: the upper x-axis is automatically reverted starting with the lowest value of ~30, although it should start with ~49.

    – sergiuspro
    Nov 24 '18 at 14:30





    OK, let's assume there is some non-linearity; then, I guess, I have to slightly change my question into: how can I set up the upper x-axis (phase angle) in such a way, that the phase angle values are properly scaled and aligned with time values? If I just remove the set_xlim(), then a strange thing happens: the upper x-axis is automatically reverted starting with the lowest value of ~30, although it should start with ~49.

    – sergiuspro
    Nov 24 '18 at 14:30













    @sergiuspro Fundamentally, you'd have to give the second x-axis an inconsistent scale, so that the actual distance on the plot between, for example, 49 and 48 deg would be different from the actual distance between 45 and 44 degrees. Are you sure that's actually what you want?

    – tel
    Nov 24 '18 at 15:32





    @sergiuspro Fundamentally, you'd have to give the second x-axis an inconsistent scale, so that the actual distance on the plot between, for example, 49 and 48 deg would be different from the actual distance between 45 and 44 degrees. Are you sure that's actually what you want?

    – tel
    Nov 24 '18 at 15:32













    Yes, the ticks of the upper x-axis would be spread at different (gradually increasing or decreasing) distances and that's absolutely fine. With my plot I want to demonstrate two things at once: the brightness at a given moment of time (only this one should actually be plotted) and the same brightness at a given phase angle, while the corresponding phase angle is aligned with the corresponding moment of time.

    – sergiuspro
    Nov 24 '18 at 15:41





    Yes, the ticks of the upper x-axis would be spread at different (gradually increasing or decreasing) distances and that's absolutely fine. With my plot I want to demonstrate two things at once: the brightness at a given moment of time (only this one should actually be plotted) and the same brightness at a given phase angle, while the corresponding phase angle is aligned with the corresponding moment of time.

    – sergiuspro
    Nov 24 '18 at 15:41













    @sergiuspro Don't do that, it's a terrible idea. I added a note to my answer explaining why.

    – tel
    Nov 24 '18 at 16:10





    @sergiuspro Don't do that, it's a terrible idea. I added a note to my answer explaining why.

    – tel
    Nov 24 '18 at 16:10













    I still dont understand why is it impossible to plot it the way I need. We have a time-series. At every moment of time the object has some brightness and is located at some phase angle. These two things -- brightness and phase angle -- are bound(!) to the time moment. The formula for phase angle calculation is correct. Both brightness and phase angle change with time. It's kind of a 3-element tuple. As you have seen in my Python script, there are 3 lists, so for every x_ut value there is one y_brightness and one x_phi value. How do I plot y_brightness vs. x_ut and only show x_phi at x_ut?

    – sergiuspro
    Nov 24 '18 at 16:21







    I still dont understand why is it impossible to plot it the way I need. We have a time-series. At every moment of time the object has some brightness and is located at some phase angle. These two things -- brightness and phase angle -- are bound(!) to the time moment. The formula for phase angle calculation is correct. Both brightness and phase angle change with time. It's kind of a 3-element tuple. As you have seen in my Python script, there are 3 lists, so for every x_ut value there is one y_brightness and one x_phi value. How do I plot y_brightness vs. x_ut and only show x_phi at x_ut?

    – sergiuspro
    Nov 24 '18 at 16:21















    0














    Yay! I've managed to get the sought result without defining a new scale class! Here are the relevant code parts which have been added/modified in the script from the question (the variable step will be later read from the user command line input, or I might find another way of automated tick frequency setting):



    x_ut = 
    x_phi =
    x_phi_ticks =
    x_phi_ticklabels =
    y_brightness =

    # populate lists for the phase angle ticks and labels

    i = 0
    step = 15
    while i <= (len(x_ut)-step):
    x_phi_ticks.append(x_ut[i])
    x_phi_ticklabels.append(x_phi[i])
    i += step
    x_phi_ticks.append(x_ut[-1])
    x_phi_ticklabels.append(x_phi[-1])

    # plot'em all

    fig, ax1 = plt.subplots()

    ax1.plot(x_ut, y_brightness, marker='o', label='apparent brightness')
    ax1.xaxis.set_major_locator(dates.MinuteLocator(interval=1))
    ax1.xaxis.set_major_formatter(dates.DateFormatter('%H:%M'))
    ax1.tick_params(axis='x', rotation=45)
    ax1.minorticks_on()
    ax1.legend()
    ax1.grid(which='major', linestyle='-', color='#000000')
    ax1.grid(which='minor', linestyle='--')
    ax1.set_xlabel('time [h:m, UT]')
    ax1.set_ylabel('apparent brightness [mag, CR]')

    ax2 = ax1.twiny()
    ax2.set_xlim(ax1.get_xlim())
    ax2.set_xticks(x_phi_ticks)
    ax2.set_xticklabels(x_phi_ticklabels)
    ax2.set_xlabel('phase angle (phi) [deg]')

    plt.gca().invert_yaxis()
    plt.tight_layout(pad=0)
    plt.show()


    enter image description here






    share|improve this answer




























      0














      Yay! I've managed to get the sought result without defining a new scale class! Here are the relevant code parts which have been added/modified in the script from the question (the variable step will be later read from the user command line input, or I might find another way of automated tick frequency setting):



      x_ut = 
      x_phi =
      x_phi_ticks =
      x_phi_ticklabels =
      y_brightness =

      # populate lists for the phase angle ticks and labels

      i = 0
      step = 15
      while i <= (len(x_ut)-step):
      x_phi_ticks.append(x_ut[i])
      x_phi_ticklabels.append(x_phi[i])
      i += step
      x_phi_ticks.append(x_ut[-1])
      x_phi_ticklabels.append(x_phi[-1])

      # plot'em all

      fig, ax1 = plt.subplots()

      ax1.plot(x_ut, y_brightness, marker='o', label='apparent brightness')
      ax1.xaxis.set_major_locator(dates.MinuteLocator(interval=1))
      ax1.xaxis.set_major_formatter(dates.DateFormatter('%H:%M'))
      ax1.tick_params(axis='x', rotation=45)
      ax1.minorticks_on()
      ax1.legend()
      ax1.grid(which='major', linestyle='-', color='#000000')
      ax1.grid(which='minor', linestyle='--')
      ax1.set_xlabel('time [h:m, UT]')
      ax1.set_ylabel('apparent brightness [mag, CR]')

      ax2 = ax1.twiny()
      ax2.set_xlim(ax1.get_xlim())
      ax2.set_xticks(x_phi_ticks)
      ax2.set_xticklabels(x_phi_ticklabels)
      ax2.set_xlabel('phase angle (phi) [deg]')

      plt.gca().invert_yaxis()
      plt.tight_layout(pad=0)
      plt.show()


      enter image description here






      share|improve this answer


























        0












        0








        0







        Yay! I've managed to get the sought result without defining a new scale class! Here are the relevant code parts which have been added/modified in the script from the question (the variable step will be later read from the user command line input, or I might find another way of automated tick frequency setting):



        x_ut = 
        x_phi =
        x_phi_ticks =
        x_phi_ticklabels =
        y_brightness =

        # populate lists for the phase angle ticks and labels

        i = 0
        step = 15
        while i <= (len(x_ut)-step):
        x_phi_ticks.append(x_ut[i])
        x_phi_ticklabels.append(x_phi[i])
        i += step
        x_phi_ticks.append(x_ut[-1])
        x_phi_ticklabels.append(x_phi[-1])

        # plot'em all

        fig, ax1 = plt.subplots()

        ax1.plot(x_ut, y_brightness, marker='o', label='apparent brightness')
        ax1.xaxis.set_major_locator(dates.MinuteLocator(interval=1))
        ax1.xaxis.set_major_formatter(dates.DateFormatter('%H:%M'))
        ax1.tick_params(axis='x', rotation=45)
        ax1.minorticks_on()
        ax1.legend()
        ax1.grid(which='major', linestyle='-', color='#000000')
        ax1.grid(which='minor', linestyle='--')
        ax1.set_xlabel('time [h:m, UT]')
        ax1.set_ylabel('apparent brightness [mag, CR]')

        ax2 = ax1.twiny()
        ax2.set_xlim(ax1.get_xlim())
        ax2.set_xticks(x_phi_ticks)
        ax2.set_xticklabels(x_phi_ticklabels)
        ax2.set_xlabel('phase angle (phi) [deg]')

        plt.gca().invert_yaxis()
        plt.tight_layout(pad=0)
        plt.show()


        enter image description here






        share|improve this answer













        Yay! I've managed to get the sought result without defining a new scale class! Here are the relevant code parts which have been added/modified in the script from the question (the variable step will be later read from the user command line input, or I might find another way of automated tick frequency setting):



        x_ut = 
        x_phi =
        x_phi_ticks =
        x_phi_ticklabels =
        y_brightness =

        # populate lists for the phase angle ticks and labels

        i = 0
        step = 15
        while i <= (len(x_ut)-step):
        x_phi_ticks.append(x_ut[i])
        x_phi_ticklabels.append(x_phi[i])
        i += step
        x_phi_ticks.append(x_ut[-1])
        x_phi_ticklabels.append(x_phi[-1])

        # plot'em all

        fig, ax1 = plt.subplots()

        ax1.plot(x_ut, y_brightness, marker='o', label='apparent brightness')
        ax1.xaxis.set_major_locator(dates.MinuteLocator(interval=1))
        ax1.xaxis.set_major_formatter(dates.DateFormatter('%H:%M'))
        ax1.tick_params(axis='x', rotation=45)
        ax1.minorticks_on()
        ax1.legend()
        ax1.grid(which='major', linestyle='-', color='#000000')
        ax1.grid(which='minor', linestyle='--')
        ax1.set_xlabel('time [h:m, UT]')
        ax1.set_ylabel('apparent brightness [mag, CR]')

        ax2 = ax1.twiny()
        ax2.set_xlim(ax1.get_xlim())
        ax2.set_xticks(x_phi_ticks)
        ax2.set_xticklabels(x_phi_ticklabels)
        ax2.set_xlabel('phase angle (phi) [deg]')

        plt.gca().invert_yaxis()
        plt.tight_layout(pad=0)
        plt.show()


        enter image description here







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 27 '18 at 20:20









        sergiusprosergiuspro

        205




        205






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53458959%2fmatplotlib-twiny-how-to-align-values-of-two-x-axes-in-one-plot%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            這個網誌中的熱門文章

            Tangent Lines Diagram Along Smooth Curve

            Yusuf al-Mu'taman ibn Hud

            Zucchini