Setting maximum and minimum values for x-axis as dates in Excel - excel

I have a graph that has dates on the x-axis and I'm trying to set maximum and minimum values for this axis using an Excel VBA. Below is my code which doesnt seem to work.Can anyone please help.
With ActiveSheet.ChartObjects(1).Chart.Axes(xlValue)
.MinimumScale = ActiveSheet.Range("C33").Value
.MaximumScale = ActiveSheet.Range("D54").Value
End With

xlValue refers to the y-axis (or value axis). You're interested in adjust the x-axis values (or category axis) which require xlCategory. So use
With ActiveSheet.ChartObjects(1).Chart.Axes(xlCategory)
.MinimumScale = ActiveSheet.Range("C33").Value
.MaximumScale = ActiveSheet.Range("D54").Value
End With

I created a chart for a bivariate normal distribution. X1 follows a normal distribution with mu1 and stdev1 and likewise for X2. X1 is along the X axis. I wanted the limits to be within 4 standard deviations of the mean. mywidth and myheight were assigned beforehand. The data start on row 2 since there are titles on row 1. The data for X1 are in the 1st column. n is the number of rows of data.
mysheetname = ActiveSheet.Name
Set mychart = Sheets(mysheetname).ChartObjects.Add(Left:=mywidth, Top:=myheight + 2, Width:=400, Height:=250)
mychart.Chart.ChartType = xlXYScatter
mychart.Chart.SeriesCollection.NewSeries
mychart.Chart.SeriesCollection(1).Values = Range(Cells(outputrow + 1, outputcol + 1), Cells(outputrow + n, outputcol + 1))
mychart.Chart.SeriesCollection(1).XValues = Range(Cells(outputrow + 1, outputcol), Cells(outputrow + n, outputcol))
mychart.Chart.HasLegend = False
mychart.Chart.Axes(xlValue).MinimumScale = mu2 - 4 * sigma2
mychart.Chart.Axes(xlValue).MaximumScale = mu2 + 4 * sigma2
mychart.Chart.Axes(xlCategory).MinimumScale = mu1 - 4 * sigma1
mychart.Chart.Axes(xlCategory).MaximumScale = mu1 + 4 * sigma1

Related

Sphere-Sphere Intersection

