Python, plot data with two sets of y data - python

For some reason this question is tough for me to explain, but here goes. I have a set of data say (x,y1,y2) that I would like to plot. I need it to be one plot, not two plot one being (x,y1) and the other being (x,y2). Instead I want it so i can plot it at once and then have the left axis be for (y1) and the right axis be for (y2).
Currently I am stuck at plotting two separate plots and having to scale the axis to match each other, yet it still isn't working too well. Below I put my code that plots, the set of data is mesaBV=x...mesaMv=y1...mesaAge=y2
Is anyone familiar with answering this question? Thanks!!
Edit:
host = host_subplot(111, axes_class=AA.Axes)
par1 = host.twinx()
par1.set_yscale('log')
host.grid(True)
host.set_xlabel("B-V")
host.set_ylabel("Mv")
par1.set_ylabel("Age")
p1, = host.plot(mesaBV, mesaMv, label="Mv",marker="o")
p2, = par1.plot(mesaBV, mesaAge, label="Age",marker="o")
host.set_yticks(np.linspace(host.get_ybound()[0], host.get_ybound()[1], 10))
par1.set_yticks(np.linspace(par1.get_ybound()[0], par1.get_ybound()[1], 10))
host.axis["left"].label.set_color(p1.get_color())
par1.axis["right"].label.set_color(p2.get_color())
plt.draw()
plt.show()

By having two y values for the same point, you are creating a vertical line. Unless you can scale the graph perfectly, it won't work, and even if you scale it perfectly, there would be no point (no pun intended) because y1 would be essentially in exactly the same spot as y2. If you truly need it like that, than just plot (x1,y1) and figure out a different scale for the right y-axis without having it affect the original points. This way you can easily emulate (x1,y1,y2).
EDIT: Now that I can see your code, I recommend using the twinx() function to create the second axis.

Related

Managing ticks for multiple lines on the same subplot in Matplotlib

I want to plot multiple lines in the same plot, like in the picture below:
The problem with the picture is that if the Y values of the graphs aren't similar the y ticks get jumbled, it's unclear which tick is related to the first graph and which one isn't.
Is there a way for me to colour the ticks of each graph differently (preferably to the colour of the graph)? or maybe separate it into different columns?
Also, I wouldn't mind using more than one subplot, as long as the graphs' space overlaps.
The code I use to create the new lines:
def generate_graph():
colors = "rgbmcmyk"
subplot_recent.clear()
lines_drawn = []
mat_figure.legends = []
for i in range(n):
lines_drawn.append(["A Name", subplot_recent.plot(values[i][0], values[i][1], colors[i])[0]])
mat_figure.legend((i[1] for i in lines_drawn), (i[0] for i in lines_drawn), 'upper right')
subplot_recent.yaxis.set_major_locator(plt.MaxNLocator(10))
mat_canvas.draw()
The error actually was that I forgot to cast the values to int/float, and so matplotlib didn't really know what to do with them all to well.
It's fixed now. Thanks!

How to reproduce this legend with multiple curves?

