Tight curves in a plot in python - python

I have four curves to plot in Python, each one corresponds to a certain value of a parameter γ. As one may see in the figure, the four curves are really tight with almost no distinction between them. I would like to do a plot as the one in the figure and to add a subplot inside where the difference of the lines could be seen.
I tried reducing the scales but it looks impossible.
Is there a in-built way in matplotlib to see these differences?
Here is a csv file with the values of each curve!

Well, thanks to #JohanC I found a walk around solution on https://matplotlib.org/3.3.1/gallery/subplots_axes_and_figures/zoom_inset_axes.html
dataframe = pd.read_csv('z_curves.csv')
fig, ax = plt.subplots()
r=dataframe['rad']
z_2=dataframe['z_2']
z_4=dataframe['z_4']
z_6=dataframe['z_6']
z_8=dataframe['z_8']
ax.plot(r,z_2,"k")
ax.plot(r,z_4,"k--")
ax.plot(r,z_6,"k:")
ax.plot(r,z_8,"k-.")
ax.plot(r,[0.0 for i in range(len(r))],"g--")
ax.set_xlabel('$r/r_c$',fontsize=20)
ax.set_ylabel('$e^{\\nu(r)}-1$',fontsize=20)
plt.xlim(0.0,1.0)
plt.ylim(-0.000001,0.0000001)
targets = ["$\gamma=0.2$", "$\gamma=0.4$", "$\gamma=0.6$", "$\gamma=0.8$"]
legend = plt.legend(targets,loc='best', shadow=True)
legend.get_frame().set_facecolor('white')
axins = ax.inset_axes([0.4, 0.4, 0.4, 0.4])
x1, x2, y1, y2 = 0.2, 0.201, -5.5634547184309856e-08, -5.5606744002038696e-08
axins.set_xlim(x1, x2-0.0008)
axins.plot(r,z_2,"k")
axins.plot(r,z_4,"k--")
axins.plot(r,z_6,"k:")
axins.plot(r,z_8,"k-.")
axins.set_ylim(y1, y2)
axins.set_xticklabels('')
axins.set_yticklabels('')
ax.indicate_inset_zoom(axins)
plt.show()

Related

Creating a graphic inside another one using and linking them by lines

I would like to link a graphic with a another one, both in the same figure, and "connect" the smaller one with the larger one, due to they share X axis, but not Y axis. The problem comes when I use that function, that I really don't know very well how it works.
The function ax2.set_axes_locator(ip) calls another one ip=InsetPosition(ax1,[0.2,0.7,0.5,0.25]), where ax1 represents the bigger graphic. The problem is that function automatically generates lines which links the bigger one with the smaller, but I can't redirect them and I want to, because both graphics don't share Y axis.
I hope someone could understand the problem, definitely my english is not the best.
ax2=plt.axes([0,0,1,1])
ip=InsetPosition(ax1,[0.2,0.7,0.5,0.25])
ax2.set_axes_locator(ip)
mark_inset(ax1,ax2,loc1=3,loc2=4,fc="none",ec='0.5')
You cannot use mark_inset because that will show the marker at the same data coordinates as the view limits of the inset axes.
Instead you can create a rectangle and two connectors that will just be positionned arbitrarily on the axes. (The following code will require matplotlib 3.1 or higher)
import matplotlib.pyplot as plt
from matplotlib.patches import ConnectionPatch
fig, ax = plt.subplots()
ax.plot([1,3,5], [2,4,1])
ax.set_ylim([0, 10])
ax.set_ylabel("Some units")
axins = ax.inset_axes([.2, .7, .4, .25])
axins.plot([100, 200], [5456, 4650])
axins.set_ylabel("Other units")
rect = [2.1, 2.6, 1, 2]
kw = dict(linestyle="--", facecolor="none", edgecolor="k", linewidth=0.8)
ax.add_patch(plt.Rectangle(rect[:2], *rect[2:], **kw))
cp1 = ConnectionPatch((rect[0], rect[1]+rect[3]), (0,0), coordsA="data", axesA=ax,
coordsB="axes fraction", axesB=axins, clip_on=False, **kw)
cp2 = ConnectionPatch((rect[0]+rect[2], rect[1]+rect[3]), (1,0), coordsA="data", axesA=ax,
coordsB="axes fraction", axesB=axins, clip_on=False, **kw)
ax.add_patch(cp1)
ax.add_patch(cp2)
plt.show()

