From f684019447f9ced70a7ca5033e0772d60ebff7ea Mon Sep 17 00:00:00 2001 From: Duncan Holmes <dholmes4@huskers.unl.edu> Date: Sat, 12 Apr 2025 20:05:06 -0500 Subject: [PATCH] still need to add print statments if you want to know all of what's going on but i'd rather like... not do that so i'm not going to --- example_graph_code.py | 166 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 157 insertions(+), 9 deletions(-) diff --git a/example_graph_code.py b/example_graph_code.py index c01d003..f086f47 100644 --- a/example_graph_code.py +++ b/example_graph_code.py @@ -6,6 +6,7 @@ from kivy.lang import Builder import matplotlib.pyplot as plt from matplotlib.backends.backend_agg import FigureCanvasAgg +import matplotlib.dates as mdates # Import for date formatting import pandas as pd from io import BytesIO @@ -15,50 +16,197 @@ from PIL import Image as PILImage class GraphScreen(Screen): def __init__(self, **kwargs): + print(f"\t\t i'm in the constructor now") + print(f"\t\t i'm gonna call Screen's contructor because that's how it is....") super().__init__(**kwargs) + print(f"\t\t now i'm gonna set graph_texture, which is a variable, to None. Don't worry—it gets set later.") self.graph_texture = None + print(f"\t\t that's the end of the constructor hehe") + print('\n\n') def on_enter(self): - # Sample CoinGecko-style data - data = { - "prices": [ + print(f"\t\t\t we're in on_enter now . i think this is a 'callback function that gets called when the screen is entered'") + print(f"\t\t\t ok well if you say so mr. autocomplete line bot :- / \n") + + # Sample CoinGecko style data + data = \ + { + "prices": + [ [1711843200000, 69702.31], [1711929600000, 71246.95], [1711983682000, 68887.75] ] } + print(f"\t\t\t data: {data}") + # Create DataFrame + """ + this is screwy + DataFrame object + use the parameter collums & the strings... as the labels for said collums + use the data dictionary's prices's values as a parameter for inputs into a table + + the visualized version of this is + timestamp price + 1711843200000 69702.31 + 1711929600000 71246.95 + 1711983682000 68887.75 + + """ df = pd.DataFrame(data["prices"], columns=["timestamp", "price"]) + print(f"\t\t\t df: {df}") + + print(f"\t\t\t converting timestamp to datetime...") + + """ + ok now that we have that weird ahh python table object working + let's convert the numerical bull-pucky timestamps to datetime objects + from + ##### number number blah blah ERRUUGHGHGHH -------> yyyy/mm/dd/hh/mm/ss + + the way it does this is weird but cool + 1. call the values inside the timestamp collum like a dicationry does + 2. set those values .... by using pd which is like a dictionary? i doubt it. + use pd which is a lower level function in this context ... and it's method + which converts the values of "timestamp" into datetime objects + WHICH IS BADASS + 3. the unit="ms" is used becuase the CoinGecko goes down to the milasecond + """ + # convert timestamp to datetime df["timestamp"] = pd.to_datetime(df["timestamp"], unit="ms") + print(f"\t\t\t df: {df}") - # Plot + """ + big boy method useage + + fig .... a figure object 'should be seen as the entire graph' + apperntly you can save it as a png or jpeg + fig.savefig("my_plot.png") + or 'use it in kivy like you're doing right now' + + ax ... axes + ax stand for axes + ax.plot(x, y) ????? + "this is the actual area where you graph is drawn" + like the little commie block the graph actually lives in + + ax.plot(x, y) # Plot lines + ax.set_title(...) # Add a title + ax.set_xlabel(...) # X-axis label + ax.set_ylabel(...) # Y-axis label + ax.legend(...) # Add a legend + + plt is a static object that allows for static method calling. i guess + .subplots() returns a figure and an axis object : - ) + """ + # Create Matplotlib Figure and Axis fig, ax = plt.subplots() + print(f'\t\t\t ax: {ax}') + print(f'\t\t\t fig: {fig}') + + """ + ax.plot(x, y) # Plot lines + ax.set_title(...) # Add a title + ax.set_xlabel(...) # X-axis label + ax.set_ylabel(...) # Y-axis label + ax.legend(...) # Add a legend + """ + print(f"\t\t\t whole lotta ax methods i'm boutta call") + # Plot the data ax.plot(df["timestamp"], df["price"], label="Price", color="green") + print(f"\t\t\tgave ax plot points. like (x,y) but with dates & prices instead of numbers") + ax.set_title("Price Over Time") + print("\t\t\tgave ax a title") + ax.set_xlabel("Date") + print("\t\t\tgave ax a label for it's x axis") + ax.set_ylabel("Price (USD)") + print("\t\t\tgave ax a label for it's y axis") + ax.legend() + print("\t\t\tgave ax a legend. that means the axis-es are labeled") + + print(f'\t\t\t ax: {ax}') + + # **Key Change:** + # Manually set the x-axis tick positions to the exact datetime values in the DataFrame. + # it's a method. don't got nothin else to tell ye + print(f"\t\t\t i'm gonna make sure only the dates put in the data, show up on the graph ok?") + ax.set_xticks(df["timestamp"]) + print(f"\t\t\t ax.get_xticks = {ax.get_xticks()}") + + # Format the ticks to display in "YYYY-MM-DD" format. + print(f"\t\t\t i'm gonna format the numeric gobbelty gook that is the timestamps into a better yyyy_mm_dd format") + ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d')) + print(f"\t\t\t ax.xaxis.get_major_formatter() = {ax.xaxis.get_major_formatter()}") - # Convert plot to Kivy texture + # Note: Using manual ticks makes auto-formatting less necessary. + # fig.autofmt_xdate() # This line is optional now. BECAUSE IT AUTO FORMATS. I'M KEEPING IT IN JUST IN CASE.... world explodes idk + + """ + 1. makes a FigureCanvasAgg object using fig... a figure object only + wow + 2. canvas.draw = .... draws the figure onto the canvas + uhhh ok thanks autocomplete + 3. buf = BytesIO() = ... creates a buffer object + ? + 4. fig.savefig(buf, format='png') = ... saves the figure to the buffer object + 5. buf.seek(0) = ... seeks the buffer object to the beginning + """ + # Convert the plot to a Kivy texture canvas = FigureCanvasAgg(fig) canvas.draw() buf = BytesIO() fig.savefig(buf, format='png') buf.seek(0) + """ + 1. pil_image = PILImage.open(buf) = ... opens the buffer object as an image + 2. pil_image = pil_image.transpose(PILImage.FLIP_TOP_BOTTOM) = ... flips the image vertically + i guess it comes not vertically out the gate? why? + if you change FLIP_TOP_BOTTOM to FLIP_LEFT_RIGHT it flips it horizontally + and if you change FLIP_TOP_BOTTOM to DEFAULT_STRATEGY it assumely keeps it as it is orginally + so that's why the orginal command is there + 3. tex = Texture.create(size=pil_image.size, colorfmt='rgba') = ... creates a texture object + a texture object is a kivy image widget's property + so like + + Image: + id: image_id + texture: tex + """ + # Flip the image vertically to correct the orientation for Kivy pil_image = PILImage.open(buf).transpose(PILImage.FLIP_TOP_BOTTOM) tex = Texture.create(size=pil_image.size, colorfmt='rgba') tex.blit_buffer(pil_image.convert('RGBA').tobytes(), colorfmt='rgba', bufferfmt='ubyte') - tex.flip_vertical() - # Access the image widget via ids correctly + #if you had this your graph would be flipped veritcally + #the.... uhm. the birdy that told me to how to write this code put this here and it made the graph look funny + #i commented it out. and it worked. + #i found that very funny. + #tex.flip_vertical() + + # Save the generated texture self.graph_texture = tex class MyApp(App): def build(self): - return Builder.load_file('example_graph_code.kv') + print("\t i'm pretty sure this is MyApp's run function") + print("\t i'm gonna use Builder's static method load_file() to load your file...") + kivy_file_directory = 'example_graph_code.kv' + print(f"\t {kivy_file_directory}") + return Builder.load_file(kivy_file_directory) + print(f"\t i'm done with the build function ;- )") + if __name__ == "__main__": + print('you pressed the start button :-) ') + print("i'm making a MyApp object called app") app = MyApp() - app.run() \ No newline at end of file + print("i'm making app do the run function") + app.run() + print("program's done :-(") -- GitLab