From 46e075c78be18aafa155764c36d666e37e97f0ad Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Wed, 13 Sep 2023 19:01:27 -0400 Subject: [PATCH 01/12] move 2018 files to subdirectory --- paper/{ => 2018}/codemeta.json | 0 paper/{ => 2018}/paper.bib | 0 paper/{ => 2018}/paper.md | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename paper/{ => 2018}/codemeta.json (100%) rename paper/{ => 2018}/paper.bib (100%) rename paper/{ => 2018}/paper.md (100%) diff --git a/paper/codemeta.json b/paper/2018/codemeta.json similarity index 100% rename from paper/codemeta.json rename to paper/2018/codemeta.json diff --git a/paper/paper.bib b/paper/2018/paper.bib similarity index 100% rename from paper/paper.bib rename to paper/2018/paper.bib diff --git a/paper/paper.md b/paper/2018/paper.md similarity index 100% rename from paper/paper.md rename to paper/2018/paper.md From c236f2aab76d8541868277b82f51b72bd1dd5087 Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Wed, 13 Sep 2023 19:03:10 -0400 Subject: [PATCH 02/12] initial files for 2023 manuscript --- paper/community.pdf | Bin 0 -> 27027 bytes paper/functions_06_010.pdf | Bin 0 -> 16022 bytes paper/paper.bib | 216 +++++++++++++++++++++++ paper/paper.md | 239 ++++++++++++++++++++++++++ paper/scripts/functions_per_module.py | 50 ++++++ paper/scripts/make_ts_plots.py | 68 ++++++++ paper/scripts/timeline2.py | 138 +++++++++++++++ paper/timeline2.pdf | Bin 0 -> 27025 bytes 8 files changed, 711 insertions(+) create mode 100644 paper/community.pdf create mode 100644 paper/functions_06_010.pdf create mode 100644 paper/paper.bib create mode 100644 paper/paper.md create mode 100644 paper/scripts/functions_per_module.py create mode 100644 paper/scripts/make_ts_plots.py create mode 100644 paper/scripts/timeline2.py create mode 100644 paper/timeline2.pdf diff --git a/paper/community.pdf b/paper/community.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e0fd0dc9d0af87ad2ee4ff0589d78778356706dc GIT binary patch literal 27027 zcma&OWmFu&x-}dF5;VBGGq?{PAV_d`XK)>y5J+%$*Wm8%Zi5AP9o*gJCHI{Bt^1vO z);f31kDBV*-OsN5RCV>No?VpkqGAjzjO_4~B}*j5P4Fxv%p|sk7Vvz0BuvU~b|4Za z5d%j9D_c_%CV2x>kOK+pD?pJ%KmZ%u za&;tOlC*xMApFl#r_F&K}yMNGUQUp2JI)RN|`}3E-A_Li}z1Z{?&x zHl~hdBrN}oCT4E++E)@LF{@VrL_tQj#-P8H9UQ?R18aEK)Y>$uNrpyyot@QkZV~YB z?k;?s;3`o#(^%fF_kOU7Az1}x(Nrny-7hQOL74I|Yo2OHBn;vyKh!d`Q25Z2gtp5v z9_#gdWoz?M+0+W2xtTtLIsD#O8{)``vk&iWgJP?dWVq+kqF)#NvV6EK|9l z&g|KalV|St1K^5^TvoAgJV4JY_@pCF(DOcOxw%2R`zZ#l(Q8}R>-o0z`2~8#6<~vQ z&|K?2l{h)%S6@D#KU?2^ce}?$EO-ZZ1MWXa@v7&%-Ch-V-n%0AYPf~Y3bwc1-Sw|} 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 0 else "top") + + ax.yaxis.set_visible(False) + ax.spines[["left", "top", "right", "bottom"]].set_visible(False) + ax.set_ylim(-7, 7) + ax.margins(y=0.1) + + +timeline_events = { + 'Releases': releases.str[1:], + 'Tutorials &\nUser Meetings': tutorials, + 'Milestones': other_events, +} + +fig, axes = plt.subplots(len(timeline_events), 1, sharex=True, figsize=(10, 4), layout="constrained") + +big = np.tile([-4, 4, -1, 1], 100) +little = np.tile([-2, 2], 100) +dotcolors = ['tab:blue', 'tab:orange', 'tab:green'] + +for (title, events), ax, levels, dotcolor in zip(timeline_events.items(), axes, [big, little, little], dotcolors): + make_timeline(events.index, events.values, levels[:len(events)], dotcolor, ax) + + ax.annotate(title, xy=(releases.index[0], 0), + xytext=(-40, 3), textcoords="offset points", + horizontalalignment="center", + verticalalignment="center", + rotation=90, fontweight='semibold') + +# once all the timeline points are in, we know how long the arrows are: +lim = axes[0].get_xlim() +x1, x2 = lim +buffer = (x2 - x1) / 50 +x1 += buffer +x2 -= buffer + +for ax in axes: + ax.xaxis.set_visible(False) + ax.arrow(x=x1, y=0, dx=x2-x1, dy=0, color='k', width=0.05, head_width=1, head_length=25) + +axes[0].set_xlim(*lim) + +for ax in axes[:-1]: + ax.xaxis.set_visible(False) + + +axes[-1].xaxis.set_visible(True) +axes[-1].spines[["bottom"]].set_visible(True) + +plt.savefig('timeline2.pdf') + + diff --git a/paper/timeline2.pdf b/paper/timeline2.pdf new file mode 100644 index 0000000000000000000000000000000000000000..05fcbf12a3a0b8ec0e85279281d37d3f1be2a850 GIT binary patch literal 27025 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 b0qGtTmn0UIfU8X4l!}=tm#V6(zZ(|-JHWQG literal 0 HcmV?d00001 From 3142b6f8bac23cbef94ffdb5b561430705bf38cd Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Wed, 13 Sep 2023 19:05:56 -0400 Subject: [PATCH 03/12] add joss build job --- .github/workflows/joss-pdf.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .github/workflows/joss-pdf.yml diff --git a/.github/workflows/joss-pdf.yml b/.github/workflows/joss-pdf.yml new file mode 100644 index 0000000000..fc07838426 --- /dev/null +++ b/.github/workflows/joss-pdf.yml @@ -0,0 +1,26 @@ +# temporary job to rebuild the PDF while coauthors review the manuscript. +# TODO: delete before merging this PR + +on: [push] + +jobs: + paper: + runs-on: ubuntu-latest + name: Paper Draft + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Build draft PDF + uses: openjournals/openjournals-draft-action@master + with: + journal: joss + # This should be the path to the paper within your repo. + paper-path: paper/paper.md + - name: Upload + uses: actions/upload-artifact@v1 + with: + name: paper + # This is the output path where Pandoc will write the compiled + # PDF. Note, this should be the same directory as the input + # paper.md + path: paper/paper.pdf From 386c021a8829ba514a635812552f964ff3d26c73 Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Thu, 14 Sep 2023 14:14:48 -0400 Subject: [PATCH 04/12] Apply suggestions from code review (@adamrjensen) Co-authored-by: Adam R. Jensen <39184289+AdamRJensen@users.noreply.github.com> --- paper/paper.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/paper/paper.md b/paper/paper.md index c0201b1c79..c8ad9333b6 100644 --- a/paper/paper.md +++ b/paper/paper.md @@ -47,7 +47,7 @@ systems. It provides peer-reviewed reference implementations of over 100 empirical and physics-based models from the scientific literature, including solar position algorithms, irradiance models, thermal models, and PV electrical models. In addition to these individual low-level -model implementations, pvlib python provides high-level constructs +model implementations, pvlib python provides high-level workflows that chain these models together like building blocks to form complete "weather-to-power" photovoltaic system models. It also provides functions to fetch and import a wide variety of weather datasets useful for PV modeling. @@ -74,7 +74,7 @@ capable models. Per the United States Department of Energy, Compared with other PV modeling tools, pvlib python stands out in several key aspects. One is its reusable toolbox design, providing the user a -level of flexibility beyond that of other tools. Rather than organizing +level of flexibility and customization beyond that of other tools. Rather than organizing the user interface around pre-built modeling workflows, pvlib python makes the individual "building blocks" of PV performance models accessible to the user. This allows the user to assemble their own model workflows, including @@ -136,7 +136,7 @@ Second, in addition to the new function-level model implementations, the package's high-level classes have also been expanded to support the complexity of emerging system designs, including heterogneous systems whose subsystems differ in mounting or electrical configuration and systems that require -custom orientation/steering models. +custom orientation/tracking models. Third, the creation of `pvlib.iotools`, a sub-package for fetching and importing datasets relevant to PV modeling. These functions provide a standardized @@ -164,7 +164,7 @@ project's use of version control software enables easy quantification of repository additions (to code, documentation, tests, etc) over time. The project's repository currently comprises contributions from over 100 people spanning industry, academia, and government research institutions. -\autoref{fig:community} shows the number of unique repository +\autoref{fig:community} (left) shows the number of unique repository contributors over time, demonstrating continued and generally accelerating attraction of new contributors. @@ -176,7 +176,7 @@ participate in online fora, and support the project in other ways. Along those lines, two easily tracked metrics are the number of people registered in the pvlib python online discussion forum and the number of GitHub "stars" (an indicator of an individual's interest, akin to a browser bookmark) -on the pvlib python code repository. \autoref{fig:community} +on the pvlib python code repository. \autoref{fig:community} (right) shows these counts over time. Although these numbers almost certainly substantially underestimate the true size of the pvlib community, their increase over time indicates continued and accelerating community growth. From d053d66a83d9ab3345416ef4baa01d7988c1efbb Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Thu, 14 Sep 2023 14:17:22 -0400 Subject: [PATCH 05/12] Apply suggestions from code review (@cwhanse) Co-authored-by: Cliff Hansen --- paper/paper.md | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/paper/paper.md b/paper/paper.md index c8ad9333b6..967de72af2 100644 --- a/paper/paper.md +++ b/paper/paper.md @@ -43,8 +43,8 @@ bibliography: paper.bib pvlib python is a community-developed, open-source software toolbox for simulating the performance of solar photovoltaic (PV) energy -systems. It provides peer-reviewed reference implementations of -over 100 empirical and physics-based models from the scientific literature, +systems. It provides reference implementations of +over 100 empirical and physics-based models from the peer-reviewed scientific literature, including solar position algorithms, irradiance models, thermal models, and PV electrical models. In addition to these individual low-level model implementations, pvlib python provides high-level workflows @@ -66,7 +66,7 @@ and community development since our 2018 publication [@pvlibjoss2018]. # Statement of need -PV performance models are used throughout the field of solar phovoltaics. +PV performance models are used throughout the field of photovoltaics. The rapid increase in scale, technological diversity, and sophistication of the global solar energy industry demands correspondingly more capable models. Per the United States Department of Energy, @@ -78,16 +78,14 @@ level of flexibility and customization beyond that of other tools. Rather than the user interface around pre-built modeling workflows, pvlib python makes the individual "building blocks" of PV performance models accessible to the user. This allows the user to assemble their own model workflows, including -the ability of incorporating their own custom modeling steps. This flexibility +the ability of incorporating custom modeling steps. This flexibility is essential for applications in both academia and industry. Another key aspect of pvlib python is that it is used via -a general-purpose programming language (Python). In addition to being more -generally flexible, powerful, and scalable than a traditional -graphical user interface, pvlib python's interface as a programming library -allows it to be combined with other Python packages. This enables -integration with database query, data manipulation, numerical optimization, -plotting, and reporting packages, to name a few. +a general-purpose programming language (Python), which +allows pvlib python functions to be combined with capabilities in other Python packages, +such as database query, data manipulation, numerical optimization, +plotting, and reporting packages. A final key aspect of pvlib python is its open peer review approach and foundation in published scientific research, allowing it to be developed by @@ -95,8 +93,8 @@ a decentralized and diverse community of PV researchers and practitioners without compromising its focus on transparent and reliable model implementations. -These core tenets, along with sustained contributions from a passionate and -committed community, have lead to its widespread adoption across the PV +These key aspects, along with sustained contributions from a passionate and +committed community, have led to pvlib python's widespread adoption across the PV field [@Stein2022]. In support of the claim that pvlib python provides meaningful value and addresses real needs, we offer these quantitative metrics: @@ -106,7 +104,7 @@ ranks 14th by citation count out of the 2000+ papers published by JOSS to date. due to being in the top 1% of the index's packages by download count. 3. The project's online documentation receives over 400,000 page views per year. -4. pvlib python was found to be the third most used python project +4. pvlib python was found to be the third most-used python project in the broader open-source sustainability software landscape, with the first two being netCDF4 utilities applicable across many scientific fields [@Augspurger2023]. @@ -154,9 +152,9 @@ project's documentation. # Community growth It is difficult to comprehensively describe the community around -open-source projects like pvlib python, but some aspects of it are more easily -quantifiable than others. Here we examine the community from a few convenient -perspectives, but we emphasize that this section is necessarily a limited view of +open-source projects like pvlib python, but some aspects can be +quantified. Here we examine the community from a few convenient +perspectives, emphasizing that these metrics provide a limited view of the community as a whole. First, we examine contributors to pvlib python's code repository. The @@ -172,13 +170,13 @@ attraction of new contributors. However, the project as a whole is the product of not only of those who contribute code but also those who submit bug reports, propose ideas for new features, -participate in online fora, and support the project in other ways. +participate in online forums, and support the project in other ways. Along those lines, two easily tracked metrics are the number of people registered in the pvlib python online discussion forum and the number of GitHub "stars" (an indicator of an individual's interest, akin to a browser bookmark) on the pvlib python code repository. \autoref{fig:community} (right) shows these counts over time. Although these numbers -almost certainly substantially underestimate the true size of the pvlib community, +almost certainly underestimate the true size of the pvlib community, their increase over time indicates continued and accelerating community growth. In addition to continuous interaction online, community members sometimes @@ -192,8 +190,7 @@ notable events in the project's history. ![pvlib python major event timeline: releases (top), community events (middle), and other project milestones (bottom).\label{fig:timeline}](timeline2.pdf) Finally, it is worth pointing out that pvlib python contributors and users -are part of a broader community around not just pvlib python itself -but also other members of the pvlib software "family": pvanalytics, a +are part of a broader community for the pvlib software "family", which includes pvanalytics, a package for PV data quality assurance and feature recognition algorithms [@pvpmc2022_pvanalytics_update], and twoaxistracking, a package for simulating self-shading in arrays of two-axis solar trackers [@Jensen2022]. From 2e59712d3554ce60d1a55c7f92c21d8876a85c77 Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Thu, 14 Sep 2023 14:25:58 -0400 Subject: [PATCH 06/12] typo and core developers --- paper/paper.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/paper/paper.md b/paper/paper.md index 967de72af2..a46da195ee 100644 --- a/paper/paper.md +++ b/paper/paper.md @@ -60,8 +60,9 @@ distributed via the Python Package Index (PyPI) and the conda-forge repository. pvlib python's source code is made freely available under the permissive BSD-3 license. -Here we present an update on pvlib python, describing capability -and community development since our 2018 publication [@pvlibjoss2018]. +Here we (the project's core developers) present an update on pvlib python, +describing capability and community development since our 2018 publication +[@pvlibjoss2018]. # Statement of need @@ -132,7 +133,7 @@ last five years. Second, in addition to the new function-level model implementations, the package's high-level classes have also been expanded to support -the complexity of emerging system designs, including heterogneous systems whose +the complexity of emerging system designs, including heterogeneous systems whose subsystems differ in mounting or electrical configuration and systems that require custom orientation/tracking models. From 6f9d7a305381551484603f960c8527f117d2ab4b Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Thu, 14 Sep 2023 16:04:39 -0400 Subject: [PATCH 07/12] Apply suggestions from code review (@wholmgren) Co-authored-by: Will Holmgren --- paper/paper.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/paper/paper.md b/paper/paper.md index a46da195ee..11c05fe614 100644 --- a/paper/paper.md +++ b/paper/paper.md @@ -179,6 +179,9 @@ on the pvlib python code repository. \autoref{fig:community} (right) shows these counts over time. Although these numbers almost certainly underestimate the true size of the pvlib community, their increase over time indicates continued and accelerating community growth. +Since the 2018 JOSS publication, pvlib python has doubled the number of +maintainers to bring in new perspectives and to better support the growing +community. In addition to continuous interaction online, community members sometimes meet in person at user's group and tutorial sessions run by pvlib python From d92b5d4f2a9f36bf16a4a04c4a9a620b9a19e051 Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Thu, 14 Sep 2023 16:06:03 -0400 Subject: [PATCH 08/12] 2015 -> 2013 --- paper/paper.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/paper/paper.md b/paper/paper.md index a46da195ee..0dd2e31394 100644 --- a/paper/paper.md +++ b/paper/paper.md @@ -52,7 +52,7 @@ that chain these models together like building blocks to form complete "weather-to-power" photovoltaic system models. It also provides functions to fetch and import a wide variety of weather datasets useful for PV modeling. -pvlib python has been developed since 2015 and follows modern best +pvlib python has been developed since 2013 and follows modern best practices for open-source python software, with comprehensive automated testing, standards-based packaging, and semantic versioning. Its source code is developed openly on GitHub and releases are From c69b2ca56d49e9dbf770e725e085521391b3d888 Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Thu, 14 Sep 2023 16:06:28 -0400 Subject: [PATCH 09/12] remove scripts --- paper/scripts/functions_per_module.py | 50 ---------- paper/scripts/make_ts_plots.py | 68 ------------- paper/scripts/timeline2.py | 138 -------------------------- 3 files changed, 256 deletions(-) delete mode 100644 paper/scripts/functions_per_module.py delete mode 100644 paper/scripts/make_ts_plots.py delete mode 100644 paper/scripts/timeline2.py diff --git a/paper/scripts/functions_per_module.py b/paper/scripts/functions_per_module.py deleted file mode 100644 index b9ab5ccedb..0000000000 --- a/paper/scripts/functions_per_module.py +++ /dev/null @@ -1,50 +0,0 @@ - -import pandas as pd -import numpy as np -import pvlib - -# run in an environment with the target pvlib version installed - -def recurse(module): - objects = [] - for name in dir(module): - if name.startswith("_"): - continue - obj = getattr(module, name) - if (not hasattr(obj, '__module__') or not obj.__module__.startswith(module.__name__)) and \ - (not hasattr(obj, '__package__') or not obj.__package__.startswith(module.__name__)): - continue - if type(obj).__name__ == 'function': - objects.append(obj.__module__ + "." + obj.__name__) - if type(obj).__name__ == 'module': - objects.extend(recurse(obj)) - return np.unique(objects) - - -names = recurse(pvlib) -df = pd.DataFrame({'name': names}) -df['module'] = df['name'].str.split(".").str[1] -counts = df.groupby('module').count() - -counts['name'].to_dict() - -# %% - -import matplotlib.pyplot as plt - -counts_060 = {'atmosphere': 10, 'clearsky': 6, 'irradiance': 25, 'modelchain': 2, 'pvsystem': 22, 'singlediode': 6, 'solarposition': 16, 'spa': 51, 'tmy': 2, 'tools': 7, 'tracking': 1} -counts_0101 = {'atmosphere': 9, 'bifacial': 9, 'clearsky': 6, 'iam': 10, 'inverter': 6, 'iotools': 31, 'irradiance': 29, 'ivtools': 8, 'location': 1, 'modelchain': 2, 'pvsystem': 16, 'scaling': 2, 'shading': 4, 'singlediode': 5, 'snow': 4, 'soiling': 2, 'solarposition': 18, 'spa': 51, 'spectrum': 7, 'temperature': 11, 'tools': 9, 'tracking': 4} - -df = pd.DataFrame({ - 'v0.6.0 (2018-09-17)': pd.Series(counts_060), - 'v0.10.1 (2023-07-03)': pd.Series(counts_0101), -}) - -df = df.drop(['spa', 'tmy', 'tools']) - -fig, ax = plt.subplots(figsize=(8, 4)) -df.plot.bar(ax=ax) -ax.set_ylabel('Number of public functions') -ax.set_xlabel('pvlib module') -fig.tight_layout() -fig.savefig('functions_06_010.pdf') diff --git a/paper/scripts/make_ts_plots.py b/paper/scripts/make_ts_plots.py deleted file mode 100644 index ec469bd6f4..0000000000 --- a/paper/scripts/make_ts_plots.py +++ /dev/null @@ -1,68 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Wed May 31 19:38:26 2023 - -@author: ksande -""" - -import pandas as pd -import matplotlib.pyplot as plt - -import sys -sys.path.insert(0, r'C:\Users\ksande\projects\pv-foss-engagement\sphinx\source\project') - -from utils import get_github_contributor_timeseries, get_github_stars - -# %% - -cumulative_contributors, _ = get_github_contributor_timeseries('pvlib/pvlib-python') - -# the above API only reports up to 100 contributors, I think. So add a few more, with (very) rough dates: -fudge = pd.Series([101, 102, 103, 104], index=pd.to_datetime(['2023-07-01', '2023-08-01', '2023-09-01', '2023-09-13'])) - -cumulative_contributors = cumulative_contributors.append(fudge).resample('d').ffill() - -# %% - -fn = r'C:\Users\ksande\Downloads\pvlib_google_group_2023-09-13.csv' -df = pd.read_csv(fn, index_col=0, parse_dates=True) - -df.index = pd.to_datetime(df['Join Date']) -df['n'] = 1 -gg_members = df['n'].resample('d').sum().cumsum().ffill() - - -# %% - -gh = get_github_stars('pvlib/pvlib-python') - -gh = gh.set_index('star_date') -gh['n'] = 1 -gh_stars = gh['n'].resample('d').sum().cumsum().ffill() - - -# %% - -fig, axes = plt.subplots(1, 2, figsize=(10, 3), sharex=True) - -gg_members.plot(ax=axes[1], label='Forum registrations') -gh_stars.plot(ax=axes[1], label='GitHub stars') - -cumulative_contributors.plot(ax=axes[0]) -axes[0].set_ylabel('Repository contributors') - -axes[1].legend() -axes[1].set_ylabel('Count') - -axes[0].set_ylim(bottom=0) -axes[1].set_ylim(bottom=0) - -axes[1].set_xlabel(None) - -axes[0].tick_params(axis='x', which='minor', bottom=False) -axes[1].tick_params(axis='x', which='minor', bottom=False) - -fig.tight_layout() -fig.savefig('community.pdf') - - diff --git a/paper/scripts/timeline2.py b/paper/scripts/timeline2.py deleted file mode 100644 index 263f2cbebe..0000000000 --- a/paper/scripts/timeline2.py +++ /dev/null @@ -1,138 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Wed May 31 21:18:07 2023 - -@author: ksande -""" - -# based on https://matplotlib.org/stable/gallery/lines_bars_and_markers/timeline.html - -import matplotlib.pyplot as plt -import numpy as np -import pandas as pd - -releases = pd.Series({ - '2023-07-03': 'v0.10.1', - '2023-06-30': 'v0.10.0', - '2023-03-18': 'v0.9.5', - '2022-12-20': 'v0.9.4', - '2022-09-15': 'v0.9.3', - '2022-08-19': 'v0.9.2', - '2022-03-29': 'v0.9.1', - '2021-09-01': 'v0.9.0', - '2021-01-04': 'v0.8.1', - '2020-09-08': 'v0.8.0', - '2020-04-22': 'v0.7.2', - '2020-01-17': 'v0.7.1', - '2019-12-18': 'v0.7.0', - '2019-05-15': 'v0.6.2', - '2019-01-31': 'v0.6.1', - '2018-09-17': 'v0.6.0', - '2018-05-13': 'v0.5.2', - '2017-10-17': 'v0.5.1', - '2017-08-11': 'v0.5.0', - '2017-06-05': 'v0.4.5', - '2017-02-18': 'v0.4.4', - '2016-12-28': 'v0.4.3', - '2016-12-07': 'v0.4.2', - '2016-10-05': 'v0.4.1', - '2016-07-28': 'v0.4.0', - '2016-06-15': 'v0.3.3', - '2016-05-03': 'v0.3.2', - '2016-04-19': 'v0.3.1', - '2016-03-21': 'v0.3.0', - '2015-11-13': 'v0.2.2', - '2015-07-16': 'v0.2.1', - '2015-07-06': 'v0.2.0', - '2015-04-20': 'v0.1.0', -}) -releases.index = pd.to_datetime(releases.index) -releases = releases.sort_index() - -tutorials = pd.Series({ - '2016-05-10': 'PVPMC\nWorkshop', - '2017-05-10': 'PVPMC\nWorkshop', - '2021-06-20': 'IEEE PVSC', - '2021-10-29': 'PyData Global', - '2022-08-24': 'PVPMC\nWorkshop', - '2023-05-10': 'PVPMC\nWorkshop', - '2023-06-11': 'IEEE PVSC', -}) - -tutorials.index = pd.to_datetime(tutorials.index) -tutorials = tutorials.sort_index() - -other_events = pd.Series({ - #'2013-08-30': 'First GitHub commit', - '2018-09-07': 'JOSS\npaper', - '2018-12-17': 'Reached 100\nforum members', - '2019-04-17': 'NumFocus\nAffiliation', - '2020-03-15': 'Reached 50\ncode contributors', - '2021-06-01': 'GSoC 2021', # approximate - '2021-10-13': 'Reached 500\nforum members', - '2023-06-28': 'Reached 100\ncode contributors' -}) -other_events.index = pd.to_datetime(other_events.index) -other_events = other_events.sort_index() - - -def make_timeline(dates, labels, levels, dotcolor, ax): - - ax.vlines(dates, 0, levels, color="k", ls='-', alpha=0.3) - ax.plot(dates, np.zeros_like(dates), "o", lw=3, color='k', markerfacecolor=dotcolor) - for date, label, level in zip(dates, labels, levels): - ax.annotate(label, xy=(date, level), - xytext=(-3, np.sign(level)*3), textcoords="offset points", - horizontalalignment="center", - verticalalignment="bottom" if level > 0 else "top") - - ax.yaxis.set_visible(False) - ax.spines[["left", "top", "right", "bottom"]].set_visible(False) - ax.set_ylim(-7, 7) - ax.margins(y=0.1) - - -timeline_events = { - 'Releases': releases.str[1:], - 'Tutorials &\nUser Meetings': tutorials, - 'Milestones': other_events, -} - -fig, axes = plt.subplots(len(timeline_events), 1, sharex=True, figsize=(10, 4), layout="constrained") - -big = np.tile([-4, 4, -1, 1], 100) -little = np.tile([-2, 2], 100) -dotcolors = ['tab:blue', 'tab:orange', 'tab:green'] - -for (title, events), ax, levels, dotcolor in zip(timeline_events.items(), axes, [big, little, little], dotcolors): - make_timeline(events.index, events.values, levels[:len(events)], dotcolor, ax) - - ax.annotate(title, xy=(releases.index[0], 0), - xytext=(-40, 3), textcoords="offset points", - horizontalalignment="center", - verticalalignment="center", - rotation=90, fontweight='semibold') - -# once all the timeline points are in, we know how long the arrows are: -lim = axes[0].get_xlim() -x1, x2 = lim -buffer = (x2 - x1) / 50 -x1 += buffer -x2 -= buffer - -for ax in axes: - ax.xaxis.set_visible(False) - ax.arrow(x=x1, y=0, dx=x2-x1, dy=0, color='k', width=0.05, head_width=1, head_length=25) - -axes[0].set_xlim(*lim) - -for ax in axes[:-1]: - ax.xaxis.set_visible(False) - - -axes[-1].xaxis.set_visible(True) -axes[-1].spines[["bottom"]].set_visible(True) - -plt.savefig('timeline2.pdf') - - From 659aa7117ae1ca5b195abe3e50559de2e7bee05c Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Fri, 15 Sep 2023 12:44:15 -0400 Subject: [PATCH 10/12] Apply suggestions from code review (@adriesse) Co-authored-by: Anton Driesse --- paper/paper.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/paper/paper.md b/paper/paper.md index 9cfd78be2d..3f49034fa2 100644 --- a/paper/paper.md +++ b/paper/paper.md @@ -43,10 +43,10 @@ bibliography: paper.bib pvlib python is a community-developed, open-source software toolbox for simulating the performance of solar photovoltaic (PV) energy -systems. It provides reference implementations of +components and systems. It provides reference implementations of over 100 empirical and physics-based models from the peer-reviewed scientific literature, including solar position algorithms, irradiance models, thermal models, -and PV electrical models. In addition to these individual low-level +and PV electrical models. In addition to individual low-level model implementations, pvlib python provides high-level workflows that chain these models together like building blocks to form complete "weather-to-power" photovoltaic system models. It also provides functions to @@ -74,7 +74,7 @@ capable models. Per the United States Department of Energy, "the importance of accurate modeling is hard to overstate" [@seto2022]. Compared with other PV modeling tools, pvlib python stands out in several -key aspects. One is its reusable toolbox design, providing the user a +key aspects. One is its toolbox design, providing the user a level of flexibility and customization beyond that of other tools. Rather than organizing the user interface around pre-built modeling workflows, pvlib python makes the individual "building blocks" of PV performance models accessible to @@ -152,7 +152,7 @@ project's documentation. # Community growth -It is difficult to comprehensively describe the community around +It is difficult to fully describe the community around open-source projects like pvlib python, but some aspects can be quantified. Here we examine the community from a few convenient perspectives, emphasizing that these metrics provide a limited view of From 0a90d04aabf107abd7adbfb1c1e07bd2b698cb73 Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Mon, 18 Sep 2023 09:51:25 -0400 Subject: [PATCH 11/12] order authors by commit count since last paper https://github.com/pvlib/pvlib-python/graphs/contributors?from=2018-09-07&to=2023-09-18&type=c --- paper/paper.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/paper/paper.md b/paper/paper.md index 3f49034fa2..2098040e01 100644 --- a/paper/paper.md +++ b/paper/paper.md @@ -9,12 +9,12 @@ authors: - name: Kevin S. Anderson orcid: 0000-0002-1166-7957 affiliation: 1 - - name: William F. Holmgren - orcid: 0000-0001-6218-9767 - affiliation: 2 - name: Clifford W. Hansen orcid: 0000-0002-8620-5378 affiliation: 1 + - name: William F. Holmgren + orcid: 0000-0001-6218-9767 + affiliation: 2 - name: Mark A. Mikofski orcid: 0000-0001-8001-8582 affiliation: 2 From 4818e9624461c65a161048b170b32cf190d54fe7 Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Mon, 18 Sep 2023 10:28:31 -0400 Subject: [PATCH 12/12] s/foundation in/foundation on/ --- paper/paper.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/paper/paper.md b/paper/paper.md index 2098040e01..3936e3c1ce 100644 --- a/paper/paper.md +++ b/paper/paper.md @@ -89,7 +89,7 @@ such as database query, data manipulation, numerical optimization, plotting, and reporting packages. A final key aspect of pvlib python is its open peer review approach and -foundation in published scientific research, allowing it to be developed by +foundation on published scientific research, allowing it to be developed by a decentralized and diverse community of PV researchers and practitioners without compromising its focus on transparent and reliable model implementations.