Make graphs
This commit is contained in:
Binary file not shown.
28
main.py
28
main.py
@@ -3,13 +3,37 @@
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
from makeGraph import makeGraph, UQ_COLOURS as UQC
|
||||
|
||||
DATA_FILE_PATH = ".\\data\\AERO4450-Group-10-Data-Analysis-v2.xls"
|
||||
DATA_FILE = pd.read_excel(DATA_FILE_PATH)
|
||||
actualData = pd.read_excel(DATA_FILE_PATH, sheet_name="Actual Data")
|
||||
calibrationData = pd.read_excel(DATA_FILE_PATH, sheet_name="Calibration Data Graphs")
|
||||
|
||||
|
||||
def main():
|
||||
print(DATA_FILE)
|
||||
testRun = 0
|
||||
|
||||
cols = [f"Unnamed: {3 + testRun*5}", f"Unnamed: {4+ testRun*5}"]
|
||||
data = actualData[cols].rename(columns = {cols[0]:'Time', cols[1]:'Strain'})
|
||||
|
||||
data = data[5:505].astype({"Time":"int", "Strain":"float"})
|
||||
data1 = data[0::2]
|
||||
data2 = data[1::2]
|
||||
|
||||
|
||||
makeGraph({
|
||||
"title": f"Strain over Time\nRun: {testRun+1}",
|
||||
"xLabel": "Time (ms) - Δt = 10ms",
|
||||
"yLabel": "Strain (ε)",
|
||||
"plots":[
|
||||
{"type":"scatter", "x": data1["Time"], "y": data1["Strain"], "args":{"s":10, "zorder":2}, "label":"Upper", "colour": UQC["purple"]},
|
||||
{"type":"scatter", "x": data2["Time"], "y": data2["Strain"], "args":{"s":10, "zorder":1}, "label":"Lower", "colour": UQC["dark_grey"]},
|
||||
{"type":"plot", "x": data1["Time"], "y": data1["Strain"], "args":{"zorder":0, "alpha":0.25}, "label":"Upper", "colour": UQC["purple"]},
|
||||
{"type":"plot", "x": data2["Time"], "y": data2["Strain"], "args":{"zorder":0, "alpha":0.25}, "label":"Lower", "colour": UQC["dark_grey"]},
|
||||
|
||||
]
|
||||
})
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
275
makeGraph.py
Normal file
275
makeGraph.py
Normal file
@@ -0,0 +1,275 @@
|
||||
### MatPlotLib Graph Wrapper
|
||||
#### Written by Cal.W 2020, originally for MECH2700 but continually
|
||||
#### expanded upon.
|
||||
#### 2023 - Added UQ Colors
|
||||
|
||||
|
||||
__author__ = "Cal Wing"
|
||||
__version__ = "0.1.6"
|
||||
|
||||
import numpy as np
|
||||
import matplotlib
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib.colors as colors
|
||||
from mpl_toolkits.axes_grid1 import make_axes_locatable
|
||||
|
||||
UQ_COLOURS = {
|
||||
# Primary
|
||||
"purple": "#51247A",
|
||||
"white" : "#FFFFFF",
|
||||
"black" : "#000000",
|
||||
|
||||
# Secondary
|
||||
"light_purple": "#962A8B",
|
||||
"red" : "#E62645",
|
||||
"green" : "#2EA836",
|
||||
"gold" : "#BB9D65",
|
||||
"neutral" : "#D7D1CC",
|
||||
"orange" : "#EB602B",
|
||||
"yellow" : "#FBB800",
|
||||
"blue" : "#4085C6",
|
||||
"aqua" : "#00A2C7",
|
||||
"dark_grey" : "#999490"
|
||||
}
|
||||
|
||||
#Colorbar Function by Joseph Long & Mike Lampton
|
||||
# Retrieved from https://joseph-long.com/writing/colorbars/ on 31/10/2021
|
||||
# Minor Modifications made by Cal.W 2021
|
||||
def colorbar(mappable, size="5%", pad=0.05, lsize=None, lpad=None, lax=True, **kwargs):
|
||||
last_axes = plt.gca()
|
||||
ax = mappable.axes
|
||||
fig = ax.figure
|
||||
divider = make_axes_locatable(ax)
|
||||
if lax:
|
||||
lsize = lsize if lsize is not None else size
|
||||
lpad = lpad if lpad is not None else pad
|
||||
dax = divider.append_axes("left", size=lsize, pad=lpad)
|
||||
dax.set_frame_on(False)
|
||||
dax.grid(False)
|
||||
dax.set_yticks([])
|
||||
dax.set_xticks([])
|
||||
cax = divider.append_axes("right", size=size, pad=pad)
|
||||
cbar = fig.colorbar(mappable, cax=cax, **kwargs)
|
||||
plt.sca(last_axes)
|
||||
return cbar
|
||||
|
||||
def makeGraph(graphData, showPlot=True, doProgramBlock=True):
|
||||
""" Generate a matplotlib graph based on a simple dictionary object
|
||||
Input:
|
||||
dict(graphData): The dictionary containing all the graph data - see example for more info
|
||||
bool(showPlot[True]): Should the function display the plot
|
||||
bool(doProgramBlock[True]): Should the function block the main python thread
|
||||
|
||||
Returns: The the figure and axes from matplotlib.pyplot.subplots()
|
||||
From 'matplotlib.pyplot.subplots():
|
||||
fig : `matplotlib.figure.Figure`
|
||||
ax : `matplotlib.axes.Axes` or array of Axes
|
||||
*ax* can be either a single `~matplotlib.axes.Axes` object or an
|
||||
array of Axes objects if more than one subplot was created.
|
||||
Example:
|
||||
makeGraph({
|
||||
"title": "Simple Plot",
|
||||
"xLabel": "x label",
|
||||
"yLabel": "y label",
|
||||
"plots": [
|
||||
{"x":[0,1,2,3,4], "y":[0,1,2,3,4], "label":"Linear"},
|
||||
{"x":[0,1,2,3,4], "y":[5,5,5,5,5]},
|
||||
{"x":[4,3,2,1,0], "y":[4,3,2,1,0], "label":"Linear2"},
|
||||
{"x":0, "type":"axvLine", "label":"Red Vertical Line", "color":"red"},
|
||||
{"y":6, "type":"axhLine", "label":"Dashed Horizontal Line", "args":{"linestyle":"--"}},
|
||||
{"type":"scatter", "x":4, "y":4, "label":"A Random Point", "colour":"purple", "args":{"zorder":2}}
|
||||
]
|
||||
})
|
||||
"""
|
||||
|
||||
doKeyCopy = True
|
||||
plotDim = (1,)
|
||||
if "subPlots" in graphData:
|
||||
if "plotDim" in graphData: plotDim = graphData["plotDim"]
|
||||
else: plotDim = (1,len(graphData["subPlots"]))
|
||||
else:
|
||||
graphData["subPlots"] = [graphData]
|
||||
doKeyCopy = False
|
||||
|
||||
figSize = graphData["figSize"] if "figSize" in graphData else None
|
||||
|
||||
fig, axes = plt.subplots(*plotDim, figsize=figSize) # Create a figure and an axes.
|
||||
|
||||
#if len(graphData["subPlots"]) <= 1:
|
||||
# axes = [axes]
|
||||
#Makes everything nice and linear
|
||||
# IE ((1,2), (3,4)) = (1,2,3,4)
|
||||
flatAxes = np.array(axes).flatten().tolist()
|
||||
|
||||
loopKeys = [
|
||||
"xLabel", "yLabel", "title", "axis", "grid", "xPos", "yPos",
|
||||
"xLabelPos", "yLabelPos", "xTickPos", "yTickPos", "xScale", "yScale",
|
||||
"xTickMap", "yTickMap", "plots", "xLim", "yLim"
|
||||
]
|
||||
|
||||
#Feel like this could be optimised
|
||||
if doKeyCopy:
|
||||
for key in loopKeys:
|
||||
if key not in graphData: continue
|
||||
if key in graphData:
|
||||
for axGraphData in graphData["subPlots"]:
|
||||
if key not in axGraphData:
|
||||
axGraphData[key] = graphData[key]
|
||||
|
||||
|
||||
for i, axGraphData in enumerate(graphData["subPlots"]):
|
||||
ax = flatAxes[i]
|
||||
|
||||
#Draw many plots as needed
|
||||
# Also provide functions for drawing other types of lines
|
||||
if "plots" in axGraphData:
|
||||
getSafeValue = lambda key: pData[key] if key in pData else None #Only return the key-value if present in pData
|
||||
getSafeValue2 = lambda key, key2: pData[key][key2] if key in pData and key2 in pData[key] else None
|
||||
for pData in axGraphData["plots"]:
|
||||
getSafeColour = getSafeValue("colour") or getSafeValue("color") #Figen American Spelling
|
||||
optArgs = {} if "args" not in pData else pData["args"] #Allow for other args to be passed in
|
||||
if "type" not in pData or pData["type"] == "plot":
|
||||
ax.plot(pData["x"], pData["y"], label=getSafeValue("label"), color=getSafeColour, **optArgs)
|
||||
elif pData["type"] == "hLine":
|
||||
ax.hlines(pData["y"], *pData["x"], label=getSafeValue("label"), color=getSafeColour, **optArgs)
|
||||
elif pData["type"] == "vLine":
|
||||
ax.vlines(pData["x"], *pData["y"], label=getSafeValue("label"), color=getSafeColour, **optArgs)
|
||||
elif pData["type"] == "axvLine":
|
||||
if "y" not in pData: pData["y"] = (0, 1) #Span the whole graph
|
||||
ax.axvline(pData["x"], *pData["y"], label=getSafeValue("label"), color=getSafeColour, **optArgs)
|
||||
elif pData["type"] == "axhLine":
|
||||
if "x" not in pData: pData["x"] = (0, 1) #Span the whole graph
|
||||
ax.axhline(pData["y"], *pData["x"], label=getSafeValue("label"), color=getSafeColour, **optArgs)
|
||||
elif pData["type"] == "contour":
|
||||
cs = ax.contour(getSafeValue("x"), getSafeValue("y"), pData["z"], levels=getSafeValue("levels"), colors=getSafeColour, **optArgs)
|
||||
if "label" in pData: cs.collections[0].set_label(getSafeValue("label"))
|
||||
elif pData["type"] == "scatter":
|
||||
ax.scatter(pData["x"], pData["y"], marker=getSafeValue("marker"), label=getSafeValue("label"), color=getSafeColour, **optArgs)
|
||||
elif pData["type"] == "matshow":
|
||||
ms = ax.matshow(pData["matrix"], origin=getSafeValue("origin"), label=getSafeValue("label"), **optArgs)
|
||||
if "colourBar" in pData:
|
||||
colorbar(ms, extend=getSafeValue2("colourBar", "extend"))
|
||||
elif pData["type"] == "pColourMesh":
|
||||
mesh = []
|
||||
if "X" in pData or "Y" in pData:
|
||||
mesh = [pData["X"], pData["Y"], pData["Z"]]
|
||||
if "x" in pData or "y" in pData:
|
||||
x = pData["x"]; y = pData["y"]
|
||||
|
||||
if type(x) in [int, float]: x = (0, x, None)
|
||||
if type(y) in [int, float]: y = (0, x, None)
|
||||
x = tuple(x); y = tuple(y)
|
||||
if len(x) < 3: x = (x[0], x[1], None)
|
||||
if len(y) < 3: y = (y[0], y[1], None)
|
||||
|
||||
x = np.arange(x[0], x[1], x[2])
|
||||
y = np.arange(y[0], y[1], y[2])
|
||||
X, Y = np.meshgrid(x, y)
|
||||
|
||||
mesh = [X, Y, pData["Z"]]
|
||||
else:
|
||||
mesh = [pData["Z"]]
|
||||
|
||||
cNorm = None
|
||||
if "norm" in pData:
|
||||
cNorm = colors.LogNorm(vmin=pData["norm"][0], vmax=pData["norm"][1])
|
||||
|
||||
pcMesh = ax.pcolormesh(*mesh, norm=cNorm, shading=getSafeValue("shading"), label=getSafeValue("label"), **optArgs)
|
||||
#pcMesh = ax.imshow(pData["Z"], norm=cNorm, origin="lower")
|
||||
|
||||
if "colourBar" in pData:
|
||||
cBarOptArgs = pData["colourBar"]["optArgs"] if "optArgs" in pData["colourBar"] else {}
|
||||
fig.colorbar(pcMesh, ax=ax, extend=getSafeValue2("colourBar", "extend"), **cBarOptArgs)
|
||||
elif pData["type"] == "imshow":
|
||||
cNorm = None
|
||||
if "norm" in pData:
|
||||
cNorm = colors.LogNorm(vmin=pData["norm"][0], vmax=pData["norm"][1])
|
||||
|
||||
ims = ax.imshow(pData["data"], norm=cNorm, origin=getSafeValue("origin"), label=getSafeValue("label"), **optArgs)
|
||||
|
||||
if "colourBar" in pData:
|
||||
cBarOptArgs = pData["colourBar"]["optArgs"] if "optArgs" in pData["colourBar"] else {}
|
||||
colorbar(ims, extend=getSafeValue2("colourBar", "extend"), **cBarOptArgs)
|
||||
|
||||
#Set extra options as needed
|
||||
if "xLabel" in axGraphData: ax.set_xlabel(axGraphData["xLabel"]) # Add an x-label to the axes.
|
||||
if "yLabel" in axGraphData: ax.set_ylabel(axGraphData["yLabel"]) # Add an y-label to the axes.
|
||||
if "title" in axGraphData: ax.set_title(axGraphData["title"]) # Add an title to the axes.
|
||||
if "axis" in axGraphData: ax.axis(axGraphData["axis"]) # Set the axis type
|
||||
if "grid" in axGraphData: ax.grid(axGraphData["grid"]) # Add grids to the graph
|
||||
if "xPos" in axGraphData: # Add the abilty to move the x axis label and ticks
|
||||
ax.xaxis.set_label_position(axGraphData["xPos"])
|
||||
ax.xaxis.set_ticks_position(axGraphData["xPos"])
|
||||
if "yPos" in axGraphData: # Add the abilty to move the y axis label and ticks
|
||||
ax.yaxis.set_label_position(axGraphData["yPos"])
|
||||
ax.yaxis.set_ticks_position(axGraphData["yPos"])
|
||||
if "xLabelPos" in axGraphData: ax.xaxis.set_label_position(axGraphData["xLabelPos"]) # Add the abilty to move the x axis label
|
||||
if "yLabelPos" in axGraphData: ax.yaxis.set_label_position(axGraphData["yLabelPos"]) # Add the abilty to move the y axis label
|
||||
if "xTickPos" in axGraphData: ax.xaxis.set_ticks_position(axGraphData["xTickPos"]) # Add the abilty to move the x axis ticks
|
||||
if "yTickPos" in axGraphData: ax.yaxis.set_ticks_position(axGraphData["yTickPos"]) # Add the abilty to move the y axis ticks
|
||||
if "xScale" in axGraphData: ax.set_xscale(axGraphData["xScale"]) #Add x axis scaling if needed
|
||||
if "yScale" in axGraphData: ax.set_yscale(axGraphData["yScale"]) #Add y axis scaling if needed
|
||||
if "xLim" in axGraphData:
|
||||
xLimit = ()
|
||||
if type(axGraphData["xLim"]) in [int, float]:
|
||||
xLimit = (0, axGraphData["xLim"])
|
||||
else:
|
||||
xLimit = axGraphData["xLim"]
|
||||
ax.set_xlim(xLimit)
|
||||
if "yLim" in axGraphData:
|
||||
yLimit = ()
|
||||
if type(axGraphData["yLim"]) in [int, float]:
|
||||
yLimit = (0, axGraphData["yLim"])
|
||||
else:
|
||||
yLimit = axGraphData["yLim"]
|
||||
ax.set_ylim(yLimit)
|
||||
if "xTickMap" in axGraphData: #Allow for the mapping / transformation of the xAxis Ticks
|
||||
xTicks = matplotlib.ticker.FuncFormatter(lambda x, pos: '{0:g}'.format(axGraphData["xTickMap"](x)))
|
||||
ax.xaxis.set_major_formatter(xTicks)
|
||||
if "yTickMap" in axGraphData: #Allow for the mapping / transformation of the yAxis Ticks
|
||||
yTicks = matplotlib.ticker.FuncFormatter(lambda y, pos: '{0:g}'.format(axGraphData["yTickMap"](y)))
|
||||
ax.yaxis.set_major_formatter(yTicks)
|
||||
if "plots" in axGraphData and bool(sum([("label" in pData) for pData in axGraphData["plots"]])):
|
||||
ax.legend() #Only draw the legend if there are any defined
|
||||
|
||||
if "title" in graphData and not "figTitle" in graphData: fig.canvas.manager.set_window_title(graphData["title"].replace("\n", " ")) #Set the figure title correctly
|
||||
if "figTitle" in graphData:
|
||||
getSafeValue = lambda key: graphData[key] if key in graphData else None #Only return the key-value if present in graphData
|
||||
|
||||
fig.suptitle(graphData["figTitle"], fontsize=getSafeValue("figTitleFontSize"))
|
||||
fig.canvas.manager.set_window_title(graphData["figTitle"].replace("\n", " "))
|
||||
|
||||
plt.tight_layout() #Fix labels being cut off sometimes
|
||||
if showPlot:
|
||||
plt.show(block=doProgramBlock) #Show the plot and also block the program - doing things OO style allow for more flexible programs
|
||||
|
||||
return fig, axes
|
||||
|
||||
if __name__ == '__main__':
|
||||
#This is an example of drawing 4 plots by generating them
|
||||
graphData = {
|
||||
"figTitle": "Simple Plot",
|
||||
"figTitleFontSize": 16,
|
||||
"figSize": (8,8), #Yay America, this is in inches :/ # Note: cm = 1/2.54
|
||||
"xLabel": "x label",
|
||||
"yLabel": "y label",
|
||||
"plotDim": (2,2),
|
||||
"subPlots":[]
|
||||
}
|
||||
|
||||
#Create 4 identical plots with differnt names
|
||||
for i in range(4):
|
||||
newPlot = {
|
||||
"title": f"Graph {i+1}",
|
||||
"plots": [
|
||||
{"x":[0,1,2,3,4], "y":[0,1,2,3,4], "label":"Linear"},
|
||||
{"x":[0,1,2,3,4], "y":[5,5,5,5,5]},
|
||||
{"x":[4,3,2,1,0], "y":[4,3,2,1,0], "label":"Linear2"},
|
||||
{"x":0, "type":"axvLine", "label":"Red Vertical Line", "color":"red"},
|
||||
{"y":6, "type":"axhLine", "label":"Dashed Horizontal Line", "args":{"linestyle":"--"}},
|
||||
{"type":"scatter", "x":4, "y":4, "label":"A Random Point", "colour":"purple", "args":{"zorder":2}}
|
||||
]
|
||||
}
|
||||
graphData["subPlots"].append(newPlot)
|
||||
|
||||
makeGraph(graphData)
|
||||
Reference in New Issue
Block a user