How to Create a Julia Package from Scratch

By: Great Lakes Consulting

Re-posted from: https://blog.glcs.io/package-creation

This post was written by Steven Whitaker.

The Julia programming languageis a high-level languagethat is known, at least in part,for its excellent package managerand outstanding composability.(See another blog post that illustrates this composability.)

Julia makes it super easyfor anybody to create their own package.Julia’s package manager enables easy development and testing of packages.The ease of package developmentencourages developers to split reusable chunks of codeinto individual packages,further enhancing Julia’s composability.

In this post,we will learn what comprises a Julia package.We will also discuss toolsthat automate the creation of packages.Finally,we will talk about the basics of package developmentand walk through how to publish (register) a packagefor others to use.

This post assumes you are comfortable navigating the Julia REPL.If you need a refresher,check out our post on the Julia REPL.

Components of a Package

Packages are easy enough to use:just install them with add PkgName in the package promptand then run using PkgName in the julia prompt.But what actually goes into a package?

Packages must follow a specific directory structureand include certain informationto be recognized as a package by Julia.

Suppose we are creating a package called PracticePackage.jl.First, we create a directory called PracticePackage.This directory is the package root.Within the root directory we need a file called Project.tomland another directory called src.

The Project.toml requires the following information:

name = "PracticePackage"uuid = "11111111-2222-3333-aaaa-bbbbbbbbbbbb"authors = ["Your Name <youremail@email.com>"]version = "0.1.0"
  • uuid stands for universally unique identifier,and can be generated in Julia withusing UUIDs; uuid4().The purpose of a UUID is to allow different packages of the same name to coexist.
  • version should be set to whatever version is appropriate for your package,typically "0.1.0" or "1.0.0" for an initial release.The versioning of Julia packages follows SemVer.
  • The Project.toml will also include informationabout package dependencies,but more on that later.

The src directory requires one Julia filenamed PracticePackage.jlthat defines a module named PracticePackage:

module PracticePackage# Package code goes here.end

So, the directory structure of the packagelooks like the following:

PracticePackage Project.toml src     PracticePackage.jl

And that’s all there is to a package!(Well, at least minimally.)

Some Technicalities

Feel free to skip this section,but if you are curious about some technicalitiesfor what comprises a valid package,read on.

  • The Project.toml only needs the name and uuid fieldsfor Julia to recognize the package.Without the version field,Julia treats the version as v0.0.0.
    • However, the version and authors fields are neededto register the package.
  • The name of the package root directory doesn’t matter,meaning it doesn’t have to match the package name.However, the name field in Project.tomldoes have to match the name of the moduledefined in src/PracticePackage.jl,and the file name of src/PracticePackage.jl also has to match.
    • For example,we could change the name of the packageby setting name = "Oops" in Project.toml,renaming src/PracticePackage.jl to src/Oops.jl,and defining module Oops in that file.We would not have to rename the package root directoryfrom PracticePackage to Oops(though that would be a good idea to avoid confusion).

Automatically Generating Packages

The basic structure of a package is pretty simple,so there ought to be a way to automate it, right?(I mean, who wants to manually generate a UUID?)Good news: package creation can be automated!

Package generate Command

Julia comes with a generate package command built-in.First, change directoriesto where the package root directory should live,then run generate in the Julia package prompt:

pkg> generate PracticePackage

This command creates the package root directory PracticePackageand the Project.toml and src/PracticePackage.jl files.Some notes:

  • The Project.toml is pre-filled with the correct fields and values,including an automatically generated UUID.When I ran generate on my computer,it also pre-filled the authors fieldwith my name and email from my ~/.gitconfig file.
  • src/PracticePackage.jl is pre-filledwith a definition for the module PracticePackage.It also defines a function greet in the module,but typically you will replace that with your own code.

PkgTemplates.jl

The generate command works fine,but it’s barebones.For example,if you are planning on hosting your package on GitHub,you might want to include a GitHub Actionfor continuous integration (CI),so it would be niceto automate the creation of the appropriate .yml file.This is where PkgTemplates.jl comes in.

PkgTemplates.jl is a normal Julia package,so install it as usual and run using PkgTemplates.Then we can create our PracticePackage.jl:

t = Template(; dir = ".")t("PracticePackage")

Running this code creates the packagewith the following directory structure:

PracticePackage .git    .github    dependabot.yml    workflows        CI.yml        CompatHelper.yml        TagBot.yml .gitignore LICENSE Manifest.toml Project.toml README.md src    PracticePackage.jl test     runtests.jl

As you can see,PkgTemplates.jl automatically generates a lot of filesthat aid in following package development best practices,like adding CI and tests.

Note that many optionscan be supplied to Templateto customize what files are generated.See the PkgTemplates.jl docs for all the options.

Checklist of settings

Basic Package Development

Once your package is set up,the next step is to actually add code.Add the functions, types, constants, etc.that your package needsdirectly in the PracticePackage module in src/PracticePackage.jl,or add additional files in the src directoryand include them in the module.(See a previous blog post for more information about modules,though note that using modules directly works slightly differentlythan using packages.)

To add dependencies for your package to use,you will need to activate your project’s package environmentand then add packages.For example,if you want your package to use the DataFrames.jl package,start Julia and navigate to your package root directory.Then, activate the package environment and add the package:

(@v1.X) pkg> activate .(PracticePackage) pkg> add DataFrames

After this,you will be able to include using DataFramesin your package codeto enable the functionality provided by DataFrames.jl.

Adding packages after activating the package environmentedits the package’s Project.toml file.It adds a [deps] sectionthat lists the added packages and their UUIDs.In the example above,adding DataFrames.jladds the following lines to the Project.toml file:

[deps]DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"

(And (PracticePackage) pkg> rm DataFrames would remove the DataFrames = ... line,so it is best not to edit the [deps] section manually.)

Finally,to try out your package,activate your package environment (as above)and then load your package as usual:

julia> using PracticePackage # No need to `add PracticePackage` first.

Note that by default Julia will have to be restartedto reload any changes you make to your package code.If you want to avoid restarting Juliawhenever you make changes,check out Revise.jl.

Publishing/Registering a Package

Once your package is in working order,it is natural to want to publish the packagefor others to use.

A package can be publishedby registering it in a package registry,which basically is a map that tells the Julia package managerwhere to find a packageso it can be downloaded.

Treasure map

The General registry is the largest registryas well as the default registry used by Julia;most, if not all, of the most popular open-source packages(DataFrames.jl, Plots.jl, StaticArrays.jl, ModelingToolkit.jl, etc.)exist in General.Once a package is registered in General,it can be installed with pkg> add PracticePackage.

(Note that if registering a package is not desired for some reason,a package can be added via URL, e.g.,pkg> add https://github.com/username/PracticePackage.jl,assuming the package is in a public git repository.However,the package manager has limited abilityto manage packages added in this way;in particular,managing package versions must be done manually.)

The most common wayto register a package in Generalis to use Registrator.jl as a GitHub App.See the README for detailed instructions,but the process basically boils down to:

  1. Write/test package code.
  2. Update the version field in the Project.toml(e.g., to "0.1.0" or "1.0.0" for the first registered version).
  3. Add a comment with @JuliaRegistrator registerto the latest commit that should be includedin the registered version of the package.

Note that there are additional steps for preparing a package for publishingthat we did not discuss in this post(such as specifying compatible versionsof Julia and package dependencies).Refer to the General registry’s documentation and links therein for details.

Summary

In this post,we discussed creating Julia packages.We learned what comprises a package,how to automate package creation,and how to register a package in Julia’s General registry.

What package development tips do you have?Let us know in the comments below!

Additional Links

Cover image background provided by www.proflowers.com athttps://www.flickr.com/photos/127365614@N08/16011252136.

Treasure map image source: https://openclipart.org/detail/299283/x-marks-the-spot

]]>

The Chart Missing From ALL Spreadsheet Software

By: DSB

Re-posted from: https://davisbarreira.medium.com/the-chart-missing-from-all-spreadsheet-software-b7fede90d634?source=rss-8bd6ec95ab58------2

And how to implement it in Julia