I have two spheres that are intersecting, and I'm trying to find the intersection point nearest in the direction of the point (0,0,1)
My first sphere's (c1) center is at (c1x = 0, c1y = 0, c1z = 0) and has a radius of r1 = 2.0
My second sphere's (c2) center is at (c2x = 2, c2y = 0, c2z = 0) and has a radius of r2 = 2.0
I've been following the logic on this identical question for the 'Typical intersections' part, but was having some trouble understanding it and was hoping someone could help me.
First I'm finding the center of intersection c_i and radius of the intersecting circle r_i:
Here the first sphere has center c_1 and radius r_1, the second c_2 and r_2, and their intersection has center c_i and radius r_i. Let d = ||c_2 - c_1||, the distance between the spheres.
So sphere1 has center c_1 = (0,0,0) with r_1 = 2. Sphere2 has c_2 = (2,0,0) with r_2 = 2.0.
d = ||c_2 - c_1|| = 2
h = 1/2 + (r_1^2 - r_2^2)/(2* d^2)
So now I solve the function of h like so and get 0.5:
h = .5 + (2^2 - 2^2)/(2*2^2)
h = .5 + (0)/(8)
h = 0.5
We can sub this into our formula for c_i above to find the center of the circle of intersections.
c_i = c_1 + h * (c_2 - c_1)
(this equation was my original question, but a comment on this post helped me understand to solve it for each x,y,z)
c_i_x = c_1_x + h * (c_2_x - c_1_x)
c_i_x = 0 + 0.5 * (2 - 0) = 0.5 * 2
1 = c_i_x
c_i_y = c_1_y + h * (c_2_y - c_1_y)
c_i_y = 0 + 0.5 * (0- 0)
0 = c_i_y
c_i_z = c_1_z + h * (c_2_z - c_1_z)
c_i_z = 0 + 0.5 * (0 - 0)
0 = c_i_z
c_i = (c_i_x, c_i_z, c_i_z) = (1, 0, 0)
Then, reversing one of our earlier Pythagorean relations to find r_i:
r_i = sqrt(r_1*r_1 - hhd*d)
r_i = sqrt(4 - .5*.5*2*2)
r_i = sqrt(4 - 1)
r_i = sqrt(3)
r_i = 1.73205081
So if my calculations are correct, I know the circle where my two spheres intersect is centered at (1, 0, 0) and has a radius of 1.73205081
I feel somewhat confident about all the calculations above, the steps make sense as long as I didn't make any math mistakes. I know I'm getting closer but my understanding begins to weaken starting at this point. My end goal is to find an intersection point nearest to (0,0,1), and I have the circle of intersection, so I think what I need to do is find a point on that circle which is nearest to (0,0,1) right?
The next step from this solutionsays:
So, now we have the center and radius of our intersection. Now we can revolve this around the separating axis to get our full circle of solutions. The circle lies in a plane perpendicular to the separating axis, so we can take n_i = (c_2 - c_1)/d as the normal of this plane.
So finding the normal of the plane involves n_i = (c_2 - c_1)/d, do I need to do something similar for finding n_i for x, y, and z again?
n_i_x = (c_2_x - c_1_x)/d = (2-0)/2 = 2/2 = 1
n_i_y = (c_2_y - c_1_y)/d = (0-0)/2 = 0/2 = 0
n_i_z = (c_2_z - c_1_z)/d = (0-0)/2 = 0/2 = 0
After choosing a tangent and bitangent t_i and b_i perpendicular to this normal and each other, you can write any point on this circle as: p_i(theta) = c_i + r_i * (t_i * cos(theta) + b_i sin(theta));
Could I choose t_i and b_i from the point I want to be nearest to? (0,0,1)
Because of the Hairy Ball Theorem, there's no one universal way to choose the tangent/bitangent to use. My recommendation would be to pick one of the coordinate axes not parallel to n_i, and set t_i = normalize(cross(axis, n_i)), and b_i = cross(t_i, n_i) or somesuch.
c_i = c_1 + h * (c_2 - c_1)
This is vector expression, you have to write similar one for every component like this:
c_i.x = c_1.x + h * (c_2.x - c_1.x)
and similar for y and z
As a result, you'll get circle center coordinates:
c_i = (1, 0, 0)
As your citate says, choose axis not parallel to n vect0r- for example, y-axis, get it's direction vector Y_dir=(0,1,0) and multiply by n
t = Y_dir x n = (0, 0, 1)
b = n x t = (0, 1, 0)
Now you have two vectors t,b in circle plane to build circumference points.

Shape.Rotation property behavior

With sketch
.ScaleHeight 16, msoFalse
.ScaleWidth 16, msoFalse
.Fill.Visible = False
.Line.Weight = 1
.Line.ForeColor.RGB = RGB(0, 0, 0)
.Left = XCoordinate
.Top = YCoordinate
.Rotation = AngleDeg
End With
This is a code i am writing. I have X and Y coordinate calculated using a formula that changes during every iteration of for loop.
My question is does this shape then go to the given X and Y before rotating itself? Plus, what is the axis of rotation it uses when it rotates by this angle value stored in variable AngleDeg?
I am concerned about this because if this rotates about it's left top corner, then it is a problem for me because i need it to rotate about axis passing through it's center point. Same is the reason for why i have my scalewidth and scaleheight properties before this Left and Top properties.
I found that it was using correct X and Y of my center of the sketch (calculated considering origin of the sketch is left top corner), but then it was getting disturbed when it was scaling the sketch which was then moving/messing up the co-ordinates of the center of the sketch.
Please guide.
The next procedure is able to rotate a shape, according to its center coordinates. Of course, when you test it (unchanged), on the active worksheet you must have a shape named 'sketch':
Sub testRotFunction()
Dim sketch As Shape
Set sketch = ActiveSheet.Shapes("sketch")
centerRotation sketch, 0
End Sub
Sub centerRotation(sR As Shape, rotAngle As Double)
Dim rad As Double, x As Double, y As Double
Dim x1 As Double, x2 As Double
x = sR.Top: y = sR.Left
x1 = (sR.Width / 2) * -1
x2 = sR.Height
rad = rotAngle * Atn(1) / 45
With sR
.Top = x + (.Height - .Width / 2 - x1 - x2) * (1 - Cos(rad)) / 2
.Left = y + (.Height - .Width / 2 - x1 - x2) * Sin(rad) / 2
.Rotation = rotAngle
End With
End Sub