I've been working hard on a package of functions for my work, and I'm stuck on a layout problem. Sometimes I need to work with a lot of columns subplots (1 row x N columns) and the standard matplotlib legend sometimes is not helpful and makes it hard to visualize all the data.
I've been trying to create something like the picture below. I already tried to create a subplot for the curves and another one for the legends (and display the x-axis scale as a horizontal plot). Also, I tried to spine the x-axis, but when I have a lot of curves plotted inside the same subplots the legend becomes huge.
The following image is from a software. I'd like to create a similar look. Notice that these legends are "static": it remains fixed independent of the zooming. Another observation is, I don't need all the ticks or anything like that.
What I'm already have is the following (the code is a mess, becouse I'm trying many different solutions and it is not organized nor pythonic yet.
import matplotlib.pyplot as plt
fig, ax = plt.subplots(1,2, sharey = True)
ax[0].semilogx(np.zeros_like(dados.Depth)+0.02, dados.Depth)
ax[0].semilogx(dados.AHT90, dados.Depth, label = 'aht90')
ax[0].set_xlim(0.2,2000)
ax[0].grid(True, which = 'both', axis = 'both')
axres1 = ax[0].twiny()
axres1.semilogx(dados.AHT90, dados.Depth, label = 'aht90')
axres1.set_xlim(0.2 , 2000)
axres1.set_xticks(np.logspace(np.log10(0.2),np.log10(2000),2))
axres1.spines["top"].set_position(("axes", 1.02))
axres1.get_xaxis().set_major_formatter(matplotlib.ticker.ScalarFormatter())
axres1.tick_params(axis='both', which='both', labelsize=6)
axres1.set_xlabel('sss')#, labelsize = 5)
axres2 = ax[0].twiny()
axres2.semilogx(dados.AHT10, dados.Depth, label = 'aht90')
axres2.set_xlim(0.2 , 2000)
axres2.set_xticks(np.logspace(np.log10(0.2),np.log10(2000),2))
axres2.spines["top"].set_position(("axes", 1.1))
axres2.get_xaxis().set_major_formatter(matplotlib.ticker.ScalarFormatter())
axres2.tick_params(axis='both', which='both', labelsize=6)
axres2.set_xlabel('aht10')#, labelsize = 5)
fig.show()
and the result is:
But well, I'm facing some issues on make a kind of make it automatic. If I add more curves, the prameter "set position" it is not practical to keep setting the position "by hand"
set_position(("axes", 1.02))
and another problem is, more curves I add, that kind of "legend" keep growing upward, and I have to adjust the subplot size with
fig.subplots_adjust(top=0.75)
And I'm also want to make the adjustment automatic, without keeping updating that parameter whenever I add more curves

How can I change value on Right axis? (python3/matplotlab)

When I'm plotting a single curve, I use
plt.tick_params(axis = 'y', which = 'both', labelright = True)
which shows the same value on the right axis as the left Y-axis.
Is there a way to change the value on the right axis?
As far as I've searched up to now, most threads are about a shared X-axis. But mine is a single curve, NOT shared axis curves.
I would like to show the percentage of the Y axis value to a base value on the right axis.
I appreciate your suggestions!
Even though you call it left axis and right axis, it really is one single axis. You may decide on which side of the plot to label it through the use of labelright and labelleft arguments of tick_params, which will just determine whether to show the labels or not.
In case you want to show something different on both sides of the plot you need a second axes. An easy method is to use a twinx axes. For how to do this see
Adding a second y-axis related to the first y-axis.
fig, ax = plt.subplots()
ax2 = ax.twinx()
Now it depends on how you want the two y axes to link to each other. You may share the y axes, or you may set the same limits, or you may calculate the limits of the one depending on the other.

Pcolorfast image/array rotation

I have the code below:
fig, ax = pyplot.subplots()
graph = ax.pcolorfast(data, cmap='viridis', vmin = min, vmax = max)
pyplot.colorbar(graph)
pyplot.show()
and it plots what I wanted, however it is sideways. Is there a good way of rotating it -90 or 270 degrees? I have tried a.T, which returns the original plot. I have also tried ndimage.rotate(graph, -90|270), ndimage.interpolation.rotate(graph, -90|270), and numpy.rot90(data,3). The first two return errors for invalid rotation planes and the second appears to shove the graph off the edge, losing a majority of my data points.
If anyone has some thoughts, I would be very grateful. Even if it's that I put in the wrong arguments. I am at a loss here.
Is a supposed to be equal to data in your example? Tried your code with a random 2D array, and np.transpose(a) as well as a.T seem to properly rotate the figure, as opposed to what you indicate here ('returns the original plot'). If this is not the case for you, I think we need more information.

Break // in x axis of matplotlib [duplicate]