This chart has been discussed in a recent video on the Minute Physics YouTube Channel. It is actually quite simple, consisting of a floating stacked bar chart. The idea of such plot is that we can use it to visualize range values, while assigning a color to represent such range.

Despite its simplicity, one might be surprised to find out that this chart is not readily available in many of the spreadsheet softwares. It is possible to draw it, yet, one needs to resort to some ad-hoc methods. This and more are discussed in the Minute Physics video.

The Challenge

We want to implement this visualization using the Julia programming language; but we want to be able to do this without resorting to a bunch of ad-hoc methods, and without having to write a humongous amount of code.

One possible solution would be to search for a charting library that covers such example. Yet, as in the case with spreadsheets, this search might be futile. Another possible approach would be to use a more generic visualization library that enables us to “directly” specify such graphic.

The Graphic Description

Before we can implement a solution, we must first get a clear picture of how this graphic is constructed. Consider the following dataset:

In order to reproduce the desired chart, we start by rearranging the dataset. We transform the locations (“Ontario”, “England” and “Kentucky”) into row values, and we pair together the temperature labels, for example, “winter mean low | annual mean low”.

If the dataset organized as such, we can more easily describe how to construct our graphic. Here is the construction logic. For each row, draw a “bar” with the horizontal position according to the location column, the lower end of the bar according to the low_temp column, the higher end of the bar according to the high_temp column, and the bar color is based on the label_temp column.

That’s it! With the dataset structured in such a way, the procedure to construct our graphic is fairly intuitive. We are now ready to implement our solution.

The Implementation

In order to draw our graphic, we need a visualization library that allows us to implement the construction logic we just described. This can be done using the package called Vizagrams.jl.

Vizagrams is a visualization grammar with a syntax very similar to VegaLite. If you have used packages such as Altair or ggplot, you probably know what I am talking about. The difference compared to these grammars is that Vizagrams implements what is called “graphic expression”.

A graphic expression is a constructive description of a graphic. In other words, we can use graphic expressions to encode our constructive logic without having to resort to ad-hoc methods, or writing a bunch of code.

This tutorial does not aim to thoroughly explain Vizagrams or graphic expressions. So let us cut short our explanation here, and move on to the solution.

In the code below, we start by importing Vizagrams. We assume that df holds the dataframe already properly transformed, and we use my-colors to specify the colors to be used (one could also just pick an existing colorscheme). We then specify the plot, which is stored into the plt variable.

The plot specification contains the data, the encoding variables (x, y, color, low_y) and the graphic, which is where we write the graphic expression. Our graphic expression simply iterates over each row in the dataset, and draws a trail having width 20 and with the respective color, lower point and higher point. The trail mark is simpler to use (in this example) and delivers the same result as using the bar mark.

using Vizagrams

df # Our transformed dataframe
my_colors = ["#F28E2B","#4E79A7","#FFBE7D","#A0CBE8"] # Our bar colors

plt = Plot(
data=df,
x = :location,
y = (field=:high_temp,scale_domain=(-10,40), scale_range=(0,200)),
low_y = (field=:low_temp,scale_domain=(-10,40), scale_range=(0,200)),
color = (field=:label_temp,scale_range=my_colors),
graphic =
∑() do row
S(:fill=>row.color)*Trail([[row.x,row.low_y],[row.x,row.y]],20)
end
)

draw(plt)

Conclusion

And there we have it! We implemented the desired chart. The example with all the code and data necessary can be found in Vizagrams’ gallery under the “Floating Stacked Bar” section.

To get a better understanding of what is going on, you should hop on a notebook and try the code yourself. Try changing the graphic expression using different graphical marks, or changing how the encoding variables are used.

A Fresh Approach to Lithium-Ion Battery Simulation: Insights from JuliaCon 2024

By: Jasmine Chokshi

Re-posted from: https://info.juliahub.com/blog/lithium-ion-battery-simulation

Lithium-ion battery models are highly non-linear systems of stiff, partial differential-algebraic equations (PDAEs). One of the key challenges of working with these models is to solve the system of equations over a range of inputs and parameters. Many commercial and open-source battery modeling tools are prone to sporadic failure stemming from issues in setting up, initializing, and solving these systems.