How do i fix this error when converting a Matlab code to Python

I converted a Matlab code into python by manually typing it out. However i keep getting an error message which i still have not been able to fix. what am i doing wrong and how do i get the plot as that in Matlab? Just is little information about the code; this is a Explicit finite difference method for solving pressure distribution in an oil reservoir with production from the middle block only. Its similar to the heat equation, Ut=Uxx. I was told to add more text because my question is mostly code so had to add all these details. I think that notification has vanished now.
[P_new[N] = 4000 #last blocks at all time levels equals 4000
IndexError: index 9 is out of bounds for axis 0 with size 9]
The Matlab code which runs ok is below: The python code follows.
clear
clc
% Solution of P_t = P_{xx}
L = 1000 ; %ft length of reservoir
W = 100 ; %ft reservoir width
h = 50 ;%ft pay thickness
poro = 0.25; % rock porosity
k_o = 5; %md effective perm to oil
P_i = 4000; %psia initial pressure
B_o = 1.25; %oil formation vol fact
mu = 5; %cp oil visc
c_t = 0.0000125; %1/atm total compressibility
Q_o = 10;%stb/day production rate from central well
alpha = c_t*mu*poro/k_o;
T = 1;
N_time = 50;
dt = T/N_time;
% % Number of grid cells
N =9; %number of grid cells
%N =11;%number of grid cells
dx = (L/(N-1)); %distance between grid blocks
x = 0+dx*0.5:dx:L+dx; %points in space
for i=1:N
P_old(i)=P_i;
FPT(i)=0;
end
FPT((N+1)/2)=-Q_o*B_o*mu/1.127/W/dx/h/k_o; %source term at the center block of grid cell
P_new = P_old;
for j = 1:N_time
for k = 1: N
if k<2
P_new(k)=4000;%P_old(k)+dt/alpha*((P_old(k+1)-2*P_old(k)+P_old(k))/dx^2+FPT(k));
elseif k > N-1
P_new(k) = 4000;%P_old(k)+dt/alpha*((P_old(k)-2*P_old(k)+P_old(k-1))/dx^2+FPT(k));
else
P_new(k) = P_old(k)+dt/alpha*((P_old(k+1)-2*P_old(k)+P_old(k-1))/dx^2+FPT(k));
end
end
plot(x,P_new, '-x')
xlabel('X')
ylabel('P(X)')
hold on
grid on
%%update "u_old" before you move forward to the next time level
P_old = P_new;
end
hold off
Python Code:
import numpy as np
import matplotlib.pyplot as plt
# Solution of P_t = P_{xx}
L = 1000 #ft length of reservoir
W = 100 #ft reservoir width
h = 50 #ft pay thickness
poro = 0.25 # rock porosity
k_o = 5 #md effective perm to oil
P_i = 4000 #psia initial pressure
B_o = 1.25 #oil formation vol fact
mu = 5 #cp oil visc
c_t = 0.0000125 #1/atm total compressibility
Q_o = 10 #stb/day production rate from central well
alpha = c_t * mu * poro / k_o
T = 1
N_time = 20
dt = T / N_time
# % Number of grid cells
N = 9 #number of grid cells
dx = (L / (N - 1)) #distance between grid blocks
x= np.arange(0.0,L+dx,dx)
P_old = np.zeros_like(x) #pressure at previous time level
P_new = np.zeros_like(x) #pressure at previous time level
FPT = np.zeros_like(x)
for i in range(0,N):
P_old[i]= P_i
FPT[int((N + 1) / 2)]= -Q_o * B_o * mu / (1.127 * W * dx * h * k_o) # source term at the center block of grid cell
P_new = P_old
d=np.arange(0,N)
for j in range(0,N_time):
for k in range(0,N):
P_new[0] = 4000 #pressure at first block for all time levels equals 4000
P_new[N] = 4000 #pressure at last block for all time levels equals 4000
P_new[k]= P_old[k] + dt / alpha * ((P_old[k+1] - 2 * P_old[k] + P_old[k - 1]) / dx ** 2 + FPT[k])
plt.plot(x, P_new)
plt.xlabel('X')
plt.ylabel('P(X)')
P_old = P_new
Matlab uses 1 based indexing , Python arrays use "0" based indexing. If you define an array of length N in python, the indices are from 0 to N-1.
So just replace the index N to index N-1 in your code as below and it works.
import numpy as np
import matplotlib.pyplot as plt
# Solution of P_t = P_{xx}
L = 1000 #ft length of reservoir
W = 100 #ft reservoir width
h = 50 #ft pay thickness
poro = 0.25 # rock porosity
k_o = 5 #md effective perm to oil
P_i = 4000 #psia initial pressure
B_o = 1.25 #oil formation vol fact
mu = 5 #cp oil visc
c_t = 0.0000125 #1/atm total compressibility
Q_o = 10 #stb/day production rate from central well
alpha = c_t * mu * poro / k_o
T = 1
N_time = 20
dt = T / N_time
# % Number of grid cells
N = 9 #number of grid cells
dx = (L / (N - 1)) #distance between grid blocks
x= np.arange(0.0,L+dx,dx)
P_old = np.zeros_like(x) #pressure at previous time level
P_new = np.zeros_like(x) #pressure at previous time level
FPT = np.zeros_like(x)
for i in range(0,N):
P_old[i]= P_i
FPT[int((N + 1) / 2)]= -Q_o * B_o * mu / (1.127 * W * dx * h * k_o) # source term at the center block of grid cell
P_new = P_old
d=np.arange(0,N)
for j in range(0,N_time):
for k in range(0,N-1):
P_new[0] = 4000 #pressure at first block for all time levels equals 4000
P_new[N-1] = 4000 #pressure at last block for all time levels equals 4000
P_new[k]= P_old[k] + dt / alpha * ((P_old[k+1] - 2 * P_old[k] + P_old[k - 1]) / dx ** 2 + FPT[k])
plt.plot(x, P_new)
plt.xlabel('X')
plt.ylabel('P(X)')
P_old = P_new
output:

Creating values with loop in vba and storing them in a column in the worksheet?

I am trying to calculate velocity and acceleration, with the variable being the time t. I'd like to write these in vba, to make it faster, because later on I'll need velocity and acceleration for several other calculations combined with different logical conditions. I would like the results to be printed in the worksheet, to double check during calculation if the results are realistic.
example of how it should like more or less
t vel a
0.002 39 -777
0.004 38.6 -802
0.006 35 -500
0.008 33.4 -400
0.01 32.1 -12297.1
So I have tried a few different things based on comments:
This first code example works fine I think from the results, but I still can see any of the results in between > so main question: any chance I can change the commend to write to the worksheet without changing much else?
The second code example is an attempt to write everything into arrays: I do understand the principle I think, but here the main error seems to be that my variable t is not getting generated properly and therefore the formulas are not calculated: can't find the mistakes here and I would be grateful for some more help...
Kinematics Calculation
'Set t from 0 to 2 s with time step of 0.002s; Calculate Rot_vel until <= 0,
'Find index t_2 when Rot_vel <= 0
t = 0
Do
t = t + 0.002
Rot_vel = -10356# * t ^ 6 + 24130# * t ^ 5 - 19002# * t ^ 4 + 4933# * t ^ 3 +
362# * t ^ 2 - 213# * t + 39
Worksheets("test").Range(Cells(3, 2), Cells(1003, 2)) = Rot_vel
Loop Until Rot_vel <= 0
If Rot_vel <= 0 Then
t_2 = t
If t_2 > 0 Then
Debug.Print t_2
End If
End If
'Continue calculations for t 0 to t_2 with 0.002 steps
t = 0
Do
t = t + 0.002
A_rot = -62136# * t ^ 5 + 120650# * t ^ 4 - 76008# * t ^ 3 + 14797.8 * t
^ 2 + 723.26 * t - 212.7
Worksheets("test").Range(Cells(3, 3), Cells(1003, 3)).value = A_rot
L = MoI * Rot_vel / 1000
M = MoI * A_rot / 1000
Worksheets("test").Range(Cells(3, 8), Cells(1003, 8)).value = L
Worksheets("test").Range(Cells(3, 9), Cells(1003, 9)).value = M
G = L / t_2
Worksheets("test").Range(Cells(3, 10), Cells(1003, 10)).value = G
Loop Until t = t_2
Second version:
Kinematics Calculation
'Set t from 0 to 2 s with time step of 0.002s; Calculate Rot_vel until <= 0,
'Find index t_2 when Rot_vel <= 0
Dim arrCalc As Variant
Dim i As Integer
Dim j As Integer
ReDim arrCalc(i To 1003, j To 13)
For i = LBound(arrCalc, 2) To UBound(arrCalc, 2)
t = 0
Do
t = t + 0.002
arrCalc(i, 1) = t
arrCalc(i, 2) = -10356# * t ^ 6 + 24130# * t ^ 5 - 19002# * t ^ 4 + 4933#
* t ^ 3 + 362# * t ^ 2 - 213# * t + 39 'Rot_vel
Loop Until arrCalc(i, 2) < 0
Dim pos, val
val = 0
pos = Application.Match(val, arrCalc(i, 2), False)
pos = t_2
t = 0
Do
t = t + 0.002
arrCalc(i, 3) = -62136# * t ^ 5 + 120650# * t ^ 4 - 76008# * t ^ 3 +
14797.8 * t ^ 2 + 723.26 * t - 212.7
arrCalc(i, 8) = MoI * Rot_vel / 1000 'L
arrCalc(i, 9) = MoI * A_rot / 1000 'M
arrCalc(i, 10) = 1 / t_2 * L 'G
Loop Until t = t_2
Next i
With Worksheets("test")
.Cells(2, "A") = 0
.Cells(3, "A").Resize(UBound(arrCalc, 1), UBound(arrCalc, 2)) = Rot_vel
.Cells(2, "A").Resize(UBound(arrCalc, 1) + 1, 1) = t
'.Cells(3, "C").Resize(UBound(arrCalc, 1), UBound(arrCalc, 3)) = A_rot
End With
Your variables a_rot and rot_val don't look to me like arrays but normal variables. Therefore, only one value is stored in them and of course you get only one value as an output.
I see two options: 1) You write all of your values into an array and then copy the array to the sheet. 2) You write each calculation line by line to the sheet. Number 1) is much much faster.
A solution could look something like this:
ReDim Array (Lines, Columns)
For each line
Array (line, Columns1) = Formula1
Array (line, Columns2) = Formula2
Array (line, Columns3) = Formula3
Next
Build a 2-D array with times and calculations then dump the results back onto the worksheet.
Sequential time is very prone to 15 significant digit floating point errors. These errors can be minimized with a form of datum dimensioning that creates all new entries relative to the original starting point instead of the previous value. The former method can have no error greater than a single calculation while the latter can compounding errors by carrying them into the next calculation.
Sub kinematicsCalculation()
Dim t As Double, start As Double, i As Long, arr As Variant
start = TimeSerial(0, 0, 0) 'start at 0 second mark
ReDim arr(1 To 1000, 1 To 2)
For i = LBound(arr, 1) To UBound(arr, 1)
arr(i, 1) = start + TimeSerial(0, 0, 2 * i) / 1000
'cannot attempt velocity calc without Rot_vel_i
arr(i, 2) = "<velocity calculation here>"
Next i
With Worksheets("sheet")
.Cells(2, "B") = start
.Cells(3, "B").Resize(UBound(arr, 1), UBound(arr, 2)) = arr
.Cells(2, "B").Resize(UBound(arr, 1) + 1, 1).NumberFormat = "[hh]:mm:ss.000"
End With
End Sub

Improving VB.NET Chart Label Values

It works out that when using the autofit of axis labels, the label values take on unappealing values. Has anyone developed code to evaluate range and scale of axis values and then show for example label values at intervals of 1, 5, 10, 20, etc? The syntax I am using is listed below:
Chart1.Series.Clear()
Chart1.ChartAreas("ChartArea1").AxisX.MajorGrid.Enabled = False
Chart1.ChartAreas("ChartArea1").AxisY.MajorGrid.Enabled = False
Chart1.ChartAreas("ChartArea1").AxisX.LabelStyle.Format = "N2"
Chart1.ChartAreas("ChartArea1").AxisY.LabelStyle.Format = "N2"
Chart1.ChartAreas("ChartArea1").AxisY.LabelStyle.Angle = 0
Chart1.ChartAreas("ChartArea1").AxisY.LabelStyle.Enabled = True
Chart1.ChartAreas("ChartArea1").AxisX.IsLabelAutoFit = True
Chart1.ChartAreas("ChartArea1").AxisX.LabelStyle.Font = New System.Drawing.Font("Times New Roman", 12.0F, System.Drawing.FontStyle.Bold)
Chart1.ChartAreas("ChartArea1").AxisY.LabelStyle.Font = New System.Drawing.Font("Times New Roman", 12.0F, System.Drawing.FontStyle.Bold)
Chart1.ChartAreas("ChartArea1").AxisX.LabelStyle.IsEndLabelVisible = True
RESOLVED: I discovered that if you use the floor and ceiling functions on xmin and xmax, and set intervalautomode=True, then the last right label will typically be displayed, and the labels will appear better. The floor and ceiling prevent label values of -2.3, 5.7, etc.
Dim xmin, xmax As Double
xmin = 1.0E+30
xmax = -1.0E+30
For i = 1 To 1000
If x(i) < xmin Then xmin = x(i)
If x(i) > xmax Then xmax = x(i)
Next
Chart1.ChartAreas(0).AxisX.Minimum = Math.Floor(xmin)
Chart1.ChartAreas(0).AxisX.Maximum = Math.Ceiling(xmax)
Chart1.ChartAreas(0).AxisX.IntervalAutoMode = True
Chart1.ChartAreas(0).AxisX.LabelStyle.Format = "N1"
For i = 1 To 1000
Chart1.Series(0).Points.AddXY(x(i), y(i))
Next
You would need to do more work if the range of x is less than 1, for example 0.02 to 0.85, or 0.0002 to 0.005, etc. since the floor and ceiling always round down to the next lower integer and round right to the next greatest integer.
You need to set AxisX.Minimum and AxisX.Interval.
Chart1.ChartAreas(0).AxisX.Minimum = 0
Chart1.ChartAreas(0).AxisX.Interval = 1
Chart1.ChartAreas(0).AxisX.IntervalAutoMode = IntervalAutoMode.FixedCount
You can set AxisX.Minimum according to Series.Points(0).XValue if you want.
Chart1.ChartAreas(0).AxisX.Minimum = Math.Floor(Chart1.Series(0).Points(0).XValue / 5) * 5
Chart1.ChartAreas(0).AxisX.Interval = 5

Resources