This question already has answers here:
Is there a way to make a discontinuous axis in Matplotlib?
(7 answers)
Closed 5 years ago.
Best way to describe what I want to achieve is using my own image:
Now I have a lot of dead space in the spectra plot, especially between 5200 and 6300. My question is quite simple, how would I add in a nice little // break that looks something similar to this (image lifted from the net):
I'm using this setup for my plots:
nullfmt = pyplot.NullFormatter()
fig = pyplot.figure(figsize=(16,6))
gridspec_layout1= gridspec.GridSpec(2,1)
gridspec_layout1.update(left=0.05, right=0.97, hspace=0, wspace=0.018)
pyplot_top = fig.add_subplot(gridspec_layout1[0])
pyplot_bottom = fig.add_subplot(gridspec_layout1[1])
pyplot_top.xaxis.set_major_formatter(nullfmt)
I'm quite certain it is achievable with gridpsec but an advanced tutorial cover exactly how this is achieved would be greatly appreciated.
Apologies also if this question has been dealt with previously on stackoverflow but I have looked extensively for the correct procedure for gridSpec but found nothing as yet.
I have managed to go as far as this, pretty much there:
However, my break lines are not as steep as I would like them...how do I change them? (I have made use of the example answer below)
You could adapt the matplotlib example for a break in the x-axis directly:
"""
Broken axis example, where the x-axis will have a portion cut out.
"""
import matplotlib.pylab as plt
import numpy as np
x = np.linspace(0,10,100)
x[75:] = np.linspace(40,42.5,25)
y = np.sin(x)
f,(ax,ax2) = plt.subplots(1,2,sharey=True, facecolor='w')
# plot the same data on both axes
ax.plot(x, y)
ax2.plot(x, y)
ax.set_xlim(0,7.5)
ax2.set_xlim(40,42.5)
# hide the spines between ax and ax2
ax.spines['right'].set_visible(False)
ax2.spines['left'].set_visible(False)
ax.yaxis.tick_left()
ax.tick_params(labelright='off')
ax2.yaxis.tick_right()
# This looks pretty good, and was fairly painless, but you can get that
# cut-out diagonal lines look with just a bit more work. The important
# thing to know here is that in axes coordinates, which are always
# between 0-1, spine endpoints are at these locations (0,0), (0,1),
# (1,0), and (1,1). Thus, we just need to put the diagonals in the
# appropriate corners of each of our axes, and so long as we use the
# right transform and disable clipping.
d = .015 # how big to make the diagonal lines in axes coordinates
# arguments to pass plot, just so we don't keep repeating them
kwargs = dict(transform=ax.transAxes, color='k', clip_on=False)
ax.plot((1-d,1+d), (-d,+d), **kwargs)
ax.plot((1-d,1+d),(1-d,1+d), **kwargs)
kwargs.update(transform=ax2.transAxes) # switch to the bottom axes
ax2.plot((-d,+d), (1-d,1+d), **kwargs)
ax2.plot((-d,+d), (-d,+d), **kwargs)
# What's cool about this is that now if we vary the distance between
# ax and ax2 via f.subplots_adjust(hspace=...) or plt.subplot_tool(),
# the diagonal lines will move accordingly, and stay right at the tips
# of the spines they are 'breaking'
plt.show()
For your purposes, just plot your data twice (once on each axis, ax and ax2 and set your xlims appropriately. The "break lines" should move to match the new break because they are plotted in relative axis coordinates rather than data coordinates.
The break lines are just unclipped plot lines drawn between a pair of points. E.g. ax.plot((1-d,1+d), (-d,+d), **kwargs) plots the break line between point (1-d,-d) and (1+d,+d) on the first axis: this is the bottom righthand one. If you want to change the graident, change these values appropriately. For example, to make this one steeper, try ax.plot((1-d/2,1+d/2), (-d,+d), **kwargs)
The solution provided by xnx is a good start, but there is a remaining issue that the scales of the x-axes are different between the plots. This is not a problem if the range in the left plot and the range in the right plot are the same, but if they are unequal, subplot will still give the two plots equal width, so the x-axis scale will be different between the two plots (as is the case with xnx's example). I made a package, brokenaxes to deal with this.

Categories