Creating and referencing separate matplotlib plots

What's the best practice to create multiple separate plots using matplotlib, so they can be called later or output into a pdf report? I'm a bit unclear as to how to do this in a way that retains each plot in memory (like we could with dataframes) for later reference.
Suppose we have this code:
%pylab inline
x1 = np.random.randn(50)*100
y1 = np.random.randn(50)*100
x2 = np.random.randn(50)*100
y2 = np.random.randn(50)*100
and the intent is to create 2 separate plots of (x1,y1) and (x2,y2) and 'save' them in some way to be referenced later. the intent is to be able to output these into a PDF (perhaps via reportlab). the relationship between "figures", "subplots" and "axes" is confusing to me and not sure what is optimal for this purpose. i started with an approach like:
plt.figure(1, figsize=(8, 6))
plt.subplot(211)
plt.scatter(x1, y1, c = 'r', alpha = 0.3)
plt.subplot(212)
plt.scatter(x2, y2, c = 'k', alpha = 0.7)
plt.show()
which does technically work, but i'm not sure how i can refer to these later. also, i am using a small example here for illustration, but in practice i may have many more of these.
With the implicit style that the question uses (where the figure object is not saved in a variable, and where plotting commands apply to the current figure), you can easily make a previous figure the current figure:
plt.figure(1)
will thus reactivate figure 1. plt.savefig() can then be used, additional plots can be made in it, etc.
Furthermore, you can also give a name to your figure when you create it, and then refer to it:
plt.figure("growth", figsize=…)
…
plt.figure("counts", figsize=…)
…
plt.figure("growth") # This figure becomes the active one again
(the figure reference parameter is called num, but it doesn't have to be a number and can be a string, which makes for a clearer code).
Things might make more sense if you start to use the object-oriented interface to matplotlib. In that case, you could do something like:
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(8, 6))
ax1 = fig.add_subplot(211)
ax1.scatter(x1, y1, c = 'r', alpha = 0.3)
ax2 = fig.add_subplot(212)
ax2.scatter(x2, y2, c = 'k', alpha = 0.7)
plt.show()
In this way, its easy to see that ax1 and ax2 belong to the figure instance, fig. You can then later refer back to ax1 and ax2, to plot more data on them, or adjust the axis limits, or add labels, etc., etc.
You can also add another figure, with its own set of subplots:
fig2 = plt.figure(figsize=(8, 6))
ax3 = fig2.add_subplot(211)
and then you can save the given figures at any point, and know that you are always referring to the correct figure:
fig.savefig('figure1.png')
fig2.savefig('figure2.png')

Plotting ordinal data with a marker in matplotlib

I have some data for which I have experimental and simulated values, the data isn't really continuous without introducing a new definition (which I don't want to do) so I wish to display it ordinally in a scatter type plot with two markers for each set and then label each set on the X-axis.
Basically I can't figure out how to do this with matplotlib (I'd prefer to use it for consistency with how I've presented other data).
An example of the data is presented below:
1cm square: 0.501, 0.505
1cm circle: 0.450, 0.448
1cm X 2cm rect: 0.665, 0.641
I may be misunderstanding the question, but it sounds like you're wanting something along these lines:
import matplotlib.pyplot as plt
# Using this layout to make the grouping clear
data = [('apples', [0.1, 0.25]),
('oranges', [0.6, 0.35]),
('pears', [0.1, 0.18]),
('bananas', [0.7, 0.98]),
('peaches', [0.6, 0.48])]
# Reorganize our data a bit
names = [item[0] for item in data]
predicted = [item[1][0] for item in data]
observed = [item[1][1] for item in data]
# It might make more sense to use a bar chart in this case.
# You could also use `ax.scatter` to plot the data instead of `ax.plot`
fig, ax = plt.subplots()
ax.plot(predicted, color='lightblue', marker='o', linestyle='none',
markersize=12, label='Predicted')
ax.plot(observed, color='red', marker='s', linestyle='none',
markersize=12, label='Observed')
ax.margins(0.05)
ax.set(xticks=range(len(names)), xticklabels=names, ylabel='Meaningless')
ax.legend(loc='best', numpoints=1)
ax.grid(axis='x')
plt.show()
The key part is setting the xticks and xticklabels to correspond to your data "groups". You could plot the data in a few other ways (e.g. bar plots, etc), but using the xticks/labels will be the same in each case.

