I'd like to add the 2nd row of labels to the x-axis which for other reasons should have a very odd aspect ratio and I'd also like to use plt.tight_layout() at the end. How should I change the last line to make it looks presentable?
import matplotlib.pyplot as plt
# I like this odd aspect ratio for other resons
fig=plt.figure(3,facecolor='white', figsize=(8,1.5))
ax = fig.add_subplot(111)
data=[0,1,0,0,1]
binX=[i for i in range(len(data))]
seqA=['A','B','C','D','E']
seqB=['A','X','C','D','Z']
ax.plot(binX,data)
ax.set_xticks(binX)
ax.set_xticklabels(seqA)
# problematic 2nd row of labels :
for i, c in enumerate(seqB):
ax.text(i,-0.9,seqB[i], color='k',horizontalalignment='center')
plt.tight_layout() # I like to use this for other reasons
I'd like the 2nd row of labels to be displayed below the 1st one at a small distance
Related
I am working with a biological model of the distribution of microbial biomass (b1) on a 2D grid. From the biomass a protein (p1) is produced. The biomass diffuses over the grid, while the protein does not. Only if a certain amount of protein is produced (p > p_lim), the biomass is supposed to diffuse.
I try to implement this by using a dummy cell variable z multiplied with the diffusion coefficient and setting it from 0 to 1 only in cells where p > p_lim.
The condition works fine and when the critical amount of p is reached in a cell, z is set to 1, and diffusion happens. However, the diffusion still does not work with the rate I would like, because to calculate diffusion, the face variable, not the value of the cell itself is used. The faces of z are always a mean of the cell with z=1 and its neighboring cells with z=0. I I, however, would like the diffusion to work at its original rate even if the neighbouring cell is still at p < p_lim.
So, my question is: Can i somehow access a faceVariable and change it? For example, set a face to 1 if any neigboring cell has reached p1 > p_lim? I guess this is not a proper mathematical thing to do, but I couldn't think of another way to simulate this problem.
I will show a very reduced form of my model below. In any case, I thank you very much for your time!
##### produce mesh
nx= 5.
ny= nx
dx = 1.
dy = dx
L = nx*dx
mesh = Grid2D(nx=nx,ny=ny,dx=dx,dy=dy)
#parameters
h1 = 0.5 # production rate of p
Db = 10. # diffusion coeff of b
p_lim=0.1
# cell variables
z = CellVariable(name="z",mesh=mesh,value=0.)
b1 = CellVariable(name="b1",mesh=mesh,hasOld=True,value=0.)
p1= CellVariable(name="p1",mesh=mesh,hasOld=True,value=0.)
# equations
eqb1 = (TransientTerm(var=b1)== DiffusionTerm(var=b1,coeff=Db*z.arithmeticFaceValue)-ImplicitSourceTerm(var=b1,coeff=h1))
eqp1 = (TransientTerm(var=p1)==ImplicitSourceTerm(var=b1,coeff=h1))
# set b1 to 10. in the center of the grid
b1.setValue(10.,where=((x>2.)&(x<3.)&(y>2.)&(y<3.)))
vi=Viewer(vars=(b1,p1),FIPY_VIEWER="matplotlib")
eq = eqb1 & eqp1
from builtins import range
for t in range(10):
b1.updateOld()
p1.updateOld()
z.setValue(z + 0.1,where=((p1>=p_lim) & (z < 1.)))
eq.solve(dt=0.1)
vi.plot()
In addition to .arithmeticFaceValue, FiPy provides other interpolators between cell and face values, such as .harmonicFaceValue and .minmodFaceValue.
These properties are implemented using subclasses of _CellToFaceVariable, specifically _ArithmeticCellToFaceVariable, _HarmonicCellToFaceVariable, and _MinmodCellToFaceVariable.
You can also make a custom interpolator by subclassing _CellToFaceVariable. Two such examples are _LevelSetDiffusionVariable and ScharfetterGummelFaceVariable (neither is well documented, I'm afraid).
You need to override the _calc_() method to provide your custom calculation. This method takes three arguments:
alpha: an array of the ratio (0-1) of the distance from the face to the cell on one side, relative to the distance from distance from the cell on the other side to the cell on the first side
id1: an array of indices of the cells on one side of the face
id2: an array of indices of the cells on the other side of the face
Note: You can ignore any clause if inline.doInline: and look at the _calc_() method defined under the else: clause.
I am trying to make a 2D histogram using data from an h5 file. This file contains calculations of the Chi1 angle of an amino acid for 100 iterations and the values for each Chi angle are stored as a list of arrays within the file. I want to make a histogram of the values of the Chi1 angle for each iteration. In short, I want the x-axis to be the Chi1 angles and the y-axis to be iteration number. Here is the code that I have tried:
import numpy as np
import h5py
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
auxdata = [] #An empty list
iteration = [] #An empty list
for i in range(1,100): #100 iterations of calculations
string = "iterations/iter_" + str(i).zfill(8) + "/auxdata" + "/Trp43_Chi1" #Going to the right place in the h5 file to find the data I want
f = h5py.File("west.h5") #Loading in the h5 file
Chi1 = f[string] #Defining x-axis variable
iter_variable = i #Defining y-axis variable
auxdata_iter = auxdata + list(Chi1[:]) #X-axis variable becomes a list of arrays of varied sizes
iter_data = iteration + list([iter_variable]) # Y-axis variable becomes an array of a single value, which is the iteration number
###Plotting###
plt.hist2d(auxdata_iter, iter_data, bins=(100)); #2D histogram divided into 100 bins
plt.xlabel("Trp43 Chi1");
plt.ylabel("Frequency");
plt.title("GB1 Trp43 Chi1 Angle Distribution");
plt.savefig("Trp43_Chi1.png")
The problem is that I get the error "ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()".
What I need to learn how to do is to map every Chi1 angle value (x-axis) from a given iteration to the iteration number (y-axis).
Do you have any ideas? Thanks!
I am trying to perform a calculation using two different matrices, but they have come in slightly different forms.
The one matrix (for interests sake) are filled with reflectance values of a material from wavelengths 200nm to 2600nm, so each individual wavelength, in increments of 1 has a reflectance value.
The second matrix is a solar energy matrix which stores the amount of energy that is present at each wavelength. This one however has irregular steps and ranges from 280nm to 4000nm. But from 280nm-400nm it is in steps of 0.5nm, from 400nm-1705nm it is in steps of 1nm, and from 1750nm-4000nm it is steps of 5nm.
What I have been trying to do, unsucessfully thus far, is to edit this solar energy matrix so that it gives the entire range in steps of 1nm.
filename='H:\I_sol data.csv';
Dataisol = csvread(filename,1,0);
for j=1:1:count
if Dataisol(j,:)~=Dataisol(j+1,:)-1 %compare the wavelength to the value of the next wavelegth
newx=(Dataisol(j,:)+[1,0]) %if the next wavelength is not 1 larger than the previous, add a new row
newx(1,2)=NaN %make the new row to add blank
Dataisol=insertrows(Dataisol, newrow, j+1) %insert the new blank row
end
end
Above is what I have started with, at the moment I am just trying to fill the gaps by adding in new rows where there is a 5nm jump between wavelengths. Once i am able to create the missing elements, then I will turn my attention to populating them with the correct values (probably the midpoint between the 2 given values)
My end goal is going to be to trim both of the matrices so that they both have the same starting and ending wavelength and both have increments of 1nm throughout (also for interest sake, or for advice if this is trivial for someone). If anyone knows how to fill these gaps or make the necessary changes to the matrix it would be a great help!
Example of the csv file:
Wvlgth nm Etr W*m-2*nm-1
280.0 8.2000E-02
280.5 9.9000E-02
281.0 1.5000E-01
281.5 2.1200E-01
282.0 2.6700E-01
282.5 3.0300E-01
283.0 3.2500E-01
283.5 3.2300E-01
284.0 2.9900E-01
284.5 2.5024E-01
285.0 1.7589E-01
285.5 1.5500E-01
286.0 2.4200E-01
... .....
428.0 1.6510E+00
429.0 1.5230E+00
430.0 1.2120E+00
431.0 1.0990E+00
432.0 1.8220E+00
433.0 1.6913E+00
434.0 1.5600E+00
435.0 1.7090E+00
436.0 1.8680E+00
437.0 1.9000E+00
438.0 1.6630E+00
439.0 1.6010E+00
440.0 1.8300E+00
.... .....
2205.0 8.0900E-02
2210.0 8.0810E-02
2215.0 8.0410E-02
2220.0 7.9990E-02
2225.0 7.8840E-02
2230.0 7.8400E-02
2235.0 7.7930E-02
2240.0 7.6510E-02
2245.0 7.6250E-02
2250.0 7.5370E-02
... .....
Here is the code I use for assigning the variables to be used in the interp1 function, which is called as follows:
solx=Dataisol(:,1);
soly=Dataisol(:,2);
xi=280:1:2600;
newsol = [xi interp1(solx,soly,xi,'linear','extrap')];
The values that are stored in these variables as well as the error I am receiving are given below:
The function you need here is interp1. Set xi to be a vector of all the wavelengths you want to consider, say xi=280:1:2600;.
if wavelength is a vector of all your irregular values from the file, and sol is the corresponding vector of all the solar energies (you can use column references for your single matrix here as well)
newsol = [xi interp1(wavelength,sol,xi,'linear','extrap')];
will give you a new matrix with wavelengths increasing by 1 in column 1, and column 2 will contain values directly from your file where they exist and linearly interpolated values where they do not.
This seems like a trivial problem, though I've been hitting myself over the head with it for too long.
This doesn't even plot just the (0,0) -- I can't seem to find much about plotting from arrays -- rather just matrix plots (and only columns at that).
The data is properly in these arrays, I just need to make plots! Doesn't seem so complicated. I don't even need separate colors for the different sets...just all one big scatter plot.
Any suggestions?
pdf(mypath)
# Plot first point
plot(0,0, col = "blue", type = "n", xlab="PES", ylab=""%eff")
#Loop to Plot remaining points
for(rows in 1:nrowX)
{
for(cols in 1:ncolX)
{
points(X[rows,cols],Y[rows,cols], col = "blue", type = "p")
}
}
dev.off
I have also tried using plot.new() to have an empty plot...but no such luck.
SOLUTION!!
Turns out I'm just a fool. Code is acurate and the suggestions below do indeed work.
R happened to be open in another tab and since it was open, never let go of the plot (why? I don't know). As soon as it was closed, the plot appeared. Now I can get my plot again and again...
Thanks to everyone who tried helping a problem that wasn't a problem!
I like this place already!
When you set type = "n", the plot function will not plot anything at all. It is used to set up a basis for the rest of the plot (like axis labels, limits etc). That is why the first point at (0, 0) does not show up.
The rest of the points are probably outside the range. Use xlim and ylim to set up the ranges properly. I'm going to assume X and Y have the same size and dimension. Try this:
pdf(mypath)
# Set up the plot
plot(0, type="n", xlab="PES", ylab="%eff", xlim=range(X), ylim=range(y))
# Now plot
points(X,Y, col="blue")
dev.off
Of course you could let the plot function take care of the limits for you:
pdf(mypath)
plot(X, Y, xlab="PES", ylab="%eff")
dev.off()
Your initial plot will set up the coordinates, but since you only give it one point it does not know how much room to leave around the 0,0 point (so it does not leave very much). I expect that the rest of your points fall outside of that range which is why they don't show up on the plot (you can use par("usr") to see what the extents are).
When you create the initial plot you should include xlim and ylim arguments so that the plot includes the area where the new points will be added, something like:
plot(0,0, type='n', xlim=range(X), ylim=range(Y))
You may also be interested in the matplot function which will take a matrix as either or both the x and/or y argument and plot accordingly.
Edit
The following works for me:
X <- matrix( runif(390), nrow=10 )
Y <- matrix( rnorm(390), nrow=10 )
plot(0,0, col = "blue", type = "n", xlab="PES", ylab="%eff",
xlim=range(X), ylim=range(Y))
#Loop to Plot remaining points
for(rows in 1:nrow(X))
{
for(cols in 1:ncol(X))
{
points(X[rows,cols],Y[rows,cols], col = "blue", type = "p")
}
}
I did remove an extra " from the ylab, was that your problem?
But
plot(X,Y)
also worked without the looping.
Check with just the console to see if it works before worrying about sending to a pdf file. If this has not fixed it yet, we still need more details.
I have a plotting question regarding boxplots (using base graphics).
I have several arrays of data which I wish to turn into box plots and compare. The arrays reflect different experiments and what I would like to show is the base results and the percentage difference for the experiments (on one plot!). I.e. the base results on the 1st y axis and the % diff on the second y axis:
base <- array(runif(12*24*3), dim=c(12,24,3))
exp1 <- array(runif(12*24*3), dim=c(12,24,3))
exp2 <- array(runif(12*24*3), dim=c(12,24,3))
exp3 <- array(runif(12*24*3), dim=c(12,24,3))
exp4 <- array(runif(12*24*3), dim=c(12,24,3))
# calc p.diff
p.diff <- function(mod,base) {
100.0*((mod-base)/base) }
a <- p.diff(exp1,base)
b <- p.diff(exp2,base)
c <- p.diff(exp3,base)
# combine the % diff arrays
exps <- list(a,b,c)
# plot the results
boxplot(base, xlim=c(1,4), col="gray", xaxt="n", ylab="Base values", outline=FALSE)
axis(side=1, 1:4, labels=c("base","% exp1","% exp2","% exp3") )
par(new=TRUE)
boxplot(exps, col="red", ylim=c(-200,200), outline=FALSE, axes=FALSE)
axis(4)
grid()
This almost works but I don't get the positioning of the different box plots right (if you run my example you will see what I mean). So is there a better way to control the placement of the box plots? Or a better way to produce a similar type of figure?
Edited (1): You need to define the rigth sequences for the X axis. So that the plots don't overlap. Just try to play with it.
I think the labels of the X axes are not at the right place? I don't know a more elegant way of doing it but here is a solution:
# plot the results
boxplot(base, xlim=c(1,4), col="gray", xaxt="n", ylab="Base values", outline=FALSE)
axis(side=1,1,labels=('base'))
par(new=TRUE)
boxplot(exps, col="red", ylim=c(-200,200), outline=FALSE, axes=FALSE)
axis(4)
axis(side=1,1:3,labels=c("% exp1","% exp2","% exp3"))
grid()
So I added every label after creating the boxplot. First plot the base and label it, then plot exps and label it. Does it solve your problem?
Edit: Just to be more clear, You are adding a new plot with 3 values, that is why axis(side=1,1:3,labels=c("% exp1","% exp2","% exp3")) is from 1 to 3...
Edited (2):
Why don't you use multi rows in the plot and try to plot 2 graphs? Here is an example with your data:
#divide your plottin area into 2 columns with one row.
par(mfrow = c(1, 2))
# plot the results
boxplot(base, col="gray", xaxt="n", ylab="Base values", outline=FALSE,axes=FALSE)
axis(2)
axis(side=1,1,labels=('base'))
segments(0,0,1,0)
boxplot(exps,col="red", xaxt="n", ylim=c(-200,200), outline=FALSE, axes=FALSE)
axis(4)
axis(side=1,at=(1:3),labels=c("% exp1","% exp2","% exp3"))
you can have more information about it from here