From b240c7f412e4ec68db9b9faee26cead60f73704c Mon Sep 17 00:00:00 2001 From: flencydoc Date: Thu, 23 Dec 2021 04:04:49 +0000 Subject: [PATCH 1/4] Added docstrings to several undocumented functions. --- pdf/create_index.py | 15 ++++++++++ pdf/remove_links.py | 12 ++++++++ web/convert_table.py | 39 ++++++++++++++++++++++++ web/update_plots.py | 70 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 136 insertions(+) diff --git a/pdf/create_index.py b/pdf/create_index.py index cd6440113..6656e7f9f 100755 --- a/pdf/create_index.py +++ b/pdf/create_index.py @@ -13,6 +13,13 @@ def main(): + """ + This function reads the file index.html and extracts all headings from it. + It then creates a dictionary with the first letter of each heading as key, + and for each key, a dictionary containing all headings starting with that letter as value. + The second level of dictionaries contain the actual heading + text as keys and their ID's (which are also stored in another list) as values. + """ html = read_file('index.html') doc = BeautifulSoup(''.join(html), 'html.parser') hhh = defaultdict(lambda: defaultdict(list)) @@ -26,6 +33,14 @@ def main(): def print_hhh(hhh): + """ + Prints a table of contents for the commands in the given dictionary. + + The keys of `hhh` are letters and each letter is mapped to another dictionary + that maps command names to lists of links. The first link in each list is used as the heading for that command name, so it should be unique among all + commands (and ideally short). All other links should be unique among all lists but not necessarily short. The order of letters and commands within a + letter will match their order in `hhh`. + """ letters = hhh.keys() for letter in sorted(letters): hh = hhh[letter] diff --git a/pdf/remove_links.py b/pdf/remove_links.py index 86f333539..f1da70e13 100755 --- a/pdf/remove_links.py +++ b/pdf/remove_links.py @@ -25,6 +25,18 @@ def main(): + """ + Replaces all occurrences of `from_` with `to_` in the file at the given path. + + Args: + from_ (str): The string to be replaced. + to_ (str): The + replacement string. + + index_path (Path): Path object representing the file that is being modified by this function call. This parameter is not + optional, and it has a default value of None because we are required to pass it as an argument but we have no use for it in our code since we don't + need access to its attributes or methods while calling this function; therefore, there's no sensible default value for us to provide here. + """ index_path = Path('..', 'index.html') lines = read_file(index_path) out = ''.join(lines) diff --git a/web/convert_table.py b/web/convert_table.py index 0f21d789c..c58eb2193 100755 --- a/web/convert_table.py +++ b/web/convert_table.py @@ -1,7 +1,39 @@ #!/usr/bin/env python3 def convert_table(lines): + """ + Convert a table from ASCII art to Unicode box drawing characters or vice versa. + + :param lines: A list of strings representing the lines of the table. + The first line is assumed to be the top border, and all other lines are assumed to be inside it (i.e., not on any side). All borders must use ``+`` + for corners, ``-`` for horizontal bars, and ``|`` for vertical bars; no spaces are allowed between symbols in a single border symbol (except if there + is one space between two vertical bar symbols when converting from ASCII art). If there is only one line in `lines`, then it will be used as both the + top and bottom borders with no interior rows or columns; this can also happen if `lines` contains an empty string at some point. This function does + not check that each row has exactly as many columns as there are horizontal bar symbols in either its own border or that of its neighbor above/below + it (if applicable), but such checking could easily be added by modifying how column widths are calculated below. + # :type lines: list(str) + # :returns + out: The converted table represented by a single string containing newline characters at appropriate places so that when printed + """ def from_ascii(): + """ + Convert a list of lines from an ASCII table to a reStructuredText grid table. + + :param lines: A list of strings representing the rows in the ASCII + table. + :returns: A string containing the equivalent reStructuredText grid table. + + The first line is assumed to be a header row and will be used as + such in the resulting grid table, with each column separated by ``|`` characters (ASCII 124). The second line is assumed to contain column widths and + will be used as such in the resulting grid table, with each width separated by ``-`` characters (ASCII 45). All subsequent lines are treated as data + rows which will have their contents centered within their columns, surrounded on either side by ``|`` characters (ASCII 124) and padded on either side + by blank spaces so that all data rows have an equal number of cells. Data values are converted from plain text into bold typeface using double + asterisks for emphasis before being inserted into cells; this allows you to use plain text formatting within your tables without them being overridden + when converting back into ASCII tables later on. + + For example, given these three lines... + +-----+--------+-------+------------------+-------------+----------- + """ out = [] first, header, third, *body, last = lines first = first.translate(str.maketrans({'-': '━', '+': '┯'})) @@ -18,6 +50,13 @@ def from_ascii(): out.append(f'┗{last[1:-1]}┛') return '\n'.join(out) def from_unicode(): + """ + Convert a Unicode box-drawing character string to ASCII. + + :param str lines: A string of Unicode box-drawing characters. + :returns str out: The same + text with all the Unicode box drawing characters replaced by ASCII ones. + """ out = [] for line in lines: line = line.translate(str.maketrans('┏┓┗┛┠┼┨┯┷━─┃│', '+++++++++--||')) diff --git a/web/update_plots.py b/web/update_plots.py index 050ad5f14..4edc81053 100755 --- a/web/update_plots.py +++ b/web/update_plots.py @@ -12,6 +12,11 @@ def main(): + """ + This function scrapes the data from the web and wrangles it into a pandas DataFrame. + It then creates an interactive plotly line graph of covid cases + in New York State. + """ print('Updating covid deaths...') update_covid_deaths() print('Updating covid cases...') @@ -19,6 +24,11 @@ def main(): def update_covid_deaths(): + """ + Update the plot of global COVID-19 deaths over time. + + :param df: A pandas DataFrame with columns 'Continent', 'Date', and 'Total Deaths per Million'. + """ covid = pd.read_csv('https://covid.ourworldindata.org/data/owid-covid-data.csv', usecols=['iso_code', 'date', 'total_deaths', 'population']) continents = pd.read_csv('https://gist.githubusercontent.com/stevewithington/20a69c0b6d2ff' @@ -41,7 +51,15 @@ def update_covid_deaths(): def update_confirmed_cases(): + """ + Update the file covid_cases.js with a plot of total cases, gold price, bitcoin price and Dow Jones index. + """ def main(): + """ + This function scrapes the data from the web and wrangles it into a pandas DataFrame. + It then creates an interactive plotly line graph of covid cases + in New York State. + """ df = wrangle_data(*scrape_data()) f = get_figure(df) update_file('covid_cases.js', f) @@ -49,11 +67,29 @@ def main(): write_to_png_file('covid_cases.png', f, width=960, height=315) def scrape_data(): + """ + This function scrapes data from the following sources: + 1. Our World in Data (Total Cases) + 2. Yahoo Finance (Bitcoin, Gold, Dow Jones) + The + function returns a list of pandas Series objects containing the scraped data. + """ def scrape_covid(): + """ + This function scrapes the total number of covid cases from a csv file on the internet. + """ url = 'https://covid.ourworldindata.org/data/owid-covid-data.csv' df = pd.read_csv(url, usecols=['location', 'date', 'total_cases']) return df[df.location == 'World'].set_index('date').total_cases def scrape_yahoo(slug): + """ + Downloads historical stock price data from Yahoo Finance. + + :param str slug: The ticker symbol of the desired security. Expected to be a valid argument + for the `yfinance` function `Ticker()`. + :returns pd.Series(float): A pandas Series with timestamps as indices and adjusted closing prices as values, + sorted by timestamp in ascending order. + """ url = f'https://query1.finance.yahoo.com/v7/finance/download/{slug}' + \ '?period1=1579651200&period2=9999999999&interval=1d&events=history' df = pd.read_csv(url, usecols=['Date', 'Close']) @@ -63,6 +99,14 @@ def scrape_yahoo(slug): return map(pd.Series.rename, out, ['Total Cases', 'Bitcoin', 'Gold', 'Dow Jones']) def wrangle_data(covid, bitcoin, gold, dow): + """ + This function joins the Dow Jones, Gold and Bitcoin dataframes into a single one. + It then sorts them by date and interpolates missing values. It + discards rows before '2020-02-23'. + Finally it calculates percentages relative to day 1 of each series (Dow Jones, Gold, Bitcoin) + and adds a column + with covid cases. The result is returned as a new dataframe sorted by date in descending order. + """ df = pd.concat([dow, gold, bitcoin], axis=1) # Joins columns on dates. df = df.sort_index().interpolate() # Sorts by date and interpolates NaN-s. yesterday = str(datetime.date.today() - datetime.timedelta(1)) @@ -72,6 +116,11 @@ def wrangle_data(covid, bitcoin, gold, dow): return df.sort_values(df.index[-1], axis=1) # Sorts columns by last day's value. def get_figure(df): + """ + This function returns a plotly figure that shows the total cases of COVID-19 in the US and its economic + indicators. The data is taken from [The New + York Times](#) and retrieved using [NYT API](#). + """ figure = go.Figure() for col_name in reversed(df.columns): yaxis = 'y1' if col_name == 'Total Cases' else 'y2' @@ -97,6 +146,27 @@ def get_figure(df): # def update_file(filename, figure): + """ + Updates the file at `filename` with the plotly figure `figure`. + + :param filename: The path to a JSON file containing a Plotly figure. + :type filename: + str, required. + The extension of the file must be .json or .js (for legacy reasons). + + Note that if you are using JupyterLab and want to open + your updated + HTML files in an external browser window then you should save your + notebook as an HTML file instead of as a Jupyter notebook. + For more + information see this guide on [using Jupyter with Google Colab](http://jupyter- + notebook.readthedocs.io/en/stable/examples/Notebook/Running%20Code.html#Running-code). + + If you are not using JupyterLab then it is recommended + that you use .html for all types of notebooks so that they can be opened in any web browser, including Chrome, Firefox and Edge on Windows and macOS + without any extra configuration needed (see below for more details). This is because some browsers do not support JavaScript which is used by default + by Plotly's exporting functions to generate + """ lines = read_file(filename) f_json = figure.to_json(pretty=True).replace('\n', '\n ') out = lines[:6] + [f' {f_json}\n', ' )\n', '};\n'] From 030bb49ba67dbd89dcbb28d865d1f9296b5addc7 Mon Sep 17 00:00:00 2001 From: Fluency <93673101+fluencydoc@users.noreply.github.com> Date: Thu, 23 Dec 2021 00:14:20 -0400 Subject: [PATCH 2/4] Fixed error in docstring --- web/update_plots.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/web/update_plots.py b/web/update_plots.py index 4edc81053..49a31b140 100755 --- a/web/update_plots.py +++ b/web/update_plots.py @@ -14,8 +14,7 @@ def main(): """ This function scrapes the data from the web and wrangles it into a pandas DataFrame. - It then creates an interactive plotly line graph of covid cases - in New York State. + It then creates an interactive plotly line graph of covid cases. """ print('Updating covid deaths...') update_covid_deaths() From c6e24d6aa11f850be7c1c584ce3ae97d5d4c956a Mon Sep 17 00:00:00 2001 From: Fluency <93673101+fluencydoc@users.noreply.github.com> Date: Thu, 23 Dec 2021 00:28:35 -0400 Subject: [PATCH 3/4] Removed excess descriptions --- web/convert_table.py | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/web/convert_table.py b/web/convert_table.py index c58eb2193..a3302c301 100755 --- a/web/convert_table.py +++ b/web/convert_table.py @@ -5,15 +5,7 @@ def convert_table(lines): Convert a table from ASCII art to Unicode box drawing characters or vice versa. :param lines: A list of strings representing the lines of the table. - The first line is assumed to be the top border, and all other lines are assumed to be inside it (i.e., not on any side). All borders must use ``+`` - for corners, ``-`` for horizontal bars, and ``|`` for vertical bars; no spaces are allowed between symbols in a single border symbol (except if there - is one space between two vertical bar symbols when converting from ASCII art). If there is only one line in `lines`, then it will be used as both the - top and bottom borders with no interior rows or columns; this can also happen if `lines` contains an empty string at some point. This function does - not check that each row has exactly as many columns as there are horizontal bar symbols in either its own border or that of its neighbor above/below - it (if applicable), but such checking could easily be added by modifying how column widths are calculated below. - # :type lines: list(str) - # :returns - out: The converted table represented by a single string containing newline characters at appropriate places so that when printed + :type lines: list(str) """ def from_ascii(): """ @@ -22,17 +14,6 @@ def from_ascii(): :param lines: A list of strings representing the rows in the ASCII table. :returns: A string containing the equivalent reStructuredText grid table. - - The first line is assumed to be a header row and will be used as - such in the resulting grid table, with each column separated by ``|`` characters (ASCII 124). The second line is assumed to contain column widths and - will be used as such in the resulting grid table, with each width separated by ``-`` characters (ASCII 45). All subsequent lines are treated as data - rows which will have their contents centered within their columns, surrounded on either side by ``|`` characters (ASCII 124) and padded on either side - by blank spaces so that all data rows have an equal number of cells. Data values are converted from plain text into bold typeface using double - asterisks for emphasis before being inserted into cells; this allows you to use plain text formatting within your tables without them being overridden - when converting back into ASCII tables later on. - - For example, given these three lines... - +-----+--------+-------+------------------+-------------+----------- """ out = [] first, header, third, *body, last = lines From 47c11169895c84da5a1b85b066c51e63c042fb8d Mon Sep 17 00:00:00 2001 From: Fluency <93673101+fluencydoc@users.noreply.github.com> Date: Thu, 23 Dec 2021 00:30:56 -0400 Subject: [PATCH 4/4] Fixed docstring params --- web/update_plots.py | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/web/update_plots.py b/web/update_plots.py index 49a31b140..f6dd22b67 100755 --- a/web/update_plots.py +++ b/web/update_plots.py @@ -148,23 +148,8 @@ def update_file(filename, figure): """ Updates the file at `filename` with the plotly figure `figure`. - :param filename: The path to a JSON file containing a Plotly figure. - :type filename: - str, required. - The extension of the file must be .json or .js (for legacy reasons). - - Note that if you are using JupyterLab and want to open - your updated - HTML files in an external browser window then you should save your - notebook as an HTML file instead of as a Jupyter notebook. - For more - information see this guide on [using Jupyter with Google Colab](http://jupyter- - notebook.readthedocs.io/en/stable/examples/Notebook/Running%20Code.html#Running-code). - - If you are not using JupyterLab then it is recommended - that you use .html for all types of notebooks so that they can be opened in any web browser, including Chrome, Firefox and Edge on Windows and macOS - without any extra configuration needed (see below for more details). This is because some browsers do not support JavaScript which is used by default - by Plotly's exporting functions to generate + :param filename: The path to a JSON file. + :param figure: The Plotly figure. """ lines = read_file(filename) f_json = figure.to_json(pretty=True).replace('\n', '\n ')