boxplots with not-in-scale y-axis

I have some data I want to box plot. Outliers (e.g. 20, 30) are too far away from most values (e.g. 0.0002, 0.0003) and as a consequence I can only see outliers when I plot with matplotlib.
Is there anyway to zoom in the values around the median and then let the rest of the y-axis not be in scale and display outliers too?
EDIT
Here's my code in python. I would like to use inset axes, as suggested below, for each box plot I have. How can I do this in an easy way? There seems to be way too many parameters to take care of from the examples in the documentation.
plt.figure()
ax = plt.subplot(111)
plt.boxplot(dataToPlot)
axins = zoomed_inset_axes(ax, 6, loc=1) # zoom = 6
# what follows is taken from example linked in the answer below.
# I didn't get if the first argument is indeed the data this zoomed image refers to or not.
axins.imshow(dataToPlot[1], interpolation="nearest", origin="lower")
# here I only need the y-axis to be in [0,0.1], x-axis is no of use with vertical boxplots
x1, x2, y1, y2 = -1.5, -0.9, 0.0, 0.1
axins.set_xlim(x1, x2)
axins.set_ylim(y1, y2)
plt.xticks(visible=True)
plt.yticks(visible=True)
plt.savefig( 'somewhere.jpeg', bbox_inches=0)
You could do an inset axes as described on this page, about 1/2 way down.
inset axes
Very old question, but I came across this looking for something similar. I solved this by adding sym='' (this option may have not existed 7 years ago!) which tells boxplot not to show fliers (anything past the whiskers).
So for anyone else who comes across this, you might try changing line 3 in the question to:
plt.boxplot(dataToPlot, sym='')

problem plotting on logscale in matplotlib in python

I am trying to plot the following numbers on a log scale as a scatter plot in matplotlib. Both the quantities on the x and y axes have very different scales, and one of the variables has a huge dynamic range (nearly 0 to 12 million roughly) while the other is between nearly 0 and 2. I think it might be good to plot both on a log scale.
I tried the following, for a subset of the values of the two variables:
fig = plt.figure(figsize=(8, 8))
ax = fig.add_subplot(1, 1, 1)
ax.set_yscale('log')
ax.set_xscale('log')
plt.scatter([1.341, 0.1034, 0.6076, 1.4278, 0.0374],
[0.37, 0.12, 0.22, 0.4, 0.08])
The x-axes appear log scaled but the points do not appear -- only two points appear. Any idea how to fix this? Also, how can I make this log scale appear on a square axes, so that the correlation between the two variables can be interpreted from the scatter plot?
thanks.
I don't know why you only get those two points. For this case, you can manually adjust the limits to make sure all your points fit. I ran:
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(8, 8)) # You were missing the =
ax = fig.add_subplot(1, 1, 1)
ax.set_yscale('log')
ax.set_xscale('log')
plt.scatter([1.341, 0.1034, 0.6076, 1.4278, 0.0374],
[0.37, 0.12, 0.22, 0.4, 0.08])
plt.xlim(0.01, 10) # Fix the x limits to fit all the points
plt.show()
I'm not sure I understand understand what "Also, how can I make this log scale appear on a square axes, so that the correlation between the two variables can be interpreted from the scatter plot?" means. Perhaps someone else will understand, or maybe you can clarify?
You can also just do,
plt.loglog([1.341, 0.1034, 0.6076, 1.4278, 0.0374],
[0.37, 0.12, 0.22, 0.4, 0.08], 'o')
This produces the plot you want with properly scaled axes, though it doesn't have all the flexibility of a true scatter plot.

Categories